Add requests and limits to kubectl run
This commit is contained in:
@@ -92,6 +92,8 @@ func NewCmdRun(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *c
|
||||
cmd.Flags().Bool("attach", false, "If true, wait for the Pod to start running, and then attach to the Pod as if 'kubectl attach ...' were called. Default false, unless '-i/--interactive' is set, in which case the default is true.")
|
||||
cmd.Flags().String("restart", "Always", "The restart policy for this Pod. Legal values [Always, OnFailure, Never]. If set to 'Always' a replication controller is created for this pod, if set to OnFailure or Never, only the Pod is created and --replicas must be 1. Default 'Always'")
|
||||
cmd.Flags().Bool("command", false, "If true and extra arguments are present, use them as the 'command' field in the container, rather than the 'args' field which is the default.")
|
||||
cmd.Flags().String("requests", "", "The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'")
|
||||
cmd.Flags().String("limits", "", "The resource requirement limits for this container. For example, 'cpu=200m,memory=512Mi'")
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util"
|
||||
)
|
||||
@@ -42,9 +43,51 @@ func (BasicReplicationController) ParamNames() []GeneratorParam {
|
||||
{"command", false},
|
||||
{"args", false},
|
||||
{"env", false},
|
||||
{"requests", false},
|
||||
{"limits", false},
|
||||
}
|
||||
}
|
||||
|
||||
// populateResourceList takes strings of form <resourceName1>=<value1>,<resourceName1>=<value2>
|
||||
func populateResourceList(spec string) (api.ResourceList, error) {
|
||||
// empty input gets a nil response to preserve generator test expected behaviors
|
||||
if spec == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
result := api.ResourceList{}
|
||||
resourceStatements := strings.Split(spec, ",")
|
||||
for _, resourceStatement := range resourceStatements {
|
||||
parts := strings.Split(resourceStatement, "=")
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("Invalid argument syntax %v, expected <resource>=<value>", resourceStatement)
|
||||
}
|
||||
resourceName := api.ResourceName(parts[0])
|
||||
resourceQuantity, err := resource.ParseQuantity(parts[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[resourceName] = *resourceQuantity
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// HandleResourceRequirements parses the limits and requests parameters if specified
|
||||
func HandleResourceRequirements(params map[string]string) (api.ResourceRequirements, error) {
|
||||
result := api.ResourceRequirements{}
|
||||
limits, err := populateResourceList(params["limits"])
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result.Limits = limits
|
||||
requests, err := populateResourceList(params["requests"])
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result.Requests = requests
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func makePodSpec(params map[string]string, name string) (*api.PodSpec, error) {
|
||||
stdin, err := GetBool(params, "stdin", false)
|
||||
if err != nil {
|
||||
@@ -56,13 +99,19 @@ func makePodSpec(params map[string]string, name string) (*api.PodSpec, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resourceRequirements, err := HandleResourceRequirements(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
spec := api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: name,
|
||||
Image: params["image"],
|
||||
Stdin: stdin,
|
||||
TTY: tty,
|
||||
Name: name,
|
||||
Image: params["image"],
|
||||
Stdin: stdin,
|
||||
TTY: tty,
|
||||
Resources: resourceRequirements,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -223,6 +272,8 @@ func (BasicPod) ParamNames() []GeneratorParam {
|
||||
{"command", false},
|
||||
{"args", false},
|
||||
{"env", false},
|
||||
{"requests", false},
|
||||
{"limits", false},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,6 +339,11 @@ func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resourceRequirements, err := HandleResourceRequirements(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
restartPolicy := api.RestartPolicy(params["restart"])
|
||||
if len(restartPolicy) == 0 {
|
||||
restartPolicy = api.RestartPolicyAlways
|
||||
@@ -305,6 +361,7 @@ func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object,
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
Stdin: stdin,
|
||||
TTY: tty,
|
||||
Resources: resourceRequirements,
|
||||
},
|
||||
},
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
)
|
||||
|
||||
func TestGenerate(t *testing.T) {
|
||||
@@ -286,6 +287,92 @@ func TestGenerate(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
params: map[string]interface{}{
|
||||
"name": "foo",
|
||||
"image": "someimage",
|
||||
"replicas": "1",
|
||||
"hostport": "80",
|
||||
},
|
||||
expected: nil,
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
params: map[string]interface{}{
|
||||
"name": "foo",
|
||||
"image": "someimage",
|
||||
"replicas": "1",
|
||||
"labels": "foo=bar,baz=blah",
|
||||
"requests": "cpu100m,memory=100Mi",
|
||||
},
|
||||
expected: nil,
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
params: map[string]interface{}{
|
||||
"name": "foo",
|
||||
"image": "someimage",
|
||||
"replicas": "1",
|
||||
"labels": "foo=bar,baz=blah",
|
||||
"requests": "cpu=100m&memory=100Mi",
|
||||
},
|
||||
expected: nil,
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
params: map[string]interface{}{
|
||||
"name": "foo",
|
||||
"image": "someimage",
|
||||
"replicas": "1",
|
||||
"labels": "foo=bar,baz=blah",
|
||||
"requests": "cpu=",
|
||||
},
|
||||
expected: nil,
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
params: map[string]interface{}{
|
||||
"name": "foo",
|
||||
"image": "someimage",
|
||||
"replicas": "1",
|
||||
"labels": "foo=bar,baz=blah",
|
||||
"requests": "cpu=100m,memory=100Mi",
|
||||
"limits": "cpu=400m,memory=200Mi",
|
||||
},
|
||||
expected: &api.ReplicationController{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
Labels: map[string]string{"foo": "bar", "baz": "blah"},
|
||||
},
|
||||
Spec: api.ReplicationControllerSpec{
|
||||
Replicas: 1,
|
||||
Selector: map[string]string{"foo": "bar", "baz": "blah"},
|
||||
Template: &api.PodTemplateSpec{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Labels: map[string]string{"foo": "bar", "baz": "blah"},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "foo",
|
||||
Image: "someimage",
|
||||
Resources: api.ResourceRequirements{
|
||||
Requests: api.ResourceList{
|
||||
api.ResourceCPU: resource.MustParse("100m"),
|
||||
api.ResourceMemory: resource.MustParse("100Mi"),
|
||||
},
|
||||
Limits: api.ResourceList{
|
||||
api.ResourceCPU: resource.MustParse("400m"),
|
||||
api.ResourceMemory: resource.MustParse("200Mi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
generator := BasicReplicationController{}
|
||||
for _, test := range tests {
|
||||
|
||||
Reference in New Issue
Block a user