Merge pull request #42362 from soltysh/deployment_generators

Automatic merge from submit-queue (batch tested with PRs 38805, 42362, 42862)

Fix deployment generator after introducing deployments in apps/v1beta1

This PR does two things:

1. Switches all generator to produce versioned objects, to bypass the problem of having an object in multiple versions, which then results in not having stable generator (iow. producing exactly the same object).
2. Introduces new generator for `apps/v1beta1` deployments.

@kargakis @janetkuo ptal

@kubernetes/sig-apps-pr-reviews @kubernetes/sig-cli-pr-reviews ptal

This is a followup to https://github.com/kubernetes/kubernetes/pull/39683, so I'm adding 1.6 milestone.

```release-note
Introduce new generator for apps/v1beta1 deployments
```
This commit is contained in:
Kubernetes Submit Queue 2017-03-10 14:01:21 -08:00 committed by GitHub
commit d2d3884f83
13 changed files with 890 additions and 320 deletions

View File

@ -1046,11 +1046,23 @@ run_kubectl_run_tests() {
# Pre-Condition: no Deployment exists # Pre-Condition: no Deployment exists
kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" '' kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" ''
# Command # Command
kubectl run nginx "--image=$IMAGE_NGINX" --generator=deployment/v1beta1 "${kube_flags[@]}" kubectl run nginx-extensions "--image=$IMAGE_NGINX" "${kube_flags[@]}"
# Post-Condition: Deployment "nginx" is created # Post-Condition: Deployment "nginx" is created
kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" 'nginx:' kube::test::get_object_assert deployment.extensions "{{range.items}}{{$id_field}}:{{end}}" 'nginx-extensions:'
# and old generator was used, iow. old defaults are applied
output_message=$(kubectl get deployment.extensions/nginx-extensions -o jsonpath='{.spec.revisionHistoryLimit}')
kube::test::if_has_not_string "${output_message}" '2'
# Clean up # Clean up
kubectl delete deployment nginx "${kube_flags[@]}" kubectl delete deployment nginx-extensions "${kube_flags[@]}"
# Command
kubectl run nginx-apps "--image=$IMAGE_NGINX" --generator=deployment/apps.v1beta1 "${kube_flags[@]}"
# Post-Condition: Deployment "nginx" is created
kube::test::get_object_assert deployment.apps "{{range.items}}{{$id_field}}:{{end}}" 'nginx-apps:'
# and new generator was used, iow. new defaults are applied
output_message=$(kubectl get deployment/nginx-apps -o jsonpath='{.spec.revisionHistoryLimit}')
kube::test::if_has_string "${output_message}" '2'
# Clean up
kubectl delete deployment nginx-apps "${kube_flags[@]}"
} }
run_kubectl_get_tests() { run_kubectl_get_tests() {
@ -2283,17 +2295,35 @@ run_rc_tests() {
} }
run_deployment_tests() { run_deployment_tests() {
# Test kubectl create deployment # Test kubectl create deployment (using default - old generator)
kubectl create deployment test-nginx --image=gcr.io/google-containers/nginx:test-cmd kubectl create deployment test-nginx-extensions --image=gcr.io/google-containers/nginx:test-cmd
# Post-Condition: Deployment has 2 replicas defined in its spec. # Post-Condition: Deployment "nginx" is created.
kube::test::get_object_assert 'deploy test-nginx' "{{$container_name_field}}" 'nginx' kube::test::get_object_assert 'deploy test-nginx-extensions' "{{$container_name_field}}" 'nginx'
# and old generator was used, iow. old defaults are applied
output_message=$(kubectl get deployment.extensions/test-nginx-extensions -o jsonpath='{.spec.revisionHistoryLimit}')
kube::test::if_has_not_string "${output_message}" '2'
# Ensure we can interact with deployments through extensions and apps endpoints # Ensure we can interact with deployments through extensions and apps endpoints
output_message=$(kubectl get deployment.extensions -o=jsonpath='{.items[0].apiVersion}' 2>&1 "${kube_flags[@]}") output_message=$(kubectl get deployment.extensions -o=jsonpath='{.items[0].apiVersion}' 2>&1 "${kube_flags[@]}")
kube::test::if_has_string "${output_message}" 'extensions/v1beta1' kube::test::if_has_string "${output_message}" 'extensions/v1beta1'
output_message=$(kubectl get deployment.apps -o=jsonpath='{.items[0].apiVersion}' 2>&1 "${kube_flags[@]}") output_message=$(kubectl get deployment.apps -o=jsonpath='{.items[0].apiVersion}' 2>&1 "${kube_flags[@]}")
kube::test::if_has_string "${output_message}" 'apps/v1beta1' kube::test::if_has_string "${output_message}" 'apps/v1beta1'
# Clean up # Clean up
kubectl delete deployment test-nginx "${kube_flags[@]}" kubectl delete deployment test-nginx-extensions "${kube_flags[@]}"
# Test kubectl create deployment
kubectl create deployment test-nginx-apps --image=gcr.io/google-containers/nginx:test-cmd --generator=deployment-basic/apps.v1beta1
# Post-Condition: Deployment "nginx" is created.
kube::test::get_object_assert 'deploy test-nginx-apps' "{{$container_name_field}}" 'nginx'
# and new generator was used, iow. new defaults are applied
output_message=$(kubectl get deployment/test-nginx-apps -o jsonpath='{.spec.revisionHistoryLimit}')
kube::test::if_has_string "${output_message}" '2'
# Ensure we can interact with deployments through extensions and apps endpoints
output_message=$(kubectl get deployment.extensions -o=jsonpath='{.items[0].apiVersion}' 2>&1 "${kube_flags[@]}")
kube::test::if_has_string "${output_message}" 'extensions/v1beta1'
output_message=$(kubectl get deployment.apps -o=jsonpath='{.items[0].apiVersion}' 2>&1 "${kube_flags[@]}")
kube::test::if_has_string "${output_message}" 'apps/v1beta1'
# Clean up
kubectl delete deployment test-nginx-apps "${kube_flags[@]}"
### Test cascading deletion ### Test cascading deletion
## Test that rs is deleted when deployment is deleted. ## Test that rs is deleted when deployment is deleted.

View File

@ -53,8 +53,11 @@ go_library(
"//pkg/api/util:go_default_library", "//pkg/api/util:go_default_library",
"//pkg/api/v1:go_default_library", "//pkg/api/v1:go_default_library",
"//pkg/apis/apps:go_default_library", "//pkg/apis/apps:go_default_library",
"//pkg/apis/apps/v1beta1:go_default_library",
"//pkg/apis/autoscaling:go_default_library", "//pkg/apis/autoscaling:go_default_library",
"//pkg/apis/batch:go_default_library", "//pkg/apis/batch:go_default_library",
"//pkg/apis/batch/v1:go_default_library",
"//pkg/apis/batch/v2alpha1:go_default_library",
"//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions:go_default_library",
"//pkg/apis/extensions/v1beta1:go_default_library", "//pkg/apis/extensions/v1beta1:go_default_library",
"//pkg/apis/policy:go_default_library", "//pkg/apis/policy:go_default_library",
@ -135,8 +138,12 @@ go_test(
"//pkg/api/testapi:go_default_library", "//pkg/api/testapi:go_default_library",
"//pkg/api/testing:go_default_library", "//pkg/api/testing:go_default_library",
"//pkg/api/v1:go_default_library", "//pkg/api/v1:go_default_library",
"//pkg/apis/apps/v1beta1:go_default_library",
"//pkg/apis/batch:go_default_library", "//pkg/apis/batch:go_default_library",
"//pkg/apis/batch/v1:go_default_library",
"//pkg/apis/batch/v2alpha1:go_default_library",
"//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions:go_default_library",
"//pkg/apis/extensions/v1beta1:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/batch/internalversion:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/batch/internalversion:go_default_library",

View File

@ -70,7 +70,9 @@ go_library(
"//pkg/api/annotations:go_default_library", "//pkg/api/annotations:go_default_library",
"//pkg/api/v1:go_default_library", "//pkg/api/v1:go_default_library",
"//pkg/api/validation:go_default_library", "//pkg/api/validation:go_default_library",
"//pkg/apis/apps/v1beta1:go_default_library",
"//pkg/apis/batch/v1:go_default_library", "//pkg/apis/batch/v1:go_default_library",
"//pkg/apis/batch/v2alpha1:go_default_library",
"//pkg/apis/certificates:go_default_library", "//pkg/apis/certificates:go_default_library",
"//pkg/apis/extensions/v1beta1:go_default_library", "//pkg/apis/extensions/v1beta1:go_default_library",
"//pkg/apis/policy:go_default_library", "//pkg/apis/policy:go_default_library",

View File

@ -94,7 +94,7 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
cmd.AddCommand(NewCmdCreateConfigMap(f, out)) cmd.AddCommand(NewCmdCreateConfigMap(f, out))
cmd.AddCommand(NewCmdCreateServiceAccount(f, out)) cmd.AddCommand(NewCmdCreateServiceAccount(f, out))
cmd.AddCommand(NewCmdCreateService(f, out, errOut)) cmd.AddCommand(NewCmdCreateService(f, out, errOut))
cmd.AddCommand(NewCmdCreateDeployment(f, out)) cmd.AddCommand(NewCmdCreateDeployment(f, out, errOut))
cmd.AddCommand(NewCmdCreateClusterRole(f, out)) cmd.AddCommand(NewCmdCreateClusterRole(f, out))
cmd.AddCommand(NewCmdCreateClusterRoleBinding(f, out)) cmd.AddCommand(NewCmdCreateClusterRoleBinding(f, out))
cmd.AddCommand(NewCmdCreateRole(f, out)) cmd.AddCommand(NewCmdCreateRole(f, out))

View File

@ -22,6 +22,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -38,7 +39,7 @@ var (
) )
// NewCmdCreateDeployment is a macro command to create a new deployment // NewCmdCreateDeployment is a macro command to create a new deployment
func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "deployment NAME --image=image [--dry-run]", Use: "deployment NAME --image=image [--dry-run]",
Aliases: []string{"deploy"}, Aliases: []string{"deploy"},
@ -46,7 +47,7 @@ func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command
Long: deploymentLong, Long: deploymentLong,
Example: deploymentExample, Example: deploymentExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
err := CreateDeployment(f, cmdOut, cmd, args) err := CreateDeployment(f, cmdOut, cmdErr, cmd, args)
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
}, },
} }
@ -60,13 +61,33 @@ func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command
} }
// CreateDeployment implements the behavior to run the create deployment command // CreateDeployment implements the behavior to run the create deployment command
func CreateDeployment(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { func CreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string) error {
name, err := NameFromCommandArgs(cmd, args) name, err := NameFromCommandArgs(cmd, args)
if err != nil { if err != nil {
return err return err
} }
clientset, err := f.ClientSet()
if err != nil {
return err
}
resourcesList, err := clientset.Discovery().ServerResources()
// ServerResources ignores errors for old servers do not expose discovery
if err != nil {
return fmt.Errorf("failed to discover supported resources: %v", err)
}
generatorName := cmdutil.GetFlagString(cmd, "generator")
// fallback to the old generator if server does not support apps/v1beta1 deployments
if generatorName == cmdutil.DeploymentBasicAppsV1Beta1GeneratorName &&
!contains(resourcesList, appsv1beta1.SchemeGroupVersion.WithResource("deployments")) {
fmt.Fprintf(cmdErr, "WARNING: New deployments generator specified (%s), but apps/v1beta1.Deployments are not available, falling back to the old one (%s).\n",
cmdutil.DeploymentBasicAppsV1Beta1GeneratorName, cmdutil.DeploymentBasicV1Beta1GeneratorName)
generatorName = cmdutil.DeploymentBasicV1Beta1GeneratorName
}
var generator kubectl.StructuredGenerator var generator kubectl.StructuredGenerator
switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { switch generatorName {
case cmdutil.DeploymentBasicAppsV1Beta1GeneratorName:
generator = &kubectl.DeploymentBasicAppsGeneratorV1{Name: name, Images: cmdutil.GetFlagStringSlice(cmd, "image")}
case cmdutil.DeploymentBasicV1Beta1GeneratorName: case cmdutil.DeploymentBasicV1Beta1GeneratorName:
generator = &kubectl.DeploymentBasicGeneratorV1{Name: name, Images: cmdutil.GetFlagStringSlice(cmd, "image")} generator = &kubectl.DeploymentBasicGeneratorV1{Name: name, Images: cmdutil.GetFlagStringSlice(cmd, "image")}
default: default:

View File

@ -18,20 +18,37 @@ package cmd
import ( import (
"bytes" "bytes"
"io/ioutil"
"net/http"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
) )
func TestCreateDeployment(t *testing.T) { func TestCreateDeployment(t *testing.T) {
depName := "jonny-dep" depName := "jonny-dep"
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{
APIRegistry: api.Registry,
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(&bytes.Buffer{}),
}, nil
}),
}
tf.ClientConfig = &restclient.Config{}
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
cmd := NewCmdCreateDeployment(f, buf)
cmd := NewCmdCreateDeployment(f, buf, buf)
cmd.Flags().Set("dry-run", "true") cmd.Flags().Set("dry-run", "true")
cmd.Flags().Set("output", "name") cmd.Flags().Set("output", "name")
cmd.Flags().Set("image", "hollywood/jonny.depp:v2") cmd.Flags().Set("image", "hollywood/jonny.depp:v2")
@ -44,13 +61,25 @@ func TestCreateDeployment(t *testing.T) {
func TestCreateDeploymentNoImage(t *testing.T) { func TestCreateDeploymentNoImage(t *testing.T) {
depName := "jonny-dep" depName := "jonny-dep"
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{
APIRegistry: api.Registry,
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(&bytes.Buffer{}),
}, nil
}),
}
tf.ClientConfig = &restclient.Config{}
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
tf.Namespace = "test" tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
cmd := NewCmdCreateDeployment(f, buf) cmd := NewCmdCreateDeployment(f, buf, buf)
cmd.Flags().Set("dry-run", "true") cmd.Flags().Set("dry-run", "true")
cmd.Flags().Set("output", "name") cmd.Flags().Set("output", "name")
err := CreateDeployment(f, buf, cmd, []string{depName}) err := CreateDeployment(f, buf, buf, cmd, []string{depName})
assert.Error(t, err, "at least one image must be specified") assert.Error(t, err, "at least one image must be specified")
} }

View File

@ -33,8 +33,10 @@ import (
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/discovery" "k8s.io/client-go/discovery"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
batchv1 "k8s.io/kubernetes/pkg/apis/batch/v1" batchv1 "k8s.io/kubernetes/pkg/apis/batch/v1"
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1" batchv2alpha1 "k8s.io/kubernetes/pkg/apis/batch/v2alpha1"
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
conditions "k8s.io/kubernetes/pkg/client/unversioned" conditions "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
@ -196,38 +198,55 @@ func Run(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobr
return err return err
} }
clientset, err := f.ClientSet()
if err != nil {
return err
}
resourcesList, err := clientset.Discovery().ServerResources()
// ServerResources ignores errors for old servers do not expose discovery
if err != nil {
return fmt.Errorf("failed to discover supported resources: %v", err)
}
generatorName := cmdutil.GetFlagString(cmd, "generator") generatorName := cmdutil.GetFlagString(cmd, "generator")
schedule := cmdutil.GetFlagString(cmd, "schedule") schedule := cmdutil.GetFlagString(cmd, "schedule")
if len(schedule) != 0 && len(generatorName) == 0 { if len(schedule) != 0 && len(generatorName) == 0 {
generatorName = "cronjob/v2alpha1" generatorName = cmdutil.CronJobV2Alpha1GeneratorName
} }
if len(generatorName) == 0 { if len(generatorName) == 0 {
clientset, err := f.ClientSet()
if err != nil {
return err
}
resourcesList, err := clientset.Discovery().ServerResources()
// ServerResources ignores errors for old servers do not expose discovery
if err != nil {
return fmt.Errorf("failed to discover supported resources: %v", err)
}
switch restartPolicy { switch restartPolicy {
case api.RestartPolicyAlways: case api.RestartPolicyAlways:
if contains(resourcesList, v1beta1.SchemeGroupVersion.WithResource("deployments")) { // TODO: we need to deprecate this along with extensions/v1beta1.Deployments
generatorName = "deployment/v1beta1" // in favor of the new generator for apps/v1beta1.Deployments
if contains(resourcesList, extensionsv1beta1.SchemeGroupVersion.WithResource("deployments")) {
generatorName = cmdutil.DeploymentV1Beta1GeneratorName
} else { } else {
generatorName = "run/v1" generatorName = cmdutil.RunV1GeneratorName
} }
case api.RestartPolicyOnFailure: case api.RestartPolicyOnFailure:
if contains(resourcesList, batchv1.SchemeGroupVersion.WithResource("jobs")) { if contains(resourcesList, batchv1.SchemeGroupVersion.WithResource("jobs")) {
generatorName = "job/v1" generatorName = cmdutil.JobV1GeneratorName
} else { } else {
generatorName = "run-pod/v1" generatorName = cmdutil.RunPodV1GeneratorName
} }
case api.RestartPolicyNever: case api.RestartPolicyNever:
generatorName = "run-pod/v1" generatorName = cmdutil.RunPodV1GeneratorName
} }
} }
// TODO: this should be removed alongside with extensions/v1beta1 depployments generator
if generatorName == cmdutil.DeploymentAppsV1Beta1GeneratorName &&
!contains(resourcesList, appsv1beta1.SchemeGroupVersion.WithResource("deployments")) {
fmt.Fprintf(cmdErr, "WARNING: New deployments generator specified (%s), but apps/v1beta1.Deployments are not available, falling back to the old one (%s).\n",
cmdutil.DeploymentAppsV1Beta1GeneratorName, cmdutil.DeploymentV1Beta1GeneratorName)
generatorName = cmdutil.DeploymentV1Beta1GeneratorName
}
if generatorName == cmdutil.CronJobV2Alpha1GeneratorName &&
!contains(resourcesList, batchv2alpha1.SchemeGroupVersion.WithResource("cronjobs")) {
return fmt.Errorf("CronJob generator specified, but batch/v2alpha1.CronJobs are not available")
}
generators := f.Generators("run") generators := f.Generators("run")
generator, found := generators[generatorName] generator, found := generators[generatorName]
if !found { if !found {

View File

@ -35,6 +35,7 @@ import (
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/v1"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
) )
@ -113,7 +114,13 @@ func TestGetEnv(t *testing.T) {
} }
func TestRunArgsFollowDashRules(t *testing.T) { func TestRunArgsFollowDashRules(t *testing.T) {
_, _, rc := testData() one := int32(1)
rc := &v1.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "rc1", Namespace: "test", ResourceVersion: "18"},
Spec: v1.ReplicationControllerSpec{
Replicas: &one,
},
}
tests := []struct { tests := []struct {
args []string args []string
@ -158,7 +165,14 @@ func TestRunArgsFollowDashRules(t *testing.T) {
APIRegistry: api.Registry, APIRegistry: api.Registry,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: objBody(codec, &rc.Items[0])}, nil if req.URL.Path == "/namespaces/test/replicationcontrollers" {
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: objBody(codec, rc)}, nil
} else {
return &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(&bytes.Buffer{}),
}, nil
}
}), }),
} }
tf.Namespace = "test" tf.Namespace = "test"

View File

@ -456,31 +456,33 @@ func (f *ring0Factory) DefaultNamespace() (string, bool, error) {
} }
const ( const (
RunV1GeneratorName = "run/v1" RunV1GeneratorName = "run/v1"
RunPodV1GeneratorName = "run-pod/v1" RunPodV1GeneratorName = "run-pod/v1"
ServiceV1GeneratorName = "service/v1" ServiceV1GeneratorName = "service/v1"
ServiceV2GeneratorName = "service/v2" ServiceV2GeneratorName = "service/v2"
ServiceNodePortGeneratorV1Name = "service-nodeport/v1" ServiceNodePortGeneratorV1Name = "service-nodeport/v1"
ServiceClusterIPGeneratorV1Name = "service-clusterip/v1" ServiceClusterIPGeneratorV1Name = "service-clusterip/v1"
ServiceLoadBalancerGeneratorV1Name = "service-loadbalancer/v1" ServiceLoadBalancerGeneratorV1Name = "service-loadbalancer/v1"
ServiceExternalNameGeneratorV1Name = "service-externalname/v1" ServiceExternalNameGeneratorV1Name = "service-externalname/v1"
ServiceAccountV1GeneratorName = "serviceaccount/v1" ServiceAccountV1GeneratorName = "serviceaccount/v1"
HorizontalPodAutoscalerV1GeneratorName = "horizontalpodautoscaler/v1" HorizontalPodAutoscalerV1GeneratorName = "horizontalpodautoscaler/v1"
DeploymentV1Beta1GeneratorName = "deployment/v1beta1" DeploymentV1Beta1GeneratorName = "deployment/v1beta1"
DeploymentBasicV1Beta1GeneratorName = "deployment-basic/v1beta1" DeploymentAppsV1Beta1GeneratorName = "deployment/apps.v1beta1"
JobV1GeneratorName = "job/v1" DeploymentBasicV1Beta1GeneratorName = "deployment-basic/v1beta1"
CronJobV2Alpha1GeneratorName = "cronjob/v2alpha1" DeploymentBasicAppsV1Beta1GeneratorName = "deployment-basic/apps.v1beta1"
ScheduledJobV2Alpha1GeneratorName = "scheduledjob/v2alpha1" JobV1GeneratorName = "job/v1"
NamespaceV1GeneratorName = "namespace/v1" CronJobV2Alpha1GeneratorName = "cronjob/v2alpha1"
ResourceQuotaV1GeneratorName = "resourcequotas/v1" ScheduledJobV2Alpha1GeneratorName = "scheduledjob/v2alpha1"
SecretV1GeneratorName = "secret/v1" NamespaceV1GeneratorName = "namespace/v1"
SecretForDockerRegistryV1GeneratorName = "secret-for-docker-registry/v1" ResourceQuotaV1GeneratorName = "resourcequotas/v1"
SecretForTLSV1GeneratorName = "secret-for-tls/v1" SecretV1GeneratorName = "secret/v1"
ConfigMapV1GeneratorName = "configmap/v1" SecretForDockerRegistryV1GeneratorName = "secret-for-docker-registry/v1"
ClusterRoleBindingV1GeneratorName = "clusterrolebinding.rbac.authorization.k8s.io/v1alpha1" SecretForTLSV1GeneratorName = "secret-for-tls/v1"
RoleBindingV1GeneratorName = "rolebinding.rbac.authorization.k8s.io/v1alpha1" ConfigMapV1GeneratorName = "configmap/v1"
ClusterV1Beta1GeneratorName = "cluster/v1beta1" ClusterRoleBindingV1GeneratorName = "clusterrolebinding.rbac.authorization.k8s.io/v1alpha1"
PodDisruptionBudgetV1GeneratorName = "poddisruptionbudget/v1beta1" RoleBindingV1GeneratorName = "rolebinding.rbac.authorization.k8s.io/v1alpha1"
ClusterV1Beta1GeneratorName = "cluster/v1beta1"
PodDisruptionBudgetV1GeneratorName = "poddisruptionbudget/v1beta1"
) )
// DefaultGenerators returns the set of default generators for use in Factory instances // DefaultGenerators returns the set of default generators for use in Factory instances
@ -506,16 +508,18 @@ func DefaultGenerators(cmdName string) map[string]kubectl.Generator {
} }
case "deployment": case "deployment":
generator = map[string]kubectl.Generator{ generator = map[string]kubectl.Generator{
DeploymentBasicV1Beta1GeneratorName: kubectl.DeploymentBasicGeneratorV1{}, DeploymentBasicV1Beta1GeneratorName: kubectl.DeploymentBasicGeneratorV1{},
DeploymentBasicAppsV1Beta1GeneratorName: kubectl.DeploymentBasicAppsGeneratorV1{},
} }
case "run": case "run":
generator = map[string]kubectl.Generator{ generator = map[string]kubectl.Generator{
RunV1GeneratorName: kubectl.BasicReplicationController{}, RunV1GeneratorName: kubectl.BasicReplicationController{},
RunPodV1GeneratorName: kubectl.BasicPod{}, RunPodV1GeneratorName: kubectl.BasicPod{},
DeploymentV1Beta1GeneratorName: kubectl.DeploymentV1Beta1{}, DeploymentV1Beta1GeneratorName: kubectl.DeploymentV1Beta1{},
JobV1GeneratorName: kubectl.JobV1{}, DeploymentAppsV1Beta1GeneratorName: kubectl.DeploymentAppsV1Beta1{},
ScheduledJobV2Alpha1GeneratorName: kubectl.CronJobV2Alpha1{}, JobV1GeneratorName: kubectl.JobV1{},
CronJobV2Alpha1GeneratorName: kubectl.CronJobV2Alpha1{}, ScheduledJobV2Alpha1GeneratorName: kubectl.CronJobV2Alpha1{},
CronJobV2Alpha1GeneratorName: kubectl.CronJobV2Alpha1{},
} }
case "autoscale": case "autoscale":
generator = map[string]kubectl.Generator{ generator = map[string]kubectl.Generator{

View File

@ -22,8 +22,9 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/extensions" appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
) )
// DeploymentBasicGeneratorV1 supports stable generation of a deployment // DeploymentBasicGeneratorV1 supports stable generation of a deployment
@ -65,7 +66,7 @@ func (s *DeploymentBasicGeneratorV1) StructuredGenerate() (runtime.Object, error
return nil, err return nil, err
} }
podSpec := api.PodSpec{Containers: []api.Container{}} podSpec := v1.PodSpec{Containers: []v1.Container{}}
for _, imageString := range s.Images { for _, imageString := range s.Images {
// Retain just the image name // Retain just the image name
imageSplit := strings.Split(imageString, "/") imageSplit := strings.Split(imageString, "/")
@ -76,22 +77,23 @@ func (s *DeploymentBasicGeneratorV1) StructuredGenerate() (runtime.Object, error
} else if strings.Contains(name, "@") { } else if strings.Contains(name, "@") {
name = strings.Split(name, "@")[0] name = strings.Split(name, "@")[0]
} }
podSpec.Containers = append(podSpec.Containers, api.Container{Name: name, Image: imageString}) podSpec.Containers = append(podSpec.Containers, v1.Container{Name: name, Image: imageString})
} }
// setup default label and selector // setup default label and selector
labels := map[string]string{} labels := map[string]string{}
labels["app"] = s.Name labels["app"] = s.Name
one := int32(1)
selector := metav1.LabelSelector{MatchLabels: labels} selector := metav1.LabelSelector{MatchLabels: labels}
deployment := extensions.Deployment{ deployment := extensionsv1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: s.Name, Name: s.Name,
Labels: labels, Labels: labels,
}, },
Spec: extensions.DeploymentSpec{ Spec: extensionsv1beta1.DeploymentSpec{
Replicas: 1, Replicas: &one,
Selector: &selector, Selector: &selector,
Template: api.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: labels, Labels: labels,
}, },
@ -112,3 +114,91 @@ func (s *DeploymentBasicGeneratorV1) validate() error {
} }
return nil return nil
} }
// DeploymentBasicAppsGeneratorV1 supports stable generation of a deployment under apps/v1beta1 endpoint
type DeploymentBasicAppsGeneratorV1 struct {
Name string
Images []string
}
// Ensure it supports the generator pattern that uses parameters specified during construction
var _ StructuredGenerator = &DeploymentBasicAppsGeneratorV1{}
func (DeploymentBasicAppsGeneratorV1) ParamNames() []GeneratorParam {
return []GeneratorParam{
{"name", true},
{"image", true},
}
}
func (s DeploymentBasicAppsGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) {
err := ValidateParams(s.ParamNames(), params)
if err != nil {
return nil, err
}
name, isString := params["name"].(string)
if !isString {
return nil, fmt.Errorf("expected string, saw %v for 'name'", name)
}
imageStrings, isArray := params["image"].([]string)
if !isArray {
return nil, fmt.Errorf("expected []string, found :%v", imageStrings)
}
delegate := &DeploymentBasicAppsGeneratorV1{Name: name, Images: imageStrings}
return delegate.StructuredGenerate()
}
// StructuredGenerate outputs a deployment object using the configured fields
func (s *DeploymentBasicAppsGeneratorV1) StructuredGenerate() (runtime.Object, error) {
if err := s.validate(); err != nil {
return nil, err
}
podSpec := v1.PodSpec{Containers: []v1.Container{}}
for _, imageString := range s.Images {
// Retain just the image name
imageSplit := strings.Split(imageString, "/")
name := imageSplit[len(imageSplit)-1]
// Remove any tag or hash
if strings.Contains(name, ":") {
name = strings.Split(name, ":")[0]
} else if strings.Contains(name, "@") {
name = strings.Split(name, "@")[0]
}
podSpec.Containers = append(podSpec.Containers, v1.Container{Name: name, Image: imageString})
}
// setup default label and selector
labels := map[string]string{}
labels["app"] = s.Name
one := int32(1)
selector := metav1.LabelSelector{MatchLabels: labels}
deployment := appsv1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: s.Name,
Labels: labels,
},
Spec: appsv1beta1.DeploymentSpec{
Replicas: &one,
Selector: &selector,
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: podSpec,
},
},
}
return &deployment, nil
}
// validate validates required fields are set to support structured generation
func (s *DeploymentBasicAppsGeneratorV1) validate() error {
if len(s.Name) == 0 {
return fmt.Errorf("name must be specified")
}
if len(s.Images) == 0 {
return fmt.Errorf("at least one image must be specified")
}
return nil
}

View File

@ -21,14 +21,16 @@ import (
"testing" "testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/extensions" appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
) )
func TestDeploymentGenerate(t *testing.T) { func TestDeploymentGenerate(t *testing.T) {
one := int32(1)
tests := []struct { tests := []struct {
params map[string]interface{} params map[string]interface{}
expected *extensions.Deployment expected *extensionsv1beta1.Deployment
expectErr bool expectErr bool
}{ }{
{ {
@ -36,20 +38,20 @@ func TestDeploymentGenerate(t *testing.T) {
"name": "foo", "name": "foo",
"image": []string{"abc/app:v4"}, "image": []string{"abc/app:v4"},
}, },
expected: &extensions.Deployment{ expected: &extensionsv1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"app": "foo"}, Labels: map[string]string{"app": "foo"},
}, },
Spec: extensions.DeploymentSpec{ Spec: extensionsv1beta1.DeploymentSpec{
Replicas: 1, Replicas: &one,
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "foo"}}, Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "foo"}},
Template: api.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"app": "foo"}, Labels: map[string]string{"app": "foo"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{{Name: "app", Image: "abc/app:v4"}}, Containers: []v1.Container{{Name: "app", Image: "abc/app:v4"}},
}, },
}, },
}, },
@ -61,20 +63,20 @@ func TestDeploymentGenerate(t *testing.T) {
"name": "foo", "name": "foo",
"image": []string{"abc/app:v4", "zyx/ape"}, "image": []string{"abc/app:v4", "zyx/ape"},
}, },
expected: &extensions.Deployment{ expected: &extensionsv1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"app": "foo"}, Labels: map[string]string{"app": "foo"},
}, },
Spec: extensions.DeploymentSpec{ Spec: extensionsv1beta1.DeploymentSpec{
Replicas: 1, Replicas: &one,
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "foo"}}, Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "foo"}},
Template: api.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"app": "foo"}, Labels: map[string]string{"app": "foo"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{{Name: "app", Image: "abc/app:v4"}, Containers: []v1.Container{{Name: "app", Image: "abc/app:v4"},
{Name: "ape", Image: "zyx/ape"}}, {Name: "ape", Image: "zyx/ape"}},
}, },
}, },
@ -128,8 +130,118 @@ func TestDeploymentGenerate(t *testing.T) {
case !test.expectErr && err == nil: case !test.expectErr && err == nil:
// do nothing and drop through // do nothing and drop through
} }
if !reflect.DeepEqual(obj.(*extensions.Deployment), test.expected) { if !reflect.DeepEqual(obj.(*extensionsv1beta1.Deployment), test.expected) {
t.Errorf("expected:\n%#v\nsaw:\n%#v", test.expected, obj.(*extensions.Deployment)) t.Errorf("expected:\n%#v\nsaw:\n%#v", test.expected, obj.(*extensionsv1beta1.Deployment))
}
}
}
func TestAppsDeploymentGenerate(t *testing.T) {
one := int32(1)
tests := []struct {
params map[string]interface{}
expected *appsv1beta1.Deployment
expectErr bool
}{
{
params: map[string]interface{}{
"name": "foo",
"image": []string{"abc/app:v4"},
},
expected: &appsv1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Labels: map[string]string{"app": "foo"},
},
Spec: appsv1beta1.DeploymentSpec{
Replicas: &one,
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "foo"}},
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"app": "foo"},
},
Spec: v1.PodSpec{
Containers: []v1.Container{{Name: "app", Image: "abc/app:v4"}},
},
},
},
},
expectErr: false,
},
{
params: map[string]interface{}{
"name": "foo",
"image": []string{"abc/app:v4", "zyx/ape"},
},
expected: &appsv1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Labels: map[string]string{"app": "foo"},
},
Spec: appsv1beta1.DeploymentSpec{
Replicas: &one,
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "foo"}},
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"app": "foo"},
},
Spec: v1.PodSpec{
Containers: []v1.Container{{Name: "app", Image: "abc/app:v4"},
{Name: "ape", Image: "zyx/ape"}},
},
},
},
},
expectErr: false,
},
{
params: map[string]interface{}{},
expectErr: true,
},
{
params: map[string]interface{}{
"name": 1,
},
expectErr: true,
},
{
params: map[string]interface{}{
"name": nil,
},
expectErr: true,
},
{
params: map[string]interface{}{
"name": "foo",
"image": []string{},
},
expectErr: true,
},
{
params: map[string]interface{}{
"NAME": "some_value",
},
expectErr: true,
},
}
generator := DeploymentBasicAppsGeneratorV1{}
for index, test := range tests {
t.Logf("running scenario %d", index)
obj, err := generator.Generate(test.params)
switch {
case test.expectErr && err != nil:
continue // loop, since there's no output to check
case test.expectErr && err == nil:
t.Errorf("expected error and didn't get one")
continue // loop, no expected output object
case !test.expectErr && err != nil:
t.Errorf("unexpected error %v", err)
continue // loop, no output object
case !test.expectErr && err == nil:
// do nothing and drop through
}
if !reflect.DeepEqual(obj.(*appsv1beta1.Deployment), test.expected) {
t.Errorf("expected:\n%#v\nsaw:\n%#v", test.expected, obj.(*appsv1beta1.Deployment))
} }
} }
} }

View File

@ -26,8 +26,11 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/extensions" appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
batchv1 "k8s.io/kubernetes/pkg/apis/batch/v1"
batchv2alpha1 "k8s.io/kubernetes/pkg/apis/batch/v2alpha1"
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
) )
type DeploymentV1Beta1 struct{} type DeploymentV1Beta1 struct{}
@ -88,7 +91,7 @@ func (DeploymentV1Beta1) Generate(genericParams map[string]interface{}) (runtime
return nil, err return nil, err
} }
imagePullPolicy := api.PullPolicy(params["image-pull-policy"]) imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil { if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
return nil, err return nil, err
} }
@ -99,15 +102,16 @@ func (DeploymentV1Beta1) Generate(genericParams map[string]interface{}) (runtime
// TODO: use versioned types for generators so that we don't need to // TODO: use versioned types for generators so that we don't need to
// set default values manually (see issue #17384) // set default values manually (see issue #17384)
deployment := extensions.Deployment{ count32 := int32(count)
deployment := extensionsv1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Labels: labels, Labels: labels,
}, },
Spec: extensions.DeploymentSpec{ Spec: extensionsv1beta1.DeploymentSpec{
Replicas: int32(count), Replicas: &count32,
Selector: &metav1.LabelSelector{MatchLabels: labels}, Selector: &metav1.LabelSelector{MatchLabels: labels},
Template: api.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: labels, Labels: labels,
}, },
@ -118,6 +122,94 @@ func (DeploymentV1Beta1) Generate(genericParams map[string]interface{}) (runtime
return &deployment, nil return &deployment, nil
} }
type DeploymentAppsV1Beta1 struct{}
func (DeploymentAppsV1Beta1) ParamNames() []GeneratorParam {
return []GeneratorParam{
{"labels", false},
{"default-name", false},
{"name", true},
{"replicas", true},
{"image", true},
{"image-pull-policy", false},
{"port", false},
{"hostport", false},
{"stdin", false},
{"tty", false},
{"command", false},
{"args", false},
{"env", false},
{"requests", false},
{"limits", false},
}
}
func (DeploymentAppsV1Beta1) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
args, err := getArgs(genericParams)
if err != nil {
return nil, err
}
envs, err := getEnvs(genericParams)
if err != nil {
return nil, err
}
params, err := getParams(genericParams)
if err != nil {
return nil, err
}
name, err := getName(params)
if err != nil {
return nil, err
}
labels, err := getLabels(params, true, name)
if err != nil {
return nil, err
}
count, err := strconv.Atoi(params["replicas"])
if err != nil {
return nil, err
}
podSpec, err := makePodSpec(params, name)
if err != nil {
return nil, err
}
imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
return nil, err
}
if err := updatePodPorts(params, podSpec); err != nil {
return nil, err
}
count32 := int32(count)
deployment := appsv1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Labels: labels,
},
Spec: appsv1beta1.DeploymentSpec{
Replicas: &count32,
Selector: &metav1.LabelSelector{MatchLabels: labels},
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: *podSpec,
},
},
}
return &deployment, nil
}
// getLabels returns map of labels.
func getLabels(params map[string]string, defaultRunLabel bool, name string) (map[string]string, error) { func getLabels(params map[string]string, defaultRunLabel bool, name string) (map[string]string, error) {
labelString, found := params["labels"] labelString, found := params["labels"]
var labels map[string]string var labels map[string]string
@ -135,6 +227,7 @@ func getLabels(params map[string]string, defaultRunLabel bool, name string) (map
return labels, nil return labels, nil
} }
// getName returns the name of newly created resource.
func getName(params map[string]string) (string, error) { func getName(params map[string]string) (string, error) {
name, found := params["name"] name, found := params["name"]
if !found || len(name) == 0 { if !found || len(name) == 0 {
@ -146,6 +239,7 @@ func getName(params map[string]string) (string, error) {
return name, nil return name, nil
} }
// getParams returns map of generic parameters.
func getParams(genericParams map[string]interface{}) (map[string]string, error) { func getParams(genericParams map[string]interface{}) (map[string]string, error) {
params := map[string]string{} params := map[string]string{}
for key, value := range genericParams { for key, value := range genericParams {
@ -158,6 +252,7 @@ func getParams(genericParams map[string]interface{}) (map[string]string, error)
return params, nil return params, nil
} }
// getArgs returns arguments for the container command.
func getArgs(genericParams map[string]interface{}) ([]string, error) { func getArgs(genericParams map[string]interface{}) ([]string, error) {
args := []string{} args := []string{}
val, found := genericParams["args"] val, found := genericParams["args"]
@ -172,8 +267,9 @@ func getArgs(genericParams map[string]interface{}) ([]string, error) {
return args, nil return args, nil
} }
func getEnvs(genericParams map[string]interface{}) ([]api.EnvVar, error) { // getEnvs returns environment variables.
var envs []api.EnvVar func getEnvs(genericParams map[string]interface{}) ([]v1.EnvVar, error) {
var envs []v1.EnvVar
envStrings, found := genericParams["env"] envStrings, found := genericParams["env"]
if found { if found {
if envStringArray, isArray := envStrings.([]string); isArray { if envStringArray, isArray := envStrings.([]string); isArray {
@ -244,7 +340,7 @@ func (JobV1) Generate(genericParams map[string]interface{}) (runtime.Object, err
return nil, err return nil, err
} }
imagePullPolicy := api.PullPolicy(params["image-pull-policy"]) imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil { if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
return nil, err return nil, err
} }
@ -259,19 +355,19 @@ func (JobV1) Generate(genericParams map[string]interface{}) (runtime.Object, err
return nil, err return nil, err
} }
restartPolicy := api.RestartPolicy(params["restart"]) restartPolicy := v1.RestartPolicy(params["restart"])
if len(restartPolicy) == 0 { if len(restartPolicy) == 0 {
restartPolicy = api.RestartPolicyNever restartPolicy = v1.RestartPolicyNever
} }
podSpec.RestartPolicy = restartPolicy podSpec.RestartPolicy = restartPolicy
job := batch.Job{ job := batchv1.Job{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Labels: labels, Labels: labels,
}, },
Spec: batch.JobSpec{ Spec: batchv1.JobSpec{
Template: api.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: labels, Labels: labels,
}, },
@ -338,7 +434,7 @@ func (CronJobV2Alpha1) Generate(genericParams map[string]interface{}) (runtime.O
return nil, err return nil, err
} }
imagePullPolicy := api.PullPolicy(params["image-pull-policy"]) imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil { if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
return nil, err return nil, err
} }
@ -353,23 +449,23 @@ func (CronJobV2Alpha1) Generate(genericParams map[string]interface{}) (runtime.O
return nil, err return nil, err
} }
restartPolicy := api.RestartPolicy(params["restart"]) restartPolicy := v1.RestartPolicy(params["restart"])
if len(restartPolicy) == 0 { if len(restartPolicy) == 0 {
restartPolicy = api.RestartPolicyNever restartPolicy = v1.RestartPolicyNever
} }
podSpec.RestartPolicy = restartPolicy podSpec.RestartPolicy = restartPolicy
cronJob := batch.CronJob{ cronJob := batchv2alpha1.CronJob{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Labels: labels, Labels: labels,
}, },
Spec: batch.CronJobSpec{ Spec: batchv2alpha1.CronJobSpec{
Schedule: params["schedule"], Schedule: params["schedule"],
ConcurrencyPolicy: batch.AllowConcurrent, ConcurrencyPolicy: batchv2alpha1.AllowConcurrent,
JobTemplate: batch.JobTemplateSpec{ JobTemplate: batchv2alpha1.JobTemplateSpec{
Spec: batch.JobSpec{ Spec: batchv1.JobSpec{
Template: api.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: labels, Labels: labels,
}, },
@ -406,6 +502,7 @@ func (BasicReplicationController) ParamNames() []GeneratorParam {
} }
// populateResourceList takes strings of form <resourceName1>=<value1>,<resourceName1>=<value2> // populateResourceList takes strings of form <resourceName1>=<value1>,<resourceName1>=<value2>
// and returns ResourceList.
func populateResourceList(spec string) (api.ResourceList, error) { func populateResourceList(spec string) (api.ResourceList, error) {
// empty input gets a nil response to preserve generator test expected behaviors // empty input gets a nil response to preserve generator test expected behaviors
if spec == "" { if spec == "" {
@ -429,7 +526,33 @@ func populateResourceList(spec string) (api.ResourceList, error) {
return result, nil return result, nil
} }
// populateResourceListV1 takes strings of form <resourceName1>=<value1>,<resourceName1>=<value2>
// and returns ResourceList.
func populateResourceListV1(spec string) (v1.ResourceList, error) {
// empty input gets a nil response to preserve generator test expected behaviors
if spec == "" {
return nil, nil
}
result := v1.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 := v1.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 // HandleResourceRequirements parses the limits and requests parameters if specified
// and returns ResourceRequirements.
func HandleResourceRequirements(params map[string]string) (api.ResourceRequirements, error) { func HandleResourceRequirements(params map[string]string) (api.ResourceRequirements, error) {
result := api.ResourceRequirements{} result := api.ResourceRequirements{}
limits, err := populateResourceList(params["limits"]) limits, err := populateResourceList(params["limits"])
@ -445,7 +568,25 @@ func HandleResourceRequirements(params map[string]string) (api.ResourceRequireme
return result, nil return result, nil
} }
func makePodSpec(params map[string]string, name string) (*api.PodSpec, error) { // HandleResourceRequirementsV1 parses the limits and requests parameters if specified
// and returns ResourceRequirements.
func HandleResourceRequirementsV1(params map[string]string) (v1.ResourceRequirements, error) {
result := v1.ResourceRequirements{}
limits, err := populateResourceListV1(params["limits"])
if err != nil {
return result, err
}
result.Limits = limits
requests, err := populateResourceListV1(params["requests"])
if err != nil {
return result, err
}
result.Requests = requests
return result, nil
}
// makePodSpec returns PodSpec filled with passed parameters.
func makePodSpec(params map[string]string, name string) (*v1.PodSpec, error) {
stdin, err := GetBool(params, "stdin", false) stdin, err := GetBool(params, "stdin", false)
if err != nil { if err != nil {
return nil, err return nil, err
@ -456,13 +597,13 @@ func makePodSpec(params map[string]string, name string) (*api.PodSpec, error) {
return nil, err return nil, err
} }
resourceRequirements, err := HandleResourceRequirements(params) resourceRequirements, err := HandleResourceRequirementsV1(params)
if err != nil { if err != nil {
return nil, err return nil, err
} }
spec := api.PodSpec{ spec := v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: name, Name: name,
Image: params["image"], Image: params["image"],
@ -511,7 +652,7 @@ func (BasicReplicationController) Generate(genericParams map[string]interface{})
return nil, err return nil, err
} }
imagePullPolicy := api.PullPolicy(params["image-pull-policy"]) imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil { if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
return nil, err return nil, err
} }
@ -520,15 +661,16 @@ func (BasicReplicationController) Generate(genericParams map[string]interface{})
return nil, err return nil, err
} }
controller := api.ReplicationController{ count32 := int32(count)
controller := v1.ReplicationController{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Labels: labels, Labels: labels,
}, },
Spec: api.ReplicationControllerSpec{ Spec: v1.ReplicationControllerSpec{
Replicas: int32(count), Replicas: &count32,
Selector: labels, Selector: labels,
Template: &api.PodTemplateSpec{ Template: &v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: labels, Labels: labels,
}, },
@ -539,7 +681,8 @@ func (BasicReplicationController) Generate(genericParams map[string]interface{})
return &controller, nil return &controller, nil
} }
func updatePodContainers(params map[string]string, args []string, envs []api.EnvVar, imagePullPolicy api.PullPolicy, podSpec *api.PodSpec) error { // updatePodContainers updates PodSpec.Containers with passed parameters.
func updatePodContainers(params map[string]string, args []string, envs []v1.EnvVar, imagePullPolicy v1.PullPolicy, podSpec *v1.PodSpec) error {
if len(args) > 0 { if len(args) > 0 {
command, err := GetBool(params, "command", false) command, err := GetBool(params, "command", false)
if err != nil { if err != nil {
@ -563,7 +706,8 @@ func updatePodContainers(params map[string]string, args []string, envs []api.Env
return nil return nil
} }
func updatePodPorts(params map[string]string, podSpec *api.PodSpec) (err error) { // updatePodContainers updates PodSpec.Containers.Ports with passed parameters.
func updatePodPorts(params map[string]string, podSpec *v1.PodSpec) (err error) {
port := -1 port := -1
hostPort := -1 hostPort := -1
if len(params["port"]) > 0 { if len(params["port"]) > 0 {
@ -585,7 +729,7 @@ func updatePodPorts(params map[string]string, podSpec *api.PodSpec) (err error)
// Don't include the port if it was not specified. // Don't include the port if it was not specified.
if len(params["port"]) > 0 { if len(params["port"]) > 0 {
podSpec.Containers[0].Ports = []api.ContainerPort{ podSpec.Containers[0].Ports = []v1.ContainerPort{
{ {
ContainerPort: int32(port), ContainerPort: int32(port),
}, },
@ -660,39 +804,39 @@ func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object,
return nil, err return nil, err
} }
resourceRequirements, err := HandleResourceRequirements(params) resourceRequirements, err := HandleResourceRequirementsV1(params)
if err != nil { if err != nil {
return nil, err return nil, err
} }
restartPolicy := api.RestartPolicy(params["restart"]) restartPolicy := v1.RestartPolicy(params["restart"])
if len(restartPolicy) == 0 { if len(restartPolicy) == 0 {
restartPolicy = api.RestartPolicyAlways restartPolicy = v1.RestartPolicyAlways
} }
// TODO: Figure out why we set ImagePullPolicy here, whether we can make it // TODO: Figure out why we set ImagePullPolicy here, whether we can make it
// consistent with the other places imagePullPolicy is set using flag. // consistent with the other places imagePullPolicy is set using flag.
pod := api.Pod{ pod := v1.Pod{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Labels: labels, Labels: labels,
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: name, Name: name,
Image: params["image"], Image: params["image"],
ImagePullPolicy: api.PullIfNotPresent, ImagePullPolicy: v1.PullIfNotPresent,
Stdin: stdin, Stdin: stdin,
StdinOnce: !leaveStdinOpen && stdin, StdinOnce: !leaveStdinOpen && stdin,
TTY: tty, TTY: tty,
Resources: resourceRequirements, Resources: resourceRequirements,
}, },
}, },
DNSPolicy: api.DNSClusterFirst, DNSPolicy: v1.DNSClusterFirst,
RestartPolicy: restartPolicy, RestartPolicy: restartPolicy,
}, },
} }
imagePullPolicy := api.PullPolicy(params["image-pull-policy"]) imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
if err = updatePodContainers(params, args, envs, imagePullPolicy, &pod.Spec); err != nil { if err = updatePodContainers(params, args, envs, imagePullPolicy, &pod.Spec); err != nil {
return nil, err return nil, err
} }
@ -703,8 +847,9 @@ func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object,
return &pod, nil return &pod, nil
} }
func parseEnvs(envArray []string) ([]api.EnvVar, error) { // parseEnvs converts string into EnvVar objects.
envs := make([]api.EnvVar, 0, len(envArray)) func parseEnvs(envArray []string) ([]v1.EnvVar, error) {
envs := make([]v1.EnvVar, 0, len(envArray))
for _, env := range envArray { for _, env := range envArray {
pos := strings.Index(env, "=") pos := strings.Index(env, "=")
if pos == -1 { if pos == -1 {
@ -718,7 +863,7 @@ func parseEnvs(envArray []string) ([]api.EnvVar, error) {
if len(validation.IsCIdentifier(name)) != 0 { if len(validation.IsCIdentifier(name)) != 0 {
return nil, fmt.Errorf("invalid env: %v", env) return nil, fmt.Errorf("invalid env: %v", env)
} }
envVar := api.EnvVar{Name: name, Value: value} envVar := v1.EnvVar{Name: name, Value: value}
envs = append(envs, envVar) envs = append(envs, envVar)
} }
return envs, nil return envs, nil

View File

@ -22,15 +22,18 @@ import (
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/batch" appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
"k8s.io/kubernetes/pkg/apis/extensions" batchv1 "k8s.io/kubernetes/pkg/apis/batch/v1"
batchv2alpha1 "k8s.io/kubernetes/pkg/apis/batch/v2alpha1"
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
) )
func TestGenerate(t *testing.T) { func TestGenerate(t *testing.T) {
one := int32(1)
tests := []struct { tests := []struct {
params map[string]interface{} params map[string]interface{}
expected *api.ReplicationController expected *v1.ReplicationController
expectErr bool expectErr bool
}{ }{
{ {
@ -41,24 +44,24 @@ func TestGenerate(t *testing.T) {
"replicas": "1", "replicas": "1",
"port": "", "port": "",
}, },
expected: &api.ReplicationController{ expected: &v1.ReplicationController{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"run": "foo"}, Labels: map[string]string{"run": "foo"},
}, },
Spec: api.ReplicationControllerSpec{ Spec: v1.ReplicationControllerSpec{
Replicas: 1, Replicas: &one,
Selector: map[string]string{"run": "foo"}, Selector: map[string]string{"run": "foo"},
Template: &api.PodTemplateSpec{ Template: &v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"run": "foo"}, Labels: map[string]string{"run": "foo"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
ImagePullPolicy: api.PullAlways, ImagePullPolicy: v1.PullAlways,
}, },
}, },
}, },
@ -75,24 +78,24 @@ func TestGenerate(t *testing.T) {
"port": "", "port": "",
"env": []string{"a=b", "c=d"}, "env": []string{"a=b", "c=d"},
}, },
expected: &api.ReplicationController{ expected: &v1.ReplicationController{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"run": "foo"}, Labels: map[string]string{"run": "foo"},
}, },
Spec: api.ReplicationControllerSpec{ Spec: v1.ReplicationControllerSpec{
Replicas: 1, Replicas: &one,
Selector: map[string]string{"run": "foo"}, Selector: map[string]string{"run": "foo"},
Template: &api.PodTemplateSpec{ Template: &v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"run": "foo"}, Labels: map[string]string{"run": "foo"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
Env: []api.EnvVar{ Env: []v1.EnvVar{
{ {
Name: "a", Name: "a",
Value: "b", Value: "b",
@ -119,24 +122,24 @@ func TestGenerate(t *testing.T) {
"port": "", "port": "",
"args": []string{"bar", "baz", "blah"}, "args": []string{"bar", "baz", "blah"},
}, },
expected: &api.ReplicationController{ expected: &v1.ReplicationController{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"run": "foo"}, Labels: map[string]string{"run": "foo"},
}, },
Spec: api.ReplicationControllerSpec{ Spec: v1.ReplicationControllerSpec{
Replicas: 1, Replicas: &one,
Selector: map[string]string{"run": "foo"}, Selector: map[string]string{"run": "foo"},
Template: &api.PodTemplateSpec{ Template: &v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"run": "foo"}, Labels: map[string]string{"run": "foo"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
ImagePullPolicy: api.PullNever, ImagePullPolicy: v1.PullNever,
Args: []string{"bar", "baz", "blah"}, Args: []string{"bar", "baz", "blah"},
}, },
}, },
@ -154,20 +157,20 @@ func TestGenerate(t *testing.T) {
"args": []string{"bar", "baz", "blah"}, "args": []string{"bar", "baz", "blah"},
"command": "true", "command": "true",
}, },
expected: &api.ReplicationController{ expected: &v1.ReplicationController{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"run": "foo"}, Labels: map[string]string{"run": "foo"},
}, },
Spec: api.ReplicationControllerSpec{ Spec: v1.ReplicationControllerSpec{
Replicas: 1, Replicas: &one,
Selector: map[string]string{"run": "foo"}, Selector: map[string]string{"run": "foo"},
Template: &api.PodTemplateSpec{ Template: &v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"run": "foo"}, Labels: map[string]string{"run": "foo"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
@ -186,24 +189,24 @@ func TestGenerate(t *testing.T) {
"replicas": "1", "replicas": "1",
"port": "80", "port": "80",
}, },
expected: &api.ReplicationController{ expected: &v1.ReplicationController{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"run": "foo"}, Labels: map[string]string{"run": "foo"},
}, },
Spec: api.ReplicationControllerSpec{ Spec: v1.ReplicationControllerSpec{
Replicas: 1, Replicas: &one,
Selector: map[string]string{"run": "foo"}, Selector: map[string]string{"run": "foo"},
Template: &api.PodTemplateSpec{ Template: &v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"run": "foo"}, Labels: map[string]string{"run": "foo"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
Ports: []api.ContainerPort{ Ports: []v1.ContainerPort{
{ {
ContainerPort: 80, ContainerPort: 80,
}, },
@ -224,25 +227,25 @@ func TestGenerate(t *testing.T) {
"port": "80", "port": "80",
"hostport": "80", "hostport": "80",
}, },
expected: &api.ReplicationController{ expected: &v1.ReplicationController{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"run": "foo"}, Labels: map[string]string{"run": "foo"},
}, },
Spec: api.ReplicationControllerSpec{ Spec: v1.ReplicationControllerSpec{
Replicas: 1, Replicas: &one,
Selector: map[string]string{"run": "foo"}, Selector: map[string]string{"run": "foo"},
Template: &api.PodTemplateSpec{ Template: &v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"run": "foo"}, Labels: map[string]string{"run": "foo"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent, ImagePullPolicy: v1.PullIfNotPresent,
Ports: []api.ContainerPort{ Ports: []v1.ContainerPort{
{ {
ContainerPort: 80, ContainerPort: 80,
HostPort: 80, HostPort: 80,
@ -272,20 +275,20 @@ func TestGenerate(t *testing.T) {
"replicas": "1", "replicas": "1",
"labels": "foo=bar,baz=blah", "labels": "foo=bar,baz=blah",
}, },
expected: &api.ReplicationController{ expected: &v1.ReplicationController{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"foo": "bar", "baz": "blah"}, Labels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
Spec: api.ReplicationControllerSpec{ Spec: v1.ReplicationControllerSpec{
Replicas: 1, Replicas: &one,
Selector: map[string]string{"foo": "bar", "baz": "blah"}, Selector: map[string]string{"foo": "bar", "baz": "blah"},
Template: &api.PodTemplateSpec{ Template: &v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"foo": "bar", "baz": "blah"}, Labels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
@ -348,31 +351,31 @@ func TestGenerate(t *testing.T) {
"requests": "cpu=100m,memory=100Mi", "requests": "cpu=100m,memory=100Mi",
"limits": "cpu=400m,memory=200Mi", "limits": "cpu=400m,memory=200Mi",
}, },
expected: &api.ReplicationController{ expected: &v1.ReplicationController{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"foo": "bar", "baz": "blah"}, Labels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
Spec: api.ReplicationControllerSpec{ Spec: v1.ReplicationControllerSpec{
Replicas: 1, Replicas: &one,
Selector: map[string]string{"foo": "bar", "baz": "blah"}, Selector: map[string]string{"foo": "bar", "baz": "blah"},
Template: &api.PodTemplateSpec{ Template: &v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"foo": "bar", "baz": "blah"}, Labels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
Resources: api.ResourceRequirements{ Resources: v1.ResourceRequirements{
Requests: api.ResourceList{ Requests: v1.ResourceList{
api.ResourceCPU: resource.MustParse("100m"), v1.ResourceCPU: resource.MustParse("100m"),
api.ResourceMemory: resource.MustParse("100Mi"), v1.ResourceMemory: resource.MustParse("100Mi"),
}, },
Limits: api.ResourceList{ Limits: v1.ResourceList{
api.ResourceCPU: resource.MustParse("400m"), v1.ResourceCPU: resource.MustParse("400m"),
api.ResourceMemory: resource.MustParse("200Mi"), v1.ResourceMemory: resource.MustParse("200Mi"),
}, },
}, },
}, },
@ -394,8 +397,8 @@ func TestGenerate(t *testing.T) {
if test.expectErr && err != nil { if test.expectErr && err != nil {
continue continue
} }
if !reflect.DeepEqual(obj.(*api.ReplicationController).Spec.Template, test.expected.Spec.Template) { if !reflect.DeepEqual(obj.(*v1.ReplicationController).Spec.Template, test.expected.Spec.Template) {
t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected.Spec.Template, obj.(*api.ReplicationController).Spec.Template) t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected.Spec.Template, obj.(*v1.ReplicationController).Spec.Template)
} }
} }
} }
@ -403,7 +406,7 @@ func TestGenerate(t *testing.T) {
func TestGeneratePod(t *testing.T) { func TestGeneratePod(t *testing.T) {
tests := []struct { tests := []struct {
params map[string]interface{} params map[string]interface{}
expected *api.Pod expected *v1.Pod
expectErr bool expectErr bool
}{ }{
{ {
@ -412,20 +415,20 @@ func TestGeneratePod(t *testing.T) {
"image": "someimage", "image": "someimage",
"port": "", "port": "",
}, },
expected: &api.Pod{ expected: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent, ImagePullPolicy: v1.PullIfNotPresent,
}, },
}, },
DNSPolicy: api.DNSClusterFirst, DNSPolicy: v1.DNSClusterFirst,
RestartPolicy: api.RestartPolicyAlways, RestartPolicy: v1.RestartPolicyAlways,
}, },
}, },
}, },
@ -446,17 +449,17 @@ func TestGeneratePod(t *testing.T) {
"image-pull-policy": "Always", "image-pull-policy": "Always",
"env": []string{"a=b", "c=d"}, "env": []string{"a=b", "c=d"},
}, },
expected: &api.Pod{ expected: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
ImagePullPolicy: api.PullAlways, ImagePullPolicy: v1.PullAlways,
Env: []api.EnvVar{ Env: []v1.EnvVar{
{ {
Name: "a", Name: "a",
Value: "b", Value: "b",
@ -468,8 +471,8 @@ func TestGeneratePod(t *testing.T) {
}, },
}, },
}, },
DNSPolicy: api.DNSClusterFirst, DNSPolicy: v1.DNSClusterFirst,
RestartPolicy: api.RestartPolicyAlways, RestartPolicy: v1.RestartPolicyAlways,
}, },
}, },
}, },
@ -479,25 +482,25 @@ func TestGeneratePod(t *testing.T) {
"image": "someimage", "image": "someimage",
"port": "80", "port": "80",
}, },
expected: &api.Pod{ expected: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent, ImagePullPolicy: v1.PullIfNotPresent,
Ports: []api.ContainerPort{ Ports: []v1.ContainerPort{
{ {
ContainerPort: 80, ContainerPort: 80,
}, },
}, },
}, },
}, },
DNSPolicy: api.DNSClusterFirst, DNSPolicy: v1.DNSClusterFirst,
RestartPolicy: api.RestartPolicyAlways, RestartPolicy: v1.RestartPolicyAlways,
}, },
}, },
}, },
@ -508,17 +511,17 @@ func TestGeneratePod(t *testing.T) {
"port": "80", "port": "80",
"hostport": "80", "hostport": "80",
}, },
expected: &api.Pod{ expected: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent, ImagePullPolicy: v1.PullIfNotPresent,
Ports: []api.ContainerPort{ Ports: []v1.ContainerPort{
{ {
ContainerPort: 80, ContainerPort: 80,
HostPort: 80, HostPort: 80,
@ -526,8 +529,8 @@ func TestGeneratePod(t *testing.T) {
}, },
}, },
}, },
DNSPolicy: api.DNSClusterFirst, DNSPolicy: v1.DNSClusterFirst,
RestartPolicy: api.RestartPolicyAlways, RestartPolicy: v1.RestartPolicyAlways,
}, },
}, },
}, },
@ -547,21 +550,21 @@ func TestGeneratePod(t *testing.T) {
"replicas": "1", "replicas": "1",
"labels": "foo=bar,baz=blah", "labels": "foo=bar,baz=blah",
}, },
expected: &api.Pod{ expected: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"foo": "bar", "baz": "blah"}, Labels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent, ImagePullPolicy: v1.PullIfNotPresent,
}, },
}, },
DNSPolicy: api.DNSClusterFirst, DNSPolicy: v1.DNSClusterFirst,
RestartPolicy: api.RestartPolicyAlways, RestartPolicy: v1.RestartPolicyAlways,
}, },
}, },
}, },
@ -573,23 +576,23 @@ func TestGeneratePod(t *testing.T) {
"labels": "foo=bar,baz=blah", "labels": "foo=bar,baz=blah",
"stdin": "true", "stdin": "true",
}, },
expected: &api.Pod{ expected: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"foo": "bar", "baz": "blah"}, Labels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent, ImagePullPolicy: v1.PullIfNotPresent,
Stdin: true, Stdin: true,
StdinOnce: true, StdinOnce: true,
}, },
}, },
DNSPolicy: api.DNSClusterFirst, DNSPolicy: v1.DNSClusterFirst,
RestartPolicy: api.RestartPolicyAlways, RestartPolicy: v1.RestartPolicyAlways,
}, },
}, },
}, },
@ -602,23 +605,23 @@ func TestGeneratePod(t *testing.T) {
"stdin": "true", "stdin": "true",
"leave-stdin-open": "true", "leave-stdin-open": "true",
}, },
expected: &api.Pod{ expected: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"foo": "bar", "baz": "blah"}, Labels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent, ImagePullPolicy: v1.PullIfNotPresent,
Stdin: true, Stdin: true,
StdinOnce: false, StdinOnce: false,
}, },
}, },
DNSPolicy: api.DNSClusterFirst, DNSPolicy: v1.DNSClusterFirst,
RestartPolicy: api.RestartPolicyAlways, RestartPolicy: v1.RestartPolicyAlways,
}, },
}, },
}, },
@ -632,16 +635,17 @@ func TestGeneratePod(t *testing.T) {
if test.expectErr && err != nil { if test.expectErr && err != nil {
continue continue
} }
if !reflect.DeepEqual(obj.(*api.Pod), test.expected) { if !reflect.DeepEqual(obj.(*v1.Pod), test.expected) {
t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*api.Pod)) t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*v1.Pod))
} }
} }
} }
func TestGenerateDeployment(t *testing.T) { func TestGenerateDeployment(t *testing.T) {
three := int32(3)
tests := []struct { tests := []struct {
params map[string]interface{} params map[string]interface{}
expected *extensions.Deployment expected *extensionsv1beta1.Deployment
expectErr bool expectErr bool
}{ }{
{ {
@ -660,33 +664,33 @@ func TestGenerateDeployment(t *testing.T) {
"requests": "cpu=100m,memory=100Mi", "requests": "cpu=100m,memory=100Mi",
"limits": "cpu=400m,memory=200Mi", "limits": "cpu=400m,memory=200Mi",
}, },
expected: &extensions.Deployment{ expected: &extensionsv1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"foo": "bar", "baz": "blah"}, Labels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
Spec: extensions.DeploymentSpec{ Spec: extensionsv1beta1.DeploymentSpec{
Replicas: 3, Replicas: &three,
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar", "baz": "blah"}}, Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar", "baz": "blah"}},
Template: api.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"foo": "bar", "baz": "blah"}, Labels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
ImagePullPolicy: api.PullAlways, ImagePullPolicy: v1.PullAlways,
Stdin: true, Stdin: true,
Ports: []api.ContainerPort{ Ports: []v1.ContainerPort{
{ {
ContainerPort: 80, ContainerPort: 80,
HostPort: 80, HostPort: 80,
}, },
}, },
Command: []string{"bar", "baz", "blah"}, Command: []string{"bar", "baz", "blah"},
Env: []api.EnvVar{ Env: []v1.EnvVar{
{ {
Name: "a", Name: "a",
Value: "b", Value: "b",
@ -696,14 +700,14 @@ func TestGenerateDeployment(t *testing.T) {
Value: "d", Value: "d",
}, },
}, },
Resources: api.ResourceRequirements{ Resources: v1.ResourceRequirements{
Requests: api.ResourceList{ Requests: v1.ResourceList{
api.ResourceCPU: resource.MustParse("100m"), v1.ResourceCPU: resource.MustParse("100m"),
api.ResourceMemory: resource.MustParse("100Mi"), v1.ResourceMemory: resource.MustParse("100Mi"),
}, },
Limits: api.ResourceList{ Limits: v1.ResourceList{
api.ResourceCPU: resource.MustParse("400m"), v1.ResourceCPU: resource.MustParse("400m"),
api.ResourceMemory: resource.MustParse("200Mi"), v1.ResourceMemory: resource.MustParse("200Mi"),
}, },
}, },
}, },
@ -724,8 +728,101 @@ func TestGenerateDeployment(t *testing.T) {
if test.expectErr && err != nil { if test.expectErr && err != nil {
continue continue
} }
if !reflect.DeepEqual(obj.(*extensions.Deployment), test.expected) { if !reflect.DeepEqual(obj.(*extensionsv1beta1.Deployment), test.expected) {
t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*extensions.Deployment)) t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*extensionsv1beta1.Deployment))
}
}
}
func TestGenerateAppsDeployment(t *testing.T) {
three := int32(3)
tests := []struct {
params map[string]interface{}
expected *appsv1beta1.Deployment
expectErr bool
}{
{
params: map[string]interface{}{
"labels": "foo=bar,baz=blah",
"name": "foo",
"replicas": "3",
"image": "someimage",
"image-pull-policy": "Always",
"port": "80",
"hostport": "80",
"stdin": "true",
"command": "true",
"args": []string{"bar", "baz", "blah"},
"env": []string{"a=b", "c=d"},
"requests": "cpu=100m,memory=100Mi",
"limits": "cpu=400m,memory=200Mi",
},
expected: &appsv1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Labels: map[string]string{"foo": "bar", "baz": "blah"},
},
Spec: appsv1beta1.DeploymentSpec{
Replicas: &three,
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar", "baz": "blah"}},
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"foo": "bar", "baz": "blah"},
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: "foo",
Image: "someimage",
ImagePullPolicy: v1.PullAlways,
Stdin: true,
Ports: []v1.ContainerPort{
{
ContainerPort: 80,
HostPort: 80,
},
},
Command: []string{"bar", "baz", "blah"},
Env: []v1.EnvVar{
{
Name: "a",
Value: "b",
},
{
Name: "c",
Value: "d",
},
},
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceCPU: resource.MustParse("100m"),
v1.ResourceMemory: resource.MustParse("100Mi"),
},
Limits: v1.ResourceList{
v1.ResourceCPU: resource.MustParse("400m"),
v1.ResourceMemory: resource.MustParse("200Mi"),
},
},
},
},
},
},
},
},
},
}
generator := DeploymentAppsV1Beta1{}
for _, test := range tests {
obj, err := generator.Generate(test.params)
if !test.expectErr && err != nil {
t.Errorf("unexpected error: %v", err)
}
if test.expectErr && err != nil {
continue
}
if !reflect.DeepEqual(obj.(*appsv1beta1.Deployment), test.expected) {
t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*appsv1beta1.Deployment))
} }
} }
} }
@ -733,7 +830,7 @@ func TestGenerateDeployment(t *testing.T) {
func TestGenerateJob(t *testing.T) { func TestGenerateJob(t *testing.T) {
tests := []struct { tests := []struct {
params map[string]interface{} params map[string]interface{}
expected *batch.Job expected *batchv1.Job
expectErr bool expectErr bool
}{ }{
{ {
@ -752,32 +849,32 @@ func TestGenerateJob(t *testing.T) {
"limits": "cpu=400m,memory=200Mi", "limits": "cpu=400m,memory=200Mi",
"restart": "OnFailure", "restart": "OnFailure",
}, },
expected: &batch.Job{ expected: &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"foo": "bar", "baz": "blah"}, Labels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
Spec: batch.JobSpec{ Spec: batchv1.JobSpec{
Template: api.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"foo": "bar", "baz": "blah"}, Labels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
RestartPolicy: api.RestartPolicyOnFailure, RestartPolicy: v1.RestartPolicyOnFailure,
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
Stdin: true, Stdin: true,
StdinOnce: false, StdinOnce: false,
Ports: []api.ContainerPort{ Ports: []v1.ContainerPort{
{ {
ContainerPort: 80, ContainerPort: 80,
HostPort: 80, HostPort: 80,
}, },
}, },
Command: []string{"bar", "baz", "blah"}, Command: []string{"bar", "baz", "blah"},
Env: []api.EnvVar{ Env: []v1.EnvVar{
{ {
Name: "a", Name: "a",
Value: "b", Value: "b",
@ -787,14 +884,14 @@ func TestGenerateJob(t *testing.T) {
Value: "d", Value: "d",
}, },
}, },
Resources: api.ResourceRequirements{ Resources: v1.ResourceRequirements{
Requests: api.ResourceList{ Requests: v1.ResourceList{
api.ResourceCPU: resource.MustParse("100m"), v1.ResourceCPU: resource.MustParse("100m"),
api.ResourceMemory: resource.MustParse("100Mi"), v1.ResourceMemory: resource.MustParse("100Mi"),
}, },
Limits: api.ResourceList{ Limits: v1.ResourceList{
api.ResourceCPU: resource.MustParse("400m"), v1.ResourceCPU: resource.MustParse("400m"),
api.ResourceMemory: resource.MustParse("200Mi"), v1.ResourceMemory: resource.MustParse("200Mi"),
}, },
}, },
}, },
@ -815,8 +912,8 @@ func TestGenerateJob(t *testing.T) {
if test.expectErr && err != nil { if test.expectErr && err != nil {
continue continue
} }
if !reflect.DeepEqual(obj.(*batch.Job), test.expected) { if !reflect.DeepEqual(obj.(*batchv1.Job), test.expected) {
t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*batch.Job)) t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*batchv1.Job))
} }
} }
} }
@ -824,7 +921,7 @@ func TestGenerateJob(t *testing.T) {
func TestGenerateCronJob(t *testing.T) { func TestGenerateCronJob(t *testing.T) {
tests := []struct { tests := []struct {
params map[string]interface{} params map[string]interface{}
expected *batch.CronJob expected *batchv2alpha1.CronJob
expectErr bool expectErr bool
}{ }{
{ {
@ -844,36 +941,36 @@ func TestGenerateCronJob(t *testing.T) {
"restart": "OnFailure", "restart": "OnFailure",
"schedule": "0/5 * * * ?", "schedule": "0/5 * * * ?",
}, },
expected: &batch.CronJob{ expected: &batchv2alpha1.CronJob{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"foo": "bar", "baz": "blah"}, Labels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
Spec: batch.CronJobSpec{ Spec: batchv2alpha1.CronJobSpec{
Schedule: "0/5 * * * ?", Schedule: "0/5 * * * ?",
ConcurrencyPolicy: batch.AllowConcurrent, ConcurrencyPolicy: batchv2alpha1.AllowConcurrent,
JobTemplate: batch.JobTemplateSpec{ JobTemplate: batchv2alpha1.JobTemplateSpec{
Spec: batch.JobSpec{ Spec: batchv1.JobSpec{
Template: api.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"foo": "bar", "baz": "blah"}, Labels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
Spec: api.PodSpec{ Spec: v1.PodSpec{
RestartPolicy: api.RestartPolicyOnFailure, RestartPolicy: v1.RestartPolicyOnFailure,
Containers: []api.Container{ Containers: []v1.Container{
{ {
Name: "foo", Name: "foo",
Image: "someimage", Image: "someimage",
Stdin: true, Stdin: true,
StdinOnce: false, StdinOnce: false,
Ports: []api.ContainerPort{ Ports: []v1.ContainerPort{
{ {
ContainerPort: 80, ContainerPort: 80,
HostPort: 80, HostPort: 80,
}, },
}, },
Command: []string{"bar", "baz", "blah"}, Command: []string{"bar", "baz", "blah"},
Env: []api.EnvVar{ Env: []v1.EnvVar{
{ {
Name: "a", Name: "a",
Value: "b", Value: "b",
@ -883,14 +980,14 @@ func TestGenerateCronJob(t *testing.T) {
Value: "d", Value: "d",
}, },
}, },
Resources: api.ResourceRequirements{ Resources: v1.ResourceRequirements{
Requests: api.ResourceList{ Requests: v1.ResourceList{
api.ResourceCPU: resource.MustParse("100m"), v1.ResourceCPU: resource.MustParse("100m"),
api.ResourceMemory: resource.MustParse("100Mi"), v1.ResourceMemory: resource.MustParse("100Mi"),
}, },
Limits: api.ResourceList{ Limits: v1.ResourceList{
api.ResourceCPU: resource.MustParse("400m"), v1.ResourceCPU: resource.MustParse("400m"),
api.ResourceMemory: resource.MustParse("200Mi"), v1.ResourceMemory: resource.MustParse("200Mi"),
}, },
}, },
}, },
@ -913,8 +1010,8 @@ func TestGenerateCronJob(t *testing.T) {
if test.expectErr && err != nil { if test.expectErr && err != nil {
continue continue
} }
if !reflect.DeepEqual(obj.(*batch.CronJob), test.expected) { if !reflect.DeepEqual(obj.(*batchv2alpha1.CronJob), test.expected) {
t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*batch.CronJob)) t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*batchv2alpha1.CronJob))
} }
} }
} }
@ -922,7 +1019,7 @@ func TestGenerateCronJob(t *testing.T) {
func TestParseEnv(t *testing.T) { func TestParseEnv(t *testing.T) {
tests := []struct { tests := []struct {
envArray []string envArray []string
expected []api.EnvVar expected []v1.EnvVar
expectErr bool expectErr bool
test string test string
}{ }{
@ -932,7 +1029,7 @@ func TestParseEnv(t *testing.T) {
"HAS_COMMAS=foo,bar", "HAS_COMMAS=foo,bar",
"HAS_EQUALS=jJnro54iUu75xNy==", "HAS_EQUALS=jJnro54iUu75xNy==",
}, },
expected: []api.EnvVar{ expected: []v1.EnvVar{
{ {
Name: "THIS_ENV", Name: "THIS_ENV",
Value: "isOK", Value: "isOK",
@ -953,7 +1050,7 @@ func TestParseEnv(t *testing.T) {
envArray: []string{ envArray: []string{
"WITH_OUT_EQUALS", "WITH_OUT_EQUALS",
}, },
expected: []api.EnvVar{}, expected: []v1.EnvVar{},
expectErr: true, expectErr: true,
test: "test case 2", test: "test case 2",
}, },
@ -961,7 +1058,7 @@ func TestParseEnv(t *testing.T) {
envArray: []string{ envArray: []string{
"WITH_OUT_VALUES=", "WITH_OUT_VALUES=",
}, },
expected: []api.EnvVar{ expected: []v1.EnvVar{
{ {
Name: "WITH_OUT_VALUES", Name: "WITH_OUT_VALUES",
Value: "", Value: "",
@ -974,7 +1071,7 @@ func TestParseEnv(t *testing.T) {
envArray: []string{ envArray: []string{
"=WITH_OUT_NAME", "=WITH_OUT_NAME",
}, },
expected: []api.EnvVar{}, expected: []v1.EnvVar{},
expectErr: true, expectErr: true,
test: "test case 4", test: "test case 4",
}, },