| ... | ... |
@@ -18,7 +18,6 @@ import ( |
| 18 | 18 |
"k8s.io/kubernetes/pkg/admission" |
| 19 | 19 |
kapi "k8s.io/kubernetes/pkg/api" |
| 20 | 20 |
"k8s.io/kubernetes/pkg/api/unversioned" |
| 21 |
- "k8s.io/kubernetes/pkg/apimachinery/registered" |
|
| 22 | 21 |
"k8s.io/kubernetes/pkg/apis/extensions" |
| 23 | 22 |
"k8s.io/kubernetes/pkg/apiserver" |
| 24 | 23 |
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" |
| ... | ... |
@@ -205,20 +204,20 @@ func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextM |
| 205 | 205 |
storageVersions[configapi.APIGroupKube] = options.EtcdStorageConfig.KubernetesStorageVersion |
| 206 | 206 |
} |
| 207 | 207 |
|
| 208 |
- // TODO: also need to enable this if batch or autoscaling is enabled and doesn't have a storage version set |
|
| 209 |
- enabledExtensionsVersions := configapi.GetEnabledAPIVersionsForGroup(*options.KubernetesMasterConfig, configapi.APIGroupExtensions) |
|
| 210 |
- if len(enabledExtensionsVersions) > 0 {
|
|
| 211 |
- groupMeta, err := registered.Group(configapi.APIGroupExtensions) |
|
| 212 |
- if err != nil {
|
|
| 213 |
- return nil, fmt.Errorf("Error setting up Kubernetes extensions server storage: %v", err)
|
|
| 214 |
- } |
|
| 215 |
- // TODO expose storage version options for api groups |
|
| 216 |
- databaseStorage, err := NewEtcdStorage(etcdClient, groupMeta.GroupVersion, options.EtcdStorageConfig.KubernetesStoragePrefix) |
|
| 208 |
+ // enable this if extensions API is enabled (or batch or autoscaling, since they persist to extensions/v1beta1 for now) |
|
| 209 |
+ // TODO: replace this with a loop over configured storage versions |
|
| 210 |
+ extensionsEnabled := len(configapi.GetEnabledAPIVersionsForGroup(*options.KubernetesMasterConfig, configapi.APIGroupExtensions)) > 0 |
|
| 211 |
+ batchEnabled := len(configapi.GetEnabledAPIVersionsForGroup(*options.KubernetesMasterConfig, configapi.APIGroupBatch)) > 0 |
|
| 212 |
+ autoscalingEnabled := len(configapi.GetEnabledAPIVersionsForGroup(*options.KubernetesMasterConfig, configapi.APIGroupAutoscaling)) > 0 |
|
| 213 |
+ if extensionsEnabled || autoscalingEnabled || batchEnabled {
|
|
| 214 |
+ // TODO: replace this with a configured storage version for extensions once configuration exposes this |
|
| 215 |
+ extensionsStorageVersion := unversioned.GroupVersion{Group: extensions.GroupName, Version: "v1beta1"}
|
|
| 216 |
+ databaseStorage, err := NewEtcdStorage(etcdClient, extensionsStorageVersion, options.EtcdStorageConfig.KubernetesStoragePrefix) |
|
| 217 | 217 |
if err != nil {
|
| 218 | 218 |
return nil, fmt.Errorf("Error setting up Kubernetes extensions server storage: %v", err)
|
| 219 | 219 |
} |
| 220 | 220 |
storageDestinations.AddAPIGroup(configapi.APIGroupExtensions, databaseStorage) |
| 221 |
- storageVersions[configapi.APIGroupExtensions] = unversioned.GroupVersion{Group: extensions.GroupName, Version: enabledExtensionsVersions[0]}.String()
|
|
| 221 |
+ storageVersions[configapi.APIGroupExtensions] = extensionsStorageVersion.String() |
|
| 222 | 222 |
} |
| 223 | 223 |
|
| 224 | 224 |
// Preserve previous behavior of using the first non-loopback address |
| ... | ... |
@@ -4,7 +4,6 @@ package integration |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 | 6 |
"testing" |
| 7 |
- "time" |
|
| 8 | 7 |
|
| 9 | 8 |
testutil "github.com/openshift/origin/test/util" |
| 10 | 9 |
testserver "github.com/openshift/origin/test/util/server" |
| ... | ... |
@@ -12,9 +11,130 @@ import ( |
| 12 | 12 |
kapi "k8s.io/kubernetes/pkg/api" |
| 13 | 13 |
"k8s.io/kubernetes/pkg/api/errors" |
| 14 | 14 |
expapi "k8s.io/kubernetes/pkg/apis/extensions" |
| 15 |
- "k8s.io/kubernetes/pkg/util/wait" |
|
| 16 | 15 |
) |
| 17 | 16 |
|
| 17 |
+func TestExtensionsAPIDisabledAutoscaleBatchEnabled(t *testing.T) {
|
|
| 18 |
+ const projName = "ext-disabled-batch-enabled-proj" |
|
| 19 |
+ |
|
| 20 |
+ testutil.RequireEtcd(t) |
|
| 21 |
+ masterConfig, err := testserver.DefaultMasterOptions() |
|
| 22 |
+ if err != nil {
|
|
| 23 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 24 |
+ } |
|
| 25 |
+ |
|
| 26 |
+ // Disable all extensions API versions |
|
| 27 |
+ // Leave autoscaling/batch APIs enabled |
|
| 28 |
+ masterConfig.KubernetesMasterConfig.DisabledAPIGroupVersions = map[string][]string{"extensions": {"*"}}
|
|
| 29 |
+ |
|
| 30 |
+ clusterAdminKubeConfig, err := testserver.StartConfiguredMaster(masterConfig) |
|
| 31 |
+ if err != nil {
|
|
| 32 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 33 |
+ } |
|
| 34 |
+ |
|
| 35 |
+ clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) |
|
| 36 |
+ if err != nil {
|
|
| 37 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 38 |
+ } |
|
| 39 |
+ |
|
| 40 |
+ clusterAdminKubeClient, err := testutil.GetClusterAdminKubeClient(clusterAdminKubeConfig) |
|
| 41 |
+ if err != nil {
|
|
| 42 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 43 |
+ } |
|
| 44 |
+ |
|
| 45 |
+ clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) |
|
| 46 |
+ if err != nil {
|
|
| 47 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 48 |
+ } |
|
| 49 |
+ |
|
| 50 |
+ // create the containing project |
|
| 51 |
+ if _, err := testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, projName, "admin"); err != nil {
|
|
| 52 |
+ t.Fatalf("unexpected error creating the project: %v", err)
|
|
| 53 |
+ } |
|
| 54 |
+ projectAdminClient, projectAdminKubeClient, _, err := testutil.GetClientForUser(*clusterAdminClientConfig, "admin") |
|
| 55 |
+ if err != nil {
|
|
| 56 |
+ t.Fatalf("unexpected error getting project admin client: %v", err)
|
|
| 57 |
+ } |
|
| 58 |
+ if err := testutil.WaitForPolicyUpdate(projectAdminClient, projName, "get", expapi.Resource("horizontalpodautoscalers"), true); err != nil {
|
|
| 59 |
+ t.Fatalf("unexpected error waiting for policy update: %v", err)
|
|
| 60 |
+ } |
|
| 61 |
+ |
|
| 62 |
+ validHPA := &expapi.HorizontalPodAutoscaler{
|
|
| 63 |
+ ObjectMeta: kapi.ObjectMeta{Name: "myjob"},
|
|
| 64 |
+ Spec: expapi.HorizontalPodAutoscalerSpec{
|
|
| 65 |
+ ScaleRef: expapi.SubresourceReference{Name: "foo", Kind: "ReplicationController", Subresource: "scale"},
|
|
| 66 |
+ MaxReplicas: 1, |
|
| 67 |
+ }, |
|
| 68 |
+ } |
|
| 69 |
+ validJob := &expapi.Job{
|
|
| 70 |
+ ObjectMeta: kapi.ObjectMeta{Name: "myjob"},
|
|
| 71 |
+ Spec: expapi.JobSpec{
|
|
| 72 |
+ Template: kapi.PodTemplateSpec{
|
|
| 73 |
+ Spec: kapi.PodSpec{
|
|
| 74 |
+ Containers: []kapi.Container{{Name: "mycontainer", Image: "myimage"}},
|
|
| 75 |
+ RestartPolicy: kapi.RestartPolicyNever, |
|
| 76 |
+ }, |
|
| 77 |
+ }, |
|
| 78 |
+ }, |
|
| 79 |
+ } |
|
| 80 |
+ |
|
| 81 |
+ // make sure extensions API objects cannot be listed or created |
|
| 82 |
+ if _, err := projectAdminKubeClient.Extensions().HorizontalPodAutoscalers(projName).List(kapi.ListOptions{}); !errors.IsNotFound(err) {
|
|
| 83 |
+ t.Fatalf("expected NotFound error listing HPA, got %v", err)
|
|
| 84 |
+ } |
|
| 85 |
+ if _, err := projectAdminKubeClient.Extensions().HorizontalPodAutoscalers(projName).Create(validHPA); !errors.IsNotFound(err) {
|
|
| 86 |
+ t.Fatalf("expected NotFound error creating HPA, got %v", err)
|
|
| 87 |
+ } |
|
| 88 |
+ if _, err := projectAdminKubeClient.Extensions().Jobs(projName).List(kapi.ListOptions{}); !errors.IsNotFound(err) {
|
|
| 89 |
+ t.Fatalf("expected NotFound error listing jobs, got %v", err)
|
|
| 90 |
+ } |
|
| 91 |
+ if _, err := projectAdminKubeClient.Extensions().Jobs(projName).Create(validJob); !errors.IsNotFound(err) {
|
|
| 92 |
+ t.Fatalf("expected NotFound error creating job, got %v", err)
|
|
| 93 |
+ } |
|
| 94 |
+ |
|
| 95 |
+ // make sure autoscaling and batch API objects can be listed and created |
|
| 96 |
+ if _, err := projectAdminKubeClient.Autoscaling().HorizontalPodAutoscalers(projName).List(kapi.ListOptions{}); err != nil {
|
|
| 97 |
+ t.Fatalf("unexpected error: %#v", err)
|
|
| 98 |
+ } |
|
| 99 |
+ if _, err := projectAdminKubeClient.Autoscaling().HorizontalPodAutoscalers(projName).Create(validHPA); err != nil {
|
|
| 100 |
+ t.Fatalf("unexpected error: %#v", err)
|
|
| 101 |
+ } |
|
| 102 |
+ if _, err := projectAdminKubeClient.Batch().Jobs(projName).List(kapi.ListOptions{}); err != nil {
|
|
| 103 |
+ t.Fatalf("unexpected error: %#v", err)
|
|
| 104 |
+ } |
|
| 105 |
+ if _, err := projectAdminKubeClient.Batch().Jobs(projName).Create(validJob); err != nil {
|
|
| 106 |
+ t.Fatalf("unexpected error: %#v", err)
|
|
| 107 |
+ } |
|
| 108 |
+ |
|
| 109 |
+ // Delete the containing project |
|
| 110 |
+ if err := testutil.DeleteAndWaitForNamespaceTermination(clusterAdminKubeClient, projName); err != nil {
|
|
| 111 |
+ t.Fatalf("unexpected error: %#v", err)
|
|
| 112 |
+ } |
|
| 113 |
+ |
|
| 114 |
+ // recreate the containing project |
|
| 115 |
+ if _, err := testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, projName, "admin"); err != nil {
|
|
| 116 |
+ t.Fatalf("unexpected error creating the project: %v", err)
|
|
| 117 |
+ } |
|
| 118 |
+ projectAdminClient, projectAdminKubeClient, _, err = testutil.GetClientForUser(*clusterAdminClientConfig, "admin") |
|
| 119 |
+ if err != nil {
|
|
| 120 |
+ t.Fatalf("unexpected error getting project admin client: %v", err)
|
|
| 121 |
+ } |
|
| 122 |
+ if err := testutil.WaitForPolicyUpdate(projectAdminClient, projName, "get", expapi.Resource("horizontalpodautoscalers"), true); err != nil {
|
|
| 123 |
+ t.Fatalf("unexpected error waiting for policy update: %v", err)
|
|
| 124 |
+ } |
|
| 125 |
+ |
|
| 126 |
+ // make sure the created objects got cleaned up by namespace deletion |
|
| 127 |
+ if hpas, err := projectAdminKubeClient.Autoscaling().HorizontalPodAutoscalers(projName).List(kapi.ListOptions{}); err != nil {
|
|
| 128 |
+ t.Fatalf("unexpected error: %#v", err)
|
|
| 129 |
+ } else if len(hpas.Items) > 0 {
|
|
| 130 |
+ t.Fatalf("expected 0 HPA objects, got %#v", hpas.Items)
|
|
| 131 |
+ } |
|
| 132 |
+ if jobs, err := projectAdminKubeClient.Batch().Jobs(projName).List(kapi.ListOptions{}); err != nil {
|
|
| 133 |
+ t.Fatalf("unexpected error: %#v", err)
|
|
| 134 |
+ } else if len(jobs.Items) > 0 {
|
|
| 135 |
+ t.Fatalf("expected 0 Job objects, got %#v", jobs.Items)
|
|
| 136 |
+ } |
|
| 137 |
+} |
|
| 138 |
+ |
|
| 18 | 139 |
func TestExtensionsAPIDisabled(t *testing.T) {
|
| 19 | 140 |
const projName = "ext-disabled-proj" |
| 20 | 141 |
|
| ... | ... |
@@ -73,17 +193,8 @@ func TestExtensionsAPIDisabled(t *testing.T) {
|
| 73 | 73 |
t.Fatalf("expected NotFound error creating job, got %v", err)
|
| 74 | 74 |
} |
| 75 | 75 |
|
| 76 |
- if err := clusterAdminClient.Projects().Delete(projName); err != nil {
|
|
| 77 |
- t.Fatalf("unexpected error deleting the project: %v", err)
|
|
| 78 |
- } |
|
| 79 |
- err = wait.PollImmediate(1*time.Second, 30*time.Second, func() (bool, error) {
|
|
| 80 |
- _, err := clusterAdminKubeClient.Namespaces().Get(projName) |
|
| 81 |
- if errors.IsNotFound(err) {
|
|
| 82 |
- return true, nil |
|
| 83 |
- } |
|
| 84 |
- return false, err |
|
| 85 |
- }) |
|
| 86 |
- if err != nil {
|
|
| 87 |
- t.Fatalf("unexpected error while waiting for project to delete: %v", err)
|
|
| 76 |
+ // Delete the containing project |
|
| 77 |
+ if err := testutil.DeleteAndWaitForNamespaceTermination(clusterAdminKubeClient, projName); err != nil {
|
|
| 78 |
+ t.Fatalf("unexpected error: %#v", err)
|
|
| 88 | 79 |
} |
| 89 | 80 |
} |
| ... | ... |
@@ -4,8 +4,12 @@ import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"time" |
| 6 | 6 |
|
| 7 |
- "github.com/openshift/origin/pkg/cmd/util" |
|
| 8 | 7 |
kapi "k8s.io/kubernetes/pkg/api" |
| 8 |
+ kclient "k8s.io/kubernetes/pkg/client/unversioned" |
|
| 9 |
+ "k8s.io/kubernetes/pkg/watch" |
|
| 10 |
+ |
|
| 11 |
+ "github.com/openshift/origin/pkg/cmd/cli/cmd" |
|
| 12 |
+ "github.com/openshift/origin/pkg/cmd/util" |
|
| 9 | 13 |
) |
| 10 | 14 |
|
| 11 | 15 |
// Namespace returns the test namespace. The default namespace is set to |
| ... | ... |
@@ -33,3 +37,24 @@ func CreateNamespace(clusterAdminKubeConfig, name string) (err error) {
|
| 33 | 33 |
}) |
| 34 | 34 |
return err |
| 35 | 35 |
} |
| 36 |
+ |
|
| 37 |
+func DeleteAndWaitForNamespaceTermination(c *kclient.Client, name string) error {
|
|
| 38 |
+ w, err := c.Namespaces().Watch(kapi.ListOptions{})
|
|
| 39 |
+ if err != nil {
|
|
| 40 |
+ return err |
|
| 41 |
+ } |
|
| 42 |
+ if err := c.Namespaces().Delete(name); err != nil {
|
|
| 43 |
+ return err |
|
| 44 |
+ } |
|
| 45 |
+ _, err = cmd.Until(30*time.Second, w, func(event watch.Event) (bool, error) {
|
|
| 46 |
+ if event.Type != watch.Deleted {
|
|
| 47 |
+ return false, nil |
|
| 48 |
+ } |
|
| 49 |
+ namespace, ok := event.Object.(*kapi.Namespace) |
|
| 50 |
+ if !ok {
|
|
| 51 |
+ return false, nil |
|
| 52 |
+ } |
|
| 53 |
+ return namespace.Name == name, nil |
|
| 54 |
+ }) |
|
| 55 |
+ return err |
|
| 56 |
+} |