Introduce new generator for apps/v1beta1 deployments
This commit is contained in:
parent
1049dad0a4
commit
aa4390750c
@ -1046,11 +1046,23 @@ run_kubectl_run_tests() {
|
||||
# Pre-Condition: no Deployment exists
|
||||
kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" ''
|
||||
# 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
|
||||
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
|
||||
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() {
|
||||
@ -2283,17 +2295,35 @@ run_rc_tests() {
|
||||
}
|
||||
|
||||
run_deployment_tests() {
|
||||
# Test kubectl create deployment
|
||||
kubectl create deployment test-nginx --image=gcr.io/google-containers/nginx:test-cmd
|
||||
# Post-Condition: Deployment has 2 replicas defined in its spec.
|
||||
kube::test::get_object_assert 'deploy test-nginx' "{{$container_name_field}}" 'nginx'
|
||||
# Test kubectl create deployment (using default - old generator)
|
||||
kubectl create deployment test-nginx-extensions --image=gcr.io/google-containers/nginx:test-cmd
|
||||
# Post-Condition: Deployment "nginx" is created.
|
||||
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
|
||||
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 "${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 that rs is deleted when deployment is deleted.
|
||||
|
@ -53,6 +53,7 @@ go_library(
|
||||
"//pkg/api/util:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/apps:go_default_library",
|
||||
"//pkg/apis/apps/v1beta1:go_default_library",
|
||||
"//pkg/apis/autoscaling:go_default_library",
|
||||
"//pkg/apis/batch:go_default_library",
|
||||
"//pkg/apis/batch/v1:go_default_library",
|
||||
@ -137,6 +138,7 @@ go_test(
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/api/testing: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/v1:go_default_library",
|
||||
"//pkg/apis/batch/v2alpha1:go_default_library",
|
||||
|
@ -70,6 +70,7 @@ go_library(
|
||||
"//pkg/api/annotations:go_default_library",
|
||||
"//pkg/api/v1: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/certificates:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
|
@ -94,7 +94,7 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
cmd.AddCommand(NewCmdCreateConfigMap(f, out))
|
||||
cmd.AddCommand(NewCmdCreateServiceAccount(f, out))
|
||||
cmd.AddCommand(NewCmdCreateService(f, out, errOut))
|
||||
cmd.AddCommand(NewCmdCreateDeployment(f, out))
|
||||
cmd.AddCommand(NewCmdCreateDeployment(f, out, errOut))
|
||||
cmd.AddCommand(NewCmdCreateClusterRole(f, out))
|
||||
cmd.AddCommand(NewCmdCreateClusterRoleBinding(f, out))
|
||||
cmd.AddCommand(NewCmdCreateRole(f, out))
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
@ -38,7 +39,7 @@ var (
|
||||
)
|
||||
|
||||
// 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{
|
||||
Use: "deployment NAME --image=image [--dry-run]",
|
||||
Aliases: []string{"deploy"},
|
||||
@ -46,7 +47,7 @@ func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command
|
||||
Long: deploymentLong,
|
||||
Example: deploymentExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := CreateDeployment(f, cmdOut, cmd, args)
|
||||
err := CreateDeployment(f, cmdOut, cmdErr, cmd, args)
|
||||
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
|
||||
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)
|
||||
if err != nil {
|
||||
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
|
||||
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:
|
||||
generator = &kubectl.DeploymentBasicGeneratorV1{Name: name, Images: cmdutil.GetFlagStringSlice(cmd, "image")}
|
||||
default:
|
||||
|
@ -18,20 +18,37 @@ package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestCreateDeployment(t *testing.T) {
|
||||
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.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateDeployment(f, buf)
|
||||
|
||||
cmd := NewCmdCreateDeployment(f, buf, buf)
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
cmd.Flags().Set("output", "name")
|
||||
cmd.Flags().Set("image", "hollywood/jonny.depp:v2")
|
||||
@ -44,13 +61,25 @@ func TestCreateDeployment(t *testing.T) {
|
||||
|
||||
func TestCreateDeploymentNoImage(t *testing.T) {
|
||||
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.Namespace = "test"
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdCreateDeployment(f, buf)
|
||||
cmd := NewCmdCreateDeployment(f, buf, buf)
|
||||
cmd.Flags().Set("dry-run", "true")
|
||||
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")
|
||||
}
|
||||
|
@ -33,8 +33,9 @@ import (
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
|
||||
batchv1 "k8s.io/kubernetes/pkg/apis/batch/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||
conditions "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
@ -196,38 +197,50 @@ func Run(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobr
|
||||
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")
|
||||
schedule := cmdutil.GetFlagString(cmd, "schedule")
|
||||
if len(schedule) != 0 && len(generatorName) == 0 {
|
||||
generatorName = "cronjob/v2alpha1"
|
||||
generatorName = cmdutil.CronJobV2Alpha1GeneratorName
|
||||
}
|
||||
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 {
|
||||
case api.RestartPolicyAlways:
|
||||
if contains(resourcesList, v1beta1.SchemeGroupVersion.WithResource("deployments")) {
|
||||
generatorName = "deployment/v1beta1"
|
||||
// TODO: we need to deprecate this along with extensions/v1beta1.Deployments
|
||||
// in favor of the new generator for apps/v1beta1.Deployments
|
||||
if contains(resourcesList, extensionsv1beta1.SchemeGroupVersion.WithResource("deployments")) {
|
||||
generatorName = cmdutil.DeploymentV1Beta1GeneratorName
|
||||
} else {
|
||||
generatorName = "run/v1"
|
||||
generatorName = cmdutil.RunV1GeneratorName
|
||||
}
|
||||
case api.RestartPolicyOnFailure:
|
||||
if contains(resourcesList, batchv1.SchemeGroupVersion.WithResource("jobs")) {
|
||||
generatorName = "job/v1"
|
||||
generatorName = cmdutil.JobV1GeneratorName
|
||||
} else {
|
||||
generatorName = "run-pod/v1"
|
||||
generatorName = cmdutil.RunPodV1GeneratorName
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
generators := f.Generators("run")
|
||||
generator, found := generators[generatorName]
|
||||
if !found {
|
||||
|
@ -35,6 +35,7 @@ import (
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
)
|
||||
@ -113,7 +114,13 @@ func TestGetEnv(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 {
|
||||
args []string
|
||||
@ -158,7 +165,14 @@ func TestRunArgsFollowDashRules(t *testing.T) {
|
||||
APIRegistry: api.Registry,
|
||||
NegotiatedSerializer: ns,
|
||||
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"
|
||||
|
@ -456,31 +456,33 @@ func (f *ring0Factory) DefaultNamespace() (string, bool, error) {
|
||||
}
|
||||
|
||||
const (
|
||||
RunV1GeneratorName = "run/v1"
|
||||
RunPodV1GeneratorName = "run-pod/v1"
|
||||
ServiceV1GeneratorName = "service/v1"
|
||||
ServiceV2GeneratorName = "service/v2"
|
||||
ServiceNodePortGeneratorV1Name = "service-nodeport/v1"
|
||||
ServiceClusterIPGeneratorV1Name = "service-clusterip/v1"
|
||||
ServiceLoadBalancerGeneratorV1Name = "service-loadbalancer/v1"
|
||||
ServiceExternalNameGeneratorV1Name = "service-externalname/v1"
|
||||
ServiceAccountV1GeneratorName = "serviceaccount/v1"
|
||||
HorizontalPodAutoscalerV1GeneratorName = "horizontalpodautoscaler/v1"
|
||||
DeploymentV1Beta1GeneratorName = "deployment/v1beta1"
|
||||
DeploymentBasicV1Beta1GeneratorName = "deployment-basic/v1beta1"
|
||||
JobV1GeneratorName = "job/v1"
|
||||
CronJobV2Alpha1GeneratorName = "cronjob/v2alpha1"
|
||||
ScheduledJobV2Alpha1GeneratorName = "scheduledjob/v2alpha1"
|
||||
NamespaceV1GeneratorName = "namespace/v1"
|
||||
ResourceQuotaV1GeneratorName = "resourcequotas/v1"
|
||||
SecretV1GeneratorName = "secret/v1"
|
||||
SecretForDockerRegistryV1GeneratorName = "secret-for-docker-registry/v1"
|
||||
SecretForTLSV1GeneratorName = "secret-for-tls/v1"
|
||||
ConfigMapV1GeneratorName = "configmap/v1"
|
||||
ClusterRoleBindingV1GeneratorName = "clusterrolebinding.rbac.authorization.k8s.io/v1alpha1"
|
||||
RoleBindingV1GeneratorName = "rolebinding.rbac.authorization.k8s.io/v1alpha1"
|
||||
ClusterV1Beta1GeneratorName = "cluster/v1beta1"
|
||||
PodDisruptionBudgetV1GeneratorName = "poddisruptionbudget/v1beta1"
|
||||
RunV1GeneratorName = "run/v1"
|
||||
RunPodV1GeneratorName = "run-pod/v1"
|
||||
ServiceV1GeneratorName = "service/v1"
|
||||
ServiceV2GeneratorName = "service/v2"
|
||||
ServiceNodePortGeneratorV1Name = "service-nodeport/v1"
|
||||
ServiceClusterIPGeneratorV1Name = "service-clusterip/v1"
|
||||
ServiceLoadBalancerGeneratorV1Name = "service-loadbalancer/v1"
|
||||
ServiceExternalNameGeneratorV1Name = "service-externalname/v1"
|
||||
ServiceAccountV1GeneratorName = "serviceaccount/v1"
|
||||
HorizontalPodAutoscalerV1GeneratorName = "horizontalpodautoscaler/v1"
|
||||
DeploymentV1Beta1GeneratorName = "deployment/v1beta1"
|
||||
DeploymentAppsV1Beta1GeneratorName = "deployment/apps.v1beta1"
|
||||
DeploymentBasicV1Beta1GeneratorName = "deployment-basic/v1beta1"
|
||||
DeploymentBasicAppsV1Beta1GeneratorName = "deployment-basic/apps.v1beta1"
|
||||
JobV1GeneratorName = "job/v1"
|
||||
CronJobV2Alpha1GeneratorName = "cronjob/v2alpha1"
|
||||
ScheduledJobV2Alpha1GeneratorName = "scheduledjob/v2alpha1"
|
||||
NamespaceV1GeneratorName = "namespace/v1"
|
||||
ResourceQuotaV1GeneratorName = "resourcequotas/v1"
|
||||
SecretV1GeneratorName = "secret/v1"
|
||||
SecretForDockerRegistryV1GeneratorName = "secret-for-docker-registry/v1"
|
||||
SecretForTLSV1GeneratorName = "secret-for-tls/v1"
|
||||
ConfigMapV1GeneratorName = "configmap/v1"
|
||||
ClusterRoleBindingV1GeneratorName = "clusterrolebinding.rbac.authorization.k8s.io/v1alpha1"
|
||||
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
|
||||
@ -506,16 +508,18 @@ func DefaultGenerators(cmdName string) map[string]kubectl.Generator {
|
||||
}
|
||||
case "deployment":
|
||||
generator = map[string]kubectl.Generator{
|
||||
DeploymentBasicV1Beta1GeneratorName: kubectl.DeploymentBasicGeneratorV1{},
|
||||
DeploymentBasicV1Beta1GeneratorName: kubectl.DeploymentBasicGeneratorV1{},
|
||||
DeploymentBasicAppsV1Beta1GeneratorName: kubectl.DeploymentBasicAppsGeneratorV1{},
|
||||
}
|
||||
case "run":
|
||||
generator = map[string]kubectl.Generator{
|
||||
RunV1GeneratorName: kubectl.BasicReplicationController{},
|
||||
RunPodV1GeneratorName: kubectl.BasicPod{},
|
||||
DeploymentV1Beta1GeneratorName: kubectl.DeploymentV1Beta1{},
|
||||
JobV1GeneratorName: kubectl.JobV1{},
|
||||
ScheduledJobV2Alpha1GeneratorName: kubectl.CronJobV2Alpha1{},
|
||||
CronJobV2Alpha1GeneratorName: kubectl.CronJobV2Alpha1{},
|
||||
RunV1GeneratorName: kubectl.BasicReplicationController{},
|
||||
RunPodV1GeneratorName: kubectl.BasicPod{},
|
||||
DeploymentV1Beta1GeneratorName: kubectl.DeploymentV1Beta1{},
|
||||
DeploymentAppsV1Beta1GeneratorName: kubectl.DeploymentAppsV1Beta1{},
|
||||
JobV1GeneratorName: kubectl.JobV1{},
|
||||
ScheduledJobV2Alpha1GeneratorName: kubectl.CronJobV2Alpha1{},
|
||||
CronJobV2Alpha1GeneratorName: kubectl.CronJobV2Alpha1{},
|
||||
}
|
||||
case "autoscale":
|
||||
generator = map[string]kubectl.Generator{
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
|
||||
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
)
|
||||
|
||||
@ -113,3 +114,91 @@ func (s *DeploymentBasicGeneratorV1) validate() error {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
|
||||
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
)
|
||||
|
||||
@ -134,3 +135,113 @@ func TestDeploymentGenerate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
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"
|
||||
@ -121,6 +122,94 @@ func (DeploymentV1Beta1) Generate(genericParams map[string]interface{}) (runtime
|
||||
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) {
|
||||
labelString, found := params["labels"]
|
||||
var labels map[string]string
|
||||
@ -138,6 +227,7 @@ func getLabels(params map[string]string, defaultRunLabel bool, name string) (map
|
||||
return labels, nil
|
||||
}
|
||||
|
||||
// getName returns the name of newly created resource.
|
||||
func getName(params map[string]string) (string, error) {
|
||||
name, found := params["name"]
|
||||
if !found || len(name) == 0 {
|
||||
@ -149,6 +239,7 @@ func getName(params map[string]string) (string, error) {
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// getParams returns map of generic parameters.
|
||||
func getParams(genericParams map[string]interface{}) (map[string]string, error) {
|
||||
params := map[string]string{}
|
||||
for key, value := range genericParams {
|
||||
@ -161,6 +252,7 @@ func getParams(genericParams map[string]interface{}) (map[string]string, error)
|
||||
return params, nil
|
||||
}
|
||||
|
||||
// getArgs returns arguments for the container command.
|
||||
func getArgs(genericParams map[string]interface{}) ([]string, error) {
|
||||
args := []string{}
|
||||
val, found := genericParams["args"]
|
||||
@ -175,6 +267,7 @@ func getArgs(genericParams map[string]interface{}) ([]string, error) {
|
||||
return args, nil
|
||||
}
|
||||
|
||||
// getEnvs returns environment variables.
|
||||
func getEnvs(genericParams map[string]interface{}) ([]v1.EnvVar, error) {
|
||||
var envs []v1.EnvVar
|
||||
envStrings, found := genericParams["env"]
|
||||
@ -409,6 +502,7 @@ func (BasicReplicationController) ParamNames() []GeneratorParam {
|
||||
}
|
||||
|
||||
// populateResourceList takes strings of form <resourceName1>=<value1>,<resourceName1>=<value2>
|
||||
// and returns ResourceList.
|
||||
func populateResourceList(spec string) (api.ResourceList, error) {
|
||||
// empty input gets a nil response to preserve generator test expected behaviors
|
||||
if spec == "" {
|
||||
@ -433,6 +527,7 @@ func populateResourceList(spec string) (api.ResourceList, error) {
|
||||
}
|
||||
|
||||
// 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 == "" {
|
||||
@ -457,6 +552,7 @@ func populateResourceListV1(spec string) (v1.ResourceList, error) {
|
||||
}
|
||||
|
||||
// HandleResourceRequirements parses the limits and requests parameters if specified
|
||||
// and returns ResourceRequirements.
|
||||
func HandleResourceRequirements(params map[string]string) (api.ResourceRequirements, error) {
|
||||
result := api.ResourceRequirements{}
|
||||
limits, err := populateResourceList(params["limits"])
|
||||
@ -473,6 +569,7 @@ func HandleResourceRequirements(params map[string]string) (api.ResourceRequireme
|
||||
}
|
||||
|
||||
// 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"])
|
||||
@ -488,6 +585,7 @@ func HandleResourceRequirementsV1(params map[string]string) (v1.ResourceRequirem
|
||||
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)
|
||||
if err != nil {
|
||||
@ -583,6 +681,7 @@ func (BasicReplicationController) Generate(genericParams map[string]interface{})
|
||||
return &controller, nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
command, err := GetBool(params, "command", false)
|
||||
@ -607,6 +706,7 @@ func updatePodContainers(params map[string]string, args []string, envs []v1.EnvV
|
||||
return nil
|
||||
}
|
||||
|
||||
// updatePodContainers updates PodSpec.Containers.Ports with passed parameters.
|
||||
func updatePodPorts(params map[string]string, podSpec *v1.PodSpec) (err error) {
|
||||
port := -1
|
||||
hostPort := -1
|
||||
@ -747,6 +847,7 @@ func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object,
|
||||
return &pod, nil
|
||||
}
|
||||
|
||||
// parseEnvs converts string into EnvVar objects.
|
||||
func parseEnvs(envArray []string) ([]v1.EnvVar, error) {
|
||||
envs := make([]v1.EnvVar, 0, len(envArray))
|
||||
for _, env := range envArray {
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
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"
|
||||
@ -733,6 +734,99 @@ func TestGenerateDeployment(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateJob(t *testing.T) {
|
||||
tests := []struct {
|
||||
params map[string]interface{}
|
||||
|
Loading…
Reference in New Issue
Block a user