diff --git a/hack/make-rules/test-cmd-util.sh b/hack/make-rules/test-cmd-util.sh index db0ba9f3ea..8da6bd86a3 100755 --- a/hack/make-rules/test-cmd-util.sh +++ b/hack/make-rules/test-cmd-util.sh @@ -1390,7 +1390,7 @@ run_kubectl_get_tests() { kube::test::if_has_string "${output_message}" "/api/v1/namespaces/default/pods 200 OK" kube::test::if_has_string "${output_message}" "/api/v1/namespaces/default/replicationcontrollers 200 OK" kube::test::if_has_string "${output_message}" "/api/v1/namespaces/default/services 200 OK" - kube::test::if_has_string "${output_message}" "/apis/apps/v1beta1/namespaces/default/statefulsets 200 OK" + kube::test::if_has_string "${output_message}" "/apis/apps/v1/namespaces/default/statefulsets 200 OK" kube::test::if_has_string "${output_message}" "/apis/autoscaling/v1/namespaces/default/horizontalpodautoscalers 200" kube::test::if_has_string "${output_message}" "/apis/batch/v1/namespaces/default/jobs 200 OK" kube::test::if_has_string "${output_message}" "/apis/extensions/v1beta1/namespaces/default/deployments 200 OK" @@ -2749,7 +2749,7 @@ run_deployment_tests() { 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' + kube::test::if_has_string "${output_message}" 'apps/v1' # Clean up kubectl delete deployment test-nginx-extensions "${kube_flags[@]}" @@ -2764,7 +2764,7 @@ run_deployment_tests() { 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' + kube::test::if_has_string "${output_message}" 'apps/v1' # Describe command (resource only) should print detailed information kube::test::describe_resource_assert rs "Name:" "Pod Template:" "Labels:" "Selector:" "Controlled By" "Replicas:" "Pods Status:" "Volumes:" # Describe command (resource only) should print detailed information diff --git a/pkg/kubectl/BUILD b/pkg/kubectl/BUILD index ff86f12f78..f056446b34 100644 --- a/pkg/kubectl/BUILD +++ b/pkg/kubectl/BUILD @@ -171,6 +171,7 @@ go_library( "//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library", + "//vendor/k8s.io/client-go/kubernetes:go_default_library", "//vendor/k8s.io/client-go/kubernetes/typed/apps/v1beta1:go_default_library", "//vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library", diff --git a/pkg/kubectl/cmd/util/factory_object_mapping.go b/pkg/kubectl/cmd/util/factory_object_mapping.go index 3ebeaacee9..f1e3e1126a 100644 --- a/pkg/kubectl/cmd/util/factory_object_mapping.go +++ b/pkg/kubectl/cmd/util/factory_object_mapping.go @@ -314,21 +314,19 @@ func (f *ring1Factory) Reaper(mapping *meta.RESTMapping) (kubectl.Reaper, error) } func (f *ring1Factory) HistoryViewer(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) { - mappingVersion := mapping.GroupVersionKind.GroupVersion() - clientset, err := f.clientAccessFactory.ClientSetForVersion(&mappingVersion) + external, err := f.clientAccessFactory.KubernetesClientSet() if err != nil { return nil, err } - return kubectl.HistoryViewerFor(mapping.GroupVersionKind.GroupKind(), clientset) + return kubectl.HistoryViewerFor(mapping.GroupVersionKind.GroupKind(), external) } func (f *ring1Factory) Rollbacker(mapping *meta.RESTMapping) (kubectl.Rollbacker, error) { - mappingVersion := mapping.GroupVersionKind.GroupVersion() - clientset, err := f.clientAccessFactory.ClientSetForVersion(&mappingVersion) + external, err := f.clientAccessFactory.KubernetesClientSet() if err != nil { return nil, err } - return kubectl.RollbackerFor(mapping.GroupVersionKind.GroupKind(), clientset) + return kubectl.RollbackerFor(mapping.GroupVersionKind.GroupKind(), external) } func (f *ring1Factory) StatusViewer(mapping *meta.RESTMapping) (kubectl.StatusViewer, error) { diff --git a/pkg/kubectl/history.go b/pkg/kubectl/history.go index 848729dfdf..cfea625991 100644 --- a/pkg/kubectl/history.go +++ b/pkg/kubectl/history.go @@ -27,18 +27,18 @@ import ( extensionsv1beta1 "k8s.io/api/extensions/v1beta1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/json" "k8s.io/apimachinery/pkg/util/strategicpatch" + "k8s.io/client-go/kubernetes" clientappsv1beta1 "k8s.io/client-go/kubernetes/typed/apps/v1beta1" - clientextensionsv1beta1 "k8s.io/client-go/kubernetes/typed/extensions/v1beta1" + clientextv1beta1 "k8s.io/client-go/kubernetes/typed/extensions/v1beta1" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/legacyscheme" apiv1 "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/extensions" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util" sliceutil "k8s.io/kubernetes/pkg/kubectl/util/slice" printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" @@ -53,7 +53,7 @@ type HistoryViewer interface { ViewHistory(namespace, name string, revision int64) (string, error) } -func HistoryViewerFor(kind schema.GroupKind, c clientset.Interface) (HistoryViewer, error) { +func HistoryViewerFor(kind schema.GroupKind, c kubernetes.Interface) (HistoryViewer, error) { switch kind { case extensions.Kind("Deployment"), apps.Kind("Deployment"): return &DeploymentHistoryViewer{c}, nil @@ -66,13 +66,13 @@ func HistoryViewerFor(kind schema.GroupKind, c clientset.Interface) (HistoryView } type DeploymentHistoryViewer struct { - c clientset.Interface + c kubernetes.Interface } // ViewHistory returns a revision-to-replicaset map as the revision history of a deployment // TODO: this should be a describer func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision int64) (string, error) { - versionedExtensionsClient := versionedExtensionsClientV1beta1(h.c) + versionedExtensionsClient := h.c.ExtensionsV1beta1() deployment, err := versionedExtensionsClient.Deployments(namespace).Get(name, metav1.GetOptions{}) if err != nil { return "", fmt.Errorf("failed to retrieve deployment %s: %v", name, err) @@ -148,24 +148,21 @@ func printTemplate(template *v1.PodTemplateSpec) (string, error) { } type DaemonSetHistoryViewer struct { - c clientset.Interface + c kubernetes.Interface } // ViewHistory returns a revision-to-history map as the revision history of a deployment // TODO: this should be a describer func (h *DaemonSetHistoryViewer) ViewHistory(namespace, name string, revision int64) (string, error) { - versionedAppsClient := versionedAppsClientV1beta1(h.c) - versionedExtensionsClient := versionedExtensionsClientV1beta1(h.c) - versionedObj, allHistory, err := controlledHistories(versionedAppsClient, versionedExtensionsClient, namespace, name, "DaemonSet") + ds, history, err := daemonSetHistory(h.c.ExtensionsV1beta1(), h.c.AppsV1beta1(), namespace, name) if err != nil { - return "", fmt.Errorf("unable to find history controlled by DaemonSet %s: %v", name, err) + return "", err } historyInfo := make(map[int64]*appsv1beta1.ControllerRevision) - for _, history := range allHistory { + for _, history := range history { // TODO: for now we assume revisions don't overlap, we may need to handle it historyInfo[history.Revision] = history } - if len(historyInfo) == 0 { return "No rollout history found.", nil } @@ -176,13 +173,7 @@ func (h *DaemonSetHistoryViewer) ViewHistory(namespace, name string, revision in if !ok { return "", fmt.Errorf("unable to find the specified revision") } - - versionedDS, ok := versionedObj.(*extensionsv1beta1.DaemonSet) - if !ok { - return "", fmt.Errorf("unexpected non-DaemonSet object returned: %v", versionedDS) - } - - dsOfHistory, err := applyHistory(versionedDS, history) + dsOfHistory, err := applyDaemonSetHistory(ds, history) if err != nil { return "", fmt.Errorf("unable to parse history %s", history.Name) } @@ -212,93 +203,46 @@ func (h *DaemonSetHistoryViewer) ViewHistory(namespace, name string, revision in } type StatefulSetHistoryViewer struct { - c clientset.Interface -} - -func getOwner(revision apps.ControllerRevision) *metav1.OwnerReference { - ownerRefs := revision.GetOwnerReferences() - for i := range ownerRefs { - owner := &ownerRefs[i] - if owner.Controller != nil && *owner.Controller == true { - return owner - } - } - return nil + c kubernetes.Interface } // ViewHistory returns a list of the revision history of a statefulset // TODO: this should be a describer // TODO: needs to implement detailed revision view func (h *StatefulSetHistoryViewer) ViewHistory(namespace, name string, revision int64) (string, error) { + _, history, err := statefulSetHistory(h.c.AppsV1beta1(), namespace, name) + if err != nil { + return "", err + } - sts, err := h.c.Apps().StatefulSets(namespace).Get(name, metav1.GetOptions{}) - if err != nil { - return "", fmt.Errorf("failed to retrieve statefulset %s", err) - } - selector, err := metav1.LabelSelectorAsSelector(sts.Spec.Selector) - if err != nil { - return "", fmt.Errorf("failed to retrieve statefulset history %s", err) - } - revisions, err := h.c.Apps().ControllerRevisions(namespace).List(metav1.ListOptions{LabelSelector: selector.String()}) - if err != nil { - return "", fmt.Errorf("failed to retrieve statefulset history %s", err) - } - if len(revisions.Items) <= 0 { + if len(history) <= 0 { return "No rollout history found.", nil } - revisionNumbers := make([]int64, len(revisions.Items)) - for i := range revisions.Items { - if owner := getOwner(revisions.Items[i]); owner != nil && owner.UID == sts.UID { - revisionNumbers[i] = revisions.Items[i].Revision - } + revisions := make([]int64, len(history)) + for _, revision := range history { + revisions = append(revisions, revision.Revision) } - sliceutil.SortInts64(revisionNumbers) + sliceutil.SortInts64(revisions) return tabbedString(func(out io.Writer) error { fmt.Fprintf(out, "REVISION\n") - for _, r := range revisionNumbers { + for _, r := range revisions { fmt.Fprintf(out, "%d\n", r) } return nil }) } -// controlledHistories returns all ControllerRevisions controlled by the given API object -func controlledHistories(apps clientappsv1beta1.AppsV1beta1Interface, extensions clientextensionsv1beta1.ExtensionsV1beta1Interface, namespace, name, kind string) (runtime.Object, []*appsv1beta1.ControllerRevision, error) { - var obj runtime.Object - var labelSelector *metav1.LabelSelector - - switch kind { - case "DaemonSet": - ds, err := extensions.DaemonSets(namespace).Get(name, metav1.GetOptions{}) - if err != nil { - return nil, nil, fmt.Errorf("failed to retrieve DaemonSet %s: %v", name, err) - } - labelSelector = ds.Spec.Selector - obj = ds - case "StatefulSet": - ss, err := apps.StatefulSets(namespace).Get(name, metav1.GetOptions{}) - if err != nil { - return nil, nil, fmt.Errorf("failed to retrieve StatefulSet %s: %v", name, err) - } - labelSelector = ss.Spec.Selector - obj = ss - default: - return nil, nil, fmt.Errorf("unsupported API object kind: %s", kind) - } - +// controlledHistories returns all ControllerRevisions in namespace that selected by selector and owned by accessor +func controlledHistory( + apps clientappsv1beta1.AppsV1beta1Interface, + namespace string, + selector labels.Selector, + accessor metav1.Object) ([]*appsv1beta1.ControllerRevision, error) { var result []*appsv1beta1.ControllerRevision - selector, err := metav1.LabelSelectorAsSelector(labelSelector) - if err != nil { - return nil, nil, err - } historyList, err := apps.ControllerRevisions(namespace).List(metav1.ListOptions{LabelSelector: selector.String()}) if err != nil { - return nil, nil, err - } - accessor, err := meta.Accessor(obj) - if err != nil { - return nil, nil, fmt.Errorf("failed to obtain accessor for %s named %s: %v", kind, name, err) + return nil, err } for i := range historyList.Items { history := historyList.Items[i] @@ -307,16 +251,59 @@ func controlledHistories(apps clientappsv1beta1.AppsV1beta1Interface, extensions result = append(result, &history) } } - return obj, result, nil + return result, nil } -// applyHistory returns a specific revision of DaemonSet by applying the given history to a copy of the given DaemonSet -func applyHistory(ds *extensionsv1beta1.DaemonSet, history *appsv1beta1.ControllerRevision) (*extensionsv1beta1.DaemonSet, error) { - obj, err := legacyscheme.Scheme.New(ds.GroupVersionKind()) +// daemonSetHistory returns the DaemonSet named name in namespace and all ControllerRevisions in its history. +func daemonSetHistory( + ext clientextv1beta1.ExtensionsV1beta1Interface, + apps clientappsv1beta1.AppsV1beta1Interface, + namespace, name string) (*extensionsv1beta1.DaemonSet, []*appsv1beta1.ControllerRevision, error) { + ds, err := ext.DaemonSets(namespace).Get(name, metav1.GetOptions{}) if err != nil { - return nil, err + return nil, nil, fmt.Errorf("failed to retrieve DaemonSet %s: %v", name, err) } - clone := obj.(*extensionsv1beta1.DaemonSet) + selector, err := metav1.LabelSelectorAsSelector(ds.Spec.Selector) + if err != nil { + return nil, nil, fmt.Errorf("failed to create selector for DaemonSet %s: %v", ds.Name, err) + } + accessor, err := meta.Accessor(ds) + if err != nil { + return nil, nil, fmt.Errorf("failed to create accessor for DaemonSet %s: %v", ds.Name, err) + } + history, err := controlledHistory(apps, ds.Namespace, selector, accessor) + if err != nil { + return nil, nil, fmt.Errorf("unable to find history controlled by DaemonSet %s: %v", ds.Name, err) + } + return ds, history, nil +} + +// statefulSetHistory returns the StatefulSet named name in namespace and all ControllerRevisions in its history. +func statefulSetHistory( + apps clientappsv1beta1.AppsV1beta1Interface, + namespace, name string) (*appsv1beta1.StatefulSet, []*appsv1beta1.ControllerRevision, error) { + sts, err := apps.StatefulSets(namespace).Get(name, metav1.GetOptions{}) + if err != nil { + return nil, nil, fmt.Errorf("failed to retrieve Statefulset %s: %s", name, err.Error()) + } + selector, err := metav1.LabelSelectorAsSelector(sts.Spec.Selector) + if err != nil { + return nil, nil, fmt.Errorf("failed to create selector for StatefulSet %s: %s", name, err.Error()) + } + accessor, err := meta.Accessor(sts) + if err != nil { + return nil, nil, fmt.Errorf("failed to obtain accessor for StatefulSet %s: %s", name, err.Error()) + } + history, err := controlledHistory(apps, namespace, selector, accessor) + if err != nil { + return nil, nil, fmt.Errorf("unable to find history controlled by StatefulSet %s: %v", name, err) + } + return sts, history, nil +} + +// applyDaemonSetHistory returns a specific revision of DaemonSet by applying the given history to a copy of the given DaemonSet +func applyDaemonSetHistory(ds *extensionsv1beta1.DaemonSet, history *appsv1beta1.ControllerRevision) (*extensionsv1beta1.DaemonSet, error) { + clone := ds.DeepCopy() cloneBytes, err := json.Marshal(clone) if err != nil { return nil, err diff --git a/pkg/kubectl/rollback.go b/pkg/kubectl/rollback.go index 6240d526ae..38cff7d092 100644 --- a/pkg/kubectl/rollback.go +++ b/pkg/kubectl/rollback.go @@ -26,18 +26,19 @@ import ( appsv1beta1 "k8s.io/api/apps/v1beta1" "k8s.io/api/core/v1" - externalextensions "k8s.io/api/extensions/v1beta1" + extv1beta1 "k8s.io/api/extensions/v1beta1" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/kubernetes" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/legacyscheme" apiv1 "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/extensions" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/controller/daemon" deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util" "k8s.io/kubernetes/pkg/controller/statefulset" @@ -55,7 +56,7 @@ type Rollbacker interface { Rollback(obj runtime.Object, updatedAnnotations map[string]string, toRevision int64, dryRun bool) (string, error) } -func RollbackerFor(kind schema.GroupKind, c clientset.Interface) (Rollbacker, error) { +func RollbackerFor(kind schema.GroupKind, c kubernetes.Interface) (Rollbacker, error) { switch kind { case extensions.Kind("Deployment"), apps.Kind("Deployment"): return &DeploymentRollbacker{c}, nil @@ -68,7 +69,7 @@ func RollbackerFor(kind schema.GroupKind, c clientset.Interface) (Rollbacker, er } type DeploymentRollbacker struct { - c clientset.Interface + c kubernetes.Interface } func (r *DeploymentRollbacker) Rollback(obj runtime.Object, updatedAnnotations map[string]string, toRevision int64, dryRun bool) (string, error) { @@ -82,26 +83,26 @@ func (r *DeploymentRollbacker) Rollback(obj runtime.Object, updatedAnnotations m if d.Spec.Paused { return "", fmt.Errorf("you cannot rollback a paused deployment; resume it first with 'kubectl rollout resume deployment/%s' and try again", d.Name) } - deploymentRollback := &extensions.DeploymentRollback{ + deploymentRollback := &extv1beta1.DeploymentRollback{ Name: d.Name, UpdatedAnnotations: updatedAnnotations, - RollbackTo: extensions.RollbackConfig{ + RollbackTo: extv1beta1.RollbackConfig{ Revision: toRevision, }, } result := "" // Get current events - events, err := r.c.Core().Events(d.Namespace).List(metav1.ListOptions{}) + events, err := r.c.CoreV1().Events(d.Namespace).List(metav1.ListOptions{}) if err != nil { return result, err } // Do the rollback - if err := r.c.Extensions().Deployments(d.Namespace).Rollback(deploymentRollback); err != nil { + if err := r.c.ExtensionsV1beta1().Deployments(d.Namespace).Rollback(deploymentRollback); err != nil { return result, err } // Watch for the changes of events - watch, err := r.c.Core().Events(d.Namespace).Watch(metav1.ListOptions{Watch: true, ResourceVersion: events.ResourceVersion}) + watch, err := r.c.CoreV1().Events(d.Namespace).Watch(metav1.ListOptions{Watch: true, ResourceVersion: events.ResourceVersion}) if err != nil { return result, err } @@ -150,13 +151,13 @@ func isRollbackEvent(e *api.Event) (bool, string) { return false, "" } -func simpleDryRun(deployment *extensions.Deployment, c clientset.Interface, toRevision int64) (string, error) { - externalDeployment := &externalextensions.Deployment{} +func simpleDryRun(deployment *extensions.Deployment, c kubernetes.Interface, toRevision int64) (string, error) { + externalDeployment := &extv1beta1.Deployment{} if err := legacyscheme.Scheme.Convert(deployment, externalDeployment, nil); err != nil { return "", fmt.Errorf("failed to convert deployment, %v", err) } - versionedExtensionsClient := versionedExtensionsClientV1beta1(c) - _, allOldRSs, newRS, err := deploymentutil.GetAllReplicaSets(externalDeployment, versionedExtensionsClient) + + _, allOldRSs, newRS, err := deploymentutil.GetAllReplicaSets(externalDeployment, c.ExtensionsV1beta1()) if err != nil { return "", fmt.Errorf("failed to retrieve replica sets from deployment %s: %v", deployment.Name, err) } @@ -213,40 +214,32 @@ func simpleDryRun(deployment *extensions.Deployment, c clientset.Interface, toRe } type DaemonSetRollbacker struct { - c clientset.Interface + c kubernetes.Interface } func (r *DaemonSetRollbacker) Rollback(obj runtime.Object, updatedAnnotations map[string]string, toRevision int64, dryRun bool) (string, error) { if toRevision < 0 { return "", revisionNotFoundErr(toRevision) } - - ds, ok := obj.(*extensions.DaemonSet) - if !ok { - return "", fmt.Errorf("passed object is not a DaemonSet: %#v", obj) - } - versionedAppsClient := versionedAppsClientV1beta1(r.c) - versionedExtensionsClient := versionedExtensionsClientV1beta1(r.c) - versionedObj, allHistory, err := controlledHistories(versionedAppsClient, versionedExtensionsClient, ds.Namespace, ds.Name, "DaemonSet") + accessor, err := meta.Accessor(obj) if err != nil { - return "", fmt.Errorf("unable to find history controlled by DaemonSet %s: %v", ds.Name, err) + return "", fmt.Errorf("failed to create accessor for kind %v: %s", obj.GetObjectKind(), err.Error()) } - versionedDS, ok := versionedObj.(*externalextensions.DaemonSet) - if !ok { - return "", fmt.Errorf("unexpected non-DaemonSet object returned: %v", versionedDS) + ds, history, err := daemonSetHistory(r.c.ExtensionsV1beta1(), r.c.AppsV1beta1(), accessor.GetNamespace(), accessor.GetName()) + if err != nil { + return "", err } - - if toRevision == 0 && len(allHistory) <= 1 { + if toRevision == 0 && len(history) <= 1 { return "", fmt.Errorf("no last revision to roll back to") } - toHistory := findHistory(toRevision, allHistory) + toHistory := findHistory(toRevision, history) if toHistory == nil { return "", revisionNotFoundErr(toRevision) } if dryRun { - appliedDS, err := applyHistory(versionedDS, toHistory) + appliedDS, err := applyDaemonSetHistory(ds, toHistory) if err != nil { return "", err } @@ -254,7 +247,7 @@ func (r *DaemonSetRollbacker) Rollback(obj runtime.Object, updatedAnnotations ma } // Skip if the revision already matches current DaemonSet - done, err := daemon.Match(versionedDS, toHistory) + done, err := daemon.Match(ds, toHistory) if err != nil { return "", err } @@ -263,7 +256,7 @@ func (r *DaemonSetRollbacker) Rollback(obj runtime.Object, updatedAnnotations ma } // Restore revision - if _, err = versionedExtensionsClient.DaemonSets(ds.Namespace).Patch(ds.Name, types.StrategicMergePatchType, toHistory.Data.Raw); err != nil { + if _, err = r.c.ExtensionsV1beta1().DaemonSets(accessor.GetNamespace()).Patch(accessor.GetName(), types.StrategicMergePatchType, toHistory.Data.Raw); err != nil { return "", fmt.Errorf("failed restoring revision %d: %v", toRevision, err) } @@ -271,7 +264,7 @@ func (r *DaemonSetRollbacker) Rollback(obj runtime.Object, updatedAnnotations ma } type StatefulSetRollbacker struct { - c clientset.Interface + c kubernetes.Interface } // toRevision is a non-negative integer, with 0 being reserved to indicate rolling back to previous configuration @@ -279,34 +272,25 @@ func (r *StatefulSetRollbacker) Rollback(obj runtime.Object, updatedAnnotations if toRevision < 0 { return "", revisionNotFoundErr(toRevision) } - - ss, ok := obj.(*apps.StatefulSet) - if !ok { - return "", fmt.Errorf("passed object is not a StatefulSet: %#v", obj) - } - versionedAppsClient := versionedAppsClientV1beta1(r.c) - versionedExtensionsClient := versionedExtensionsClientV1beta1(r.c) - versionedObj, allHistory, err := controlledHistories(versionedAppsClient, versionedExtensionsClient, ss.Namespace, ss.Name, "StatefulSet") + accessor, err := meta.Accessor(obj) if err != nil { - return "", fmt.Errorf("unable to find history controlled by StatefulSet %s: %v", ss.Name, err) + return "", fmt.Errorf("failed to create accessor for kind %v: %s", obj.GetObjectKind(), err.Error()) } - - versionedSS, ok := versionedObj.(*appsv1beta1.StatefulSet) - if !ok { - return "", fmt.Errorf("unexpected non-StatefulSet object returned: %v", versionedSS) + sts, history, err := statefulSetHistory(r.c.AppsV1beta1(), accessor.GetNamespace(), accessor.GetName()) + if err != nil { + return "", err } - - if toRevision == 0 && len(allHistory) <= 1 { + if toRevision == 0 && len(history) <= 1 { return "", fmt.Errorf("no last revision to roll back to") } - toHistory := findHistory(toRevision, allHistory) + toHistory := findHistory(toRevision, history) if toHistory == nil { return "", revisionNotFoundErr(toRevision) } if dryRun { - appliedSS, err := statefulset.ApplyRevision(versionedSS, toHistory) + appliedSS, err := statefulset.ApplyRevision(sts, toHistory) if err != nil { return "", err } @@ -314,7 +298,7 @@ func (r *StatefulSetRollbacker) Rollback(obj runtime.Object, updatedAnnotations } // Skip if the revision already matches current StatefulSet - done, err := statefulset.Match(versionedSS, toHistory) + done, err := statefulset.Match(sts, toHistory) if err != nil { return "", err } @@ -323,7 +307,7 @@ func (r *StatefulSetRollbacker) Rollback(obj runtime.Object, updatedAnnotations } // Restore revision - if _, err = versionedAppsClient.StatefulSets(ss.Namespace).Patch(ss.Name, types.StrategicMergePatchType, toHistory.Data.Raw); err != nil { + if _, err = r.c.AppsV1beta1().StatefulSets(sts.Namespace).Patch(sts.Name, types.StrategicMergePatchType, toHistory.Data.Raw); err != nil { return "", fmt.Errorf("failed restoring revision %d: %v", toRevision, err) }