Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
ebdbafd2
Commit
ebdbafd2
authored
Aug 07, 2017
by
crimsonfaith91
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
statefulSet kubectl rollout command
parent
2f00e6d7
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
211 additions
and
67 deletions
+211
-67
test-cmd-util.sh
hack/make-rules/test-cmd-util.sh
+0
-0
rollingupdate-statefulset-rv2.yaml
hack/testdata/rollingupdate-statefulset-rv2.yaml
+33
-0
rollingupdate-statefulset.yaml
hack/testdata/rollingupdate-statefulset.yaml
+7
-20
stateful_set_control.go
pkg/controller/statefulset/stateful_set_control.go
+2
-2
stateful_set_control_test.go
pkg/controller/statefulset/stateful_set_control_test.go
+1
-1
stateful_set_utils.go
pkg/controller/statefulset/stateful_set_utils.go
+12
-2
stateful_set_utils_test.go
pkg/controller/statefulset/stateful_set_utils_test.go
+1
-1
BUILD
pkg/kubectl/BUILD
+1
-0
rollout.go
pkg/kubectl/cmd/rollout/rollout.go
+1
-0
rollout_history.go
pkg/kubectl/cmd/rollout/rollout_history.go
+1
-1
rollout_status.go
pkg/kubectl/cmd/rollout/rollout_status.go
+1
-1
rollout_undo.go
pkg/kubectl/cmd/rollout/rollout_undo.go
+1
-1
history.go
pkg/kubectl/history.go
+41
-13
rollback.go
pkg/kubectl/rollback.go
+109
-25
No files found.
hack/make-rules/test-cmd-util.sh
View file @
ebdbafd2
This diff is collapsed.
Click to expand it.
hack/testdata/rollingupdate-statefulset-rv2.yaml
0 → 100644
View file @
ebdbafd2
apiVersion
:
apps/v1beta2
kind
:
StatefulSet
metadata
:
name
:
nginx
spec
:
selector
:
matchLabels
:
app
:
nginx-statefulset
updateStrategy
:
type
:
RollingUpdate
serviceName
:
"
nginx"
replicas
:
0
template
:
metadata
:
labels
:
app
:
nginx-statefulset
spec
:
terminationGracePeriodSeconds
:
5
containers
:
-
name
:
nginx
image
:
gcr.io/google_containers/nginx-slim:0.8
ports
:
-
containerPort
:
80
name
:
web
command
:
-
sh
-
-c
-
'
while
true;
do
sleep
1;
done'
-
name
:
pause
image
:
gcr.io/google-containers/pause:2.0
ports
:
-
containerPort
:
81
name
:
web-2
hack/testdata/
nginx
-statefulset.yaml
→
hack/testdata/
rollingupdate
-statefulset.yaml
View file @
ebdbafd2
# A headless service to create DNS records
apiVersion
:
apps/v1beta2
apiVersion
:
v1
kind
:
Service
metadata
:
annotations
:
service.alpha.kubernetes.io/tolerate-unready-endpoints
:
"
true"
name
:
nginx
labels
:
app
:
nginx-statefulset
spec
:
ports
:
-
port
:
80
name
:
web
# *.nginx.default.svc.cluster.local
clusterIP
:
None
selector
:
app
:
nginx-statefulset
---
apiVersion
:
apps/v1beta1
kind
:
StatefulSet
kind
:
StatefulSet
metadata
:
metadata
:
name
:
nginx
name
:
nginx
spec
:
spec
:
selector
:
matchLabels
:
app
:
nginx-statefulset
updateStrategy
:
type
:
RollingUpdate
serviceName
:
"
nginx"
serviceName
:
"
nginx"
replicas
:
0
replicas
:
0
template
:
template
:
...
@@ -28,7 +15,7 @@ spec:
...
@@ -28,7 +15,7 @@ spec:
labels
:
labels
:
app
:
nginx-statefulset
app
:
nginx-statefulset
spec
:
spec
:
terminationGracePeriodSeconds
:
0
terminationGracePeriodSeconds
:
5
containers
:
containers
:
-
name
:
nginx
-
name
:
nginx
image
:
gcr.io/google_containers/nginx-slim:0.7
image
:
gcr.io/google_containers/nginx-slim:0.7
...
...
pkg/controller/statefulset/stateful_set_control.go
View file @
ebdbafd2
...
@@ -256,11 +256,11 @@ func (ssc *defaultStatefulSetControl) updateStatefulSet(
...
@@ -256,11 +256,11 @@ func (ssc *defaultStatefulSetControl) updateStatefulSet(
collisionCount
int32
,
collisionCount
int32
,
pods
[]
*
v1
.
Pod
)
(
*
apps
.
StatefulSetStatus
,
error
)
{
pods
[]
*
v1
.
Pod
)
(
*
apps
.
StatefulSetStatus
,
error
)
{
// get the current and update revisions of the set.
// get the current and update revisions of the set.
currentSet
,
err
:=
a
pplyRevision
(
set
,
currentRevision
)
currentSet
,
err
:=
A
pplyRevision
(
set
,
currentRevision
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
updateSet
,
err
:=
a
pplyRevision
(
set
,
updateRevision
)
updateSet
,
err
:=
A
pplyRevision
(
set
,
updateRevision
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
...
...
pkg/controller/statefulset/stateful_set_control_test.go
View file @
ebdbafd2
...
@@ -1281,7 +1281,7 @@ func TestStatefulSetControlRollback(t *testing.T) {
...
@@ -1281,7 +1281,7 @@ func TestStatefulSetControlRollback(t *testing.T) {
t
.
Fatalf
(
"%s: %s"
,
test
.
name
,
err
)
t
.
Fatalf
(
"%s: %s"
,
test
.
name
,
err
)
}
}
history
.
SortControllerRevisions
(
revisions
)
history
.
SortControllerRevisions
(
revisions
)
set
,
err
=
a
pplyRevision
(
set
,
revisions
[
0
])
set
,
err
=
A
pplyRevision
(
set
,
revisions
[
0
])
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"%s: %s"
,
test
.
name
,
err
)
t
.
Fatalf
(
"%s: %s"
,
test
.
name
,
err
)
}
}
...
...
pkg/controller/statefulset/stateful_set_utils.go
View file @
ebdbafd2
...
@@ -17,6 +17,7 @@ limitations under the License.
...
@@ -17,6 +17,7 @@ limitations under the License.
package
statefulset
package
statefulset
import
(
import
(
"bytes"
"encoding/json"
"encoding/json"
"fmt"
"fmt"
"regexp"
"regexp"
...
@@ -266,6 +267,15 @@ func newVersionedStatefulSetPod(currentSet, updateSet *apps.StatefulSet, current
...
@@ -266,6 +267,15 @@ func newVersionedStatefulSetPod(currentSet, updateSet *apps.StatefulSet, current
return
pod
return
pod
}
}
// Match check if the given StatefulSet's template matches the template stored in the given history.
func
Match
(
ss
*
apps
.
StatefulSet
,
history
*
apps
.
ControllerRevision
)
(
bool
,
error
)
{
patch
,
err
:=
getPatch
(
ss
)
if
err
!=
nil
{
return
false
,
err
}
return
bytes
.
Equal
(
patch
,
history
.
Data
.
Raw
),
nil
}
// getPatch returns a strategic merge patch that can be applied to restore a StatefulSet to a
// getPatch returns a strategic merge patch that can be applied to restore a StatefulSet to a
// previous version. If the returned error is nil the patch is valid. The current state that we save is just the
// previous version. If the returned error is nil the patch is valid. The current state that we save is just the
// PodSpecTemplate. We can modify this later to encompass more state (or less) and remain compatible with previously
// PodSpecTemplate. We can modify this later to encompass more state (or less) and remain compatible with previously
...
@@ -319,9 +329,9 @@ func newRevision(set *apps.StatefulSet, revision int64, collisionCount *int32) (
...
@@ -319,9 +329,9 @@ func newRevision(set *apps.StatefulSet, revision int64, collisionCount *int32) (
return
cr
,
nil
return
cr
,
nil
}
}
//
a
pplyRevision returns a new StatefulSet constructed by restoring the state in revision to set. If the returned error
//
A
pplyRevision returns a new StatefulSet constructed by restoring the state in revision to set. If the returned error
// is nil, the returned StatefulSet is valid.
// is nil, the returned StatefulSet is valid.
func
a
pplyRevision
(
set
*
apps
.
StatefulSet
,
revision
*
apps
.
ControllerRevision
)
(
*
apps
.
StatefulSet
,
error
)
{
func
A
pplyRevision
(
set
*
apps
.
StatefulSet
,
revision
*
apps
.
ControllerRevision
)
(
*
apps
.
StatefulSet
,
error
)
{
obj
,
err
:=
scheme
.
Scheme
.
DeepCopy
(
set
)
obj
,
err
:=
scheme
.
Scheme
.
DeepCopy
(
set
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
...
...
pkg/controller/statefulset/stateful_set_utils_test.go
View file @
ebdbafd2
...
@@ -258,7 +258,7 @@ func TestCreateApplyRevision(t *testing.T) {
...
@@ -258,7 +258,7 @@ func TestCreateApplyRevision(t *testing.T) {
key
:=
"foo"
key
:=
"foo"
expectedValue
:=
"bar"
expectedValue
:=
"bar"
set
.
Annotations
[
key
]
=
expectedValue
set
.
Annotations
[
key
]
=
expectedValue
restoredSet
,
err
:=
a
pplyRevision
(
set
,
revision
)
restoredSet
,
err
:=
A
pplyRevision
(
set
,
revision
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatal
(
err
)
t
.
Fatal
(
err
)
}
}
...
...
pkg/kubectl/BUILD
View file @
ebdbafd2
...
@@ -129,6 +129,7 @@ go_library(
...
@@ -129,6 +129,7 @@ go_library(
"//pkg/client/unversioned:go_default_library",
"//pkg/client/unversioned:go_default_library",
"//pkg/controller/daemon:go_default_library",
"//pkg/controller/daemon:go_default_library",
"//pkg/controller/deployment/util:go_default_library",
"//pkg/controller/deployment/util:go_default_library",
"//pkg/controller/statefulset:go_default_library",
"//pkg/credentialprovider:go_default_library",
"//pkg/credentialprovider:go_default_library",
"//pkg/kubectl/resource:go_default_library",
"//pkg/kubectl/resource:go_default_library",
"//pkg/kubectl/util:go_default_library",
"//pkg/kubectl/util:go_default_library",
...
...
pkg/kubectl/cmd/rollout/rollout.go
View file @
ebdbafd2
...
@@ -42,6 +42,7 @@ var (
...
@@ -42,6 +42,7 @@ var (
* deployments
* deployments
* daemonsets
* daemonsets
* statefulsets
`
)
`
)
)
)
...
...
pkg/kubectl/cmd/rollout/rollout_history.go
View file @
ebdbafd2
...
@@ -44,7 +44,7 @@ var (
...
@@ -44,7 +44,7 @@ var (
func
NewCmdRolloutHistory
(
f
cmdutil
.
Factory
,
out
io
.
Writer
)
*
cobra
.
Command
{
func
NewCmdRolloutHistory
(
f
cmdutil
.
Factory
,
out
io
.
Writer
)
*
cobra
.
Command
{
options
:=
&
resource
.
FilenameOptions
{}
options
:=
&
resource
.
FilenameOptions
{}
validArgs
:=
[]
string
{
"deployment"
,
"daemonset"
}
validArgs
:=
[]
string
{
"deployment"
,
"daemonset"
,
"statefulset"
}
argAliases
:=
kubectl
.
ResourceAliases
(
validArgs
)
argAliases
:=
kubectl
.
ResourceAliases
(
validArgs
)
cmd
:=
&
cobra
.
Command
{
cmd
:=
&
cobra
.
Command
{
...
...
pkg/kubectl/cmd/rollout/rollout_status.go
View file @
ebdbafd2
...
@@ -50,7 +50,7 @@ var (
...
@@ -50,7 +50,7 @@ var (
func
NewCmdRolloutStatus
(
f
cmdutil
.
Factory
,
out
io
.
Writer
)
*
cobra
.
Command
{
func
NewCmdRolloutStatus
(
f
cmdutil
.
Factory
,
out
io
.
Writer
)
*
cobra
.
Command
{
options
:=
&
resource
.
FilenameOptions
{}
options
:=
&
resource
.
FilenameOptions
{}
validArgs
:=
[]
string
{
"deployment"
,
"daemonset"
}
validArgs
:=
[]
string
{
"deployment"
,
"daemonset"
,
"statefulset"
}
argAliases
:=
kubectl
.
ResourceAliases
(
validArgs
)
argAliases
:=
kubectl
.
ResourceAliases
(
validArgs
)
cmd
:=
&
cobra
.
Command
{
cmd
:=
&
cobra
.
Command
{
...
...
pkg/kubectl/cmd/rollout/rollout_undo.go
View file @
ebdbafd2
...
@@ -64,7 +64,7 @@ var (
...
@@ -64,7 +64,7 @@ var (
func
NewCmdRolloutUndo
(
f
cmdutil
.
Factory
,
out
io
.
Writer
)
*
cobra
.
Command
{
func
NewCmdRolloutUndo
(
f
cmdutil
.
Factory
,
out
io
.
Writer
)
*
cobra
.
Command
{
options
:=
&
UndoOptions
{}
options
:=
&
UndoOptions
{}
validArgs
:=
[]
string
{
"deployment"
,
"daemonset"
}
validArgs
:=
[]
string
{
"deployment"
,
"daemonset"
,
"statefulset"
}
argAliases
:=
kubectl
.
ResourceAliases
(
validArgs
)
argAliases
:=
kubectl
.
ResourceAliases
(
validArgs
)
cmd
:=
&
cobra
.
Command
{
cmd
:=
&
cobra
.
Command
{
...
...
pkg/kubectl/history.go
View file @
ebdbafd2
...
@@ -153,9 +153,9 @@ type DaemonSetHistoryViewer struct {
...
@@ -153,9 +153,9 @@ type DaemonSetHistoryViewer struct {
// ViewHistory returns a revision-to-history map as the revision history of a deployment
// ViewHistory returns a revision-to-history map as the revision history of a deployment
// TODO: this should be a describer
// TODO: this should be a describer
func
(
h
*
DaemonSetHistoryViewer
)
ViewHistory
(
namespace
,
name
string
,
revision
int64
)
(
string
,
error
)
{
func
(
h
*
DaemonSetHistoryViewer
)
ViewHistory
(
namespace
,
name
string
,
revision
int64
)
(
string
,
error
)
{
versionedExtensionsClient
:=
versionedExtensionsClientV1beta1
(
h
.
c
)
versionedAppsClient
:=
versionedAppsClientV1beta1
(
h
.
c
)
versionedAppsClient
:=
versionedAppsClientV1beta1
(
h
.
c
)
ds
,
allHistory
,
err
:=
controlledHistories
(
versionedExtensionsClient
,
versionedAppsClient
,
namespace
,
name
)
versionedExtensionsClient
:=
versionedExtensionsClientV1beta1
(
h
.
c
)
versionedObj
,
allHistory
,
err
:=
controlledHistories
(
versionedAppsClient
,
versionedExtensionsClient
,
namespace
,
name
,
"DaemonSet"
)
if
err
!=
nil
{
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"unable to find history controlled by DaemonSet %s: %v"
,
name
,
err
)
return
""
,
fmt
.
Errorf
(
"unable to find history controlled by DaemonSet %s: %v"
,
name
,
err
)
}
}
...
@@ -175,7 +175,13 @@ func (h *DaemonSetHistoryViewer) ViewHistory(namespace, name string, revision in
...
@@ -175,7 +175,13 @@ func (h *DaemonSetHistoryViewer) ViewHistory(namespace, name string, revision in
if
!
ok
{
if
!
ok
{
return
""
,
fmt
.
Errorf
(
"unable to find the specified revision"
)
return
""
,
fmt
.
Errorf
(
"unable to find the specified revision"
)
}
}
dsOfHistory
,
err
:=
applyHistory
(
ds
,
history
)
versionedDS
,
ok
:=
versionedObj
.
(
*
extensionsv1beta1
.
DaemonSet
)
if
!
ok
{
return
""
,
fmt
.
Errorf
(
"unexpected non-DaemonSet object returned: %v"
,
versionedDS
)
}
dsOfHistory
,
err
:=
applyHistory
(
versionedDS
,
history
)
if
err
!=
nil
{
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"unable to parse history %s"
,
history
.
Name
)
return
""
,
fmt
.
Errorf
(
"unable to parse history %s"
,
history
.
Name
)
}
}
...
@@ -256,29 +262,51 @@ func (h *StatefulSetHistoryViewer) ViewHistory(namespace, name string, revision
...
@@ -256,29 +262,51 @@ func (h *StatefulSetHistoryViewer) ViewHistory(namespace, name string, revision
})
})
}
}
// controlledHistories returns all ControllerRevisions controlled by the given DaemonSet
// controlledHistories returns all ControllerRevisions controlled by the given API object
func
controlledHistories
(
extensions
clientextensionsv1beta1
.
ExtensionsV1beta1Interface
,
apps
clientappsv1beta1
.
AppsV1beta1Interface
,
namespace
,
name
string
)
(
*
extensionsv1beta1
.
DaemonSet
,
[]
*
appsv1beta1
.
ControllerRevision
,
error
)
{
func
controlledHistories
(
apps
clientappsv1beta1
.
AppsV1beta1Interface
,
extensions
clientextensionsv1beta1
.
ExtensionsV1beta1Interface
,
namespace
,
name
,
kind
string
)
(
runtime
.
Object
,
[]
*
appsv1beta1
.
ControllerRevision
,
error
)
{
ds
,
err
:=
extensions
.
DaemonSets
(
namespace
)
.
Get
(
name
,
metav1
.
GetOptions
{})
var
obj
runtime
.
Object
if
err
!=
nil
{
var
labelSelector
*
metav1
.
LabelSelector
return
nil
,
nil
,
fmt
.
Errorf
(
"failed to retrieve DaemonSet %s: %v"
,
name
,
err
)
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
)
}
}
var
result
[]
*
appsv1beta1
.
ControllerRevision
var
result
[]
*
appsv1beta1
.
ControllerRevision
selector
,
err
:=
metav1
.
LabelSelectorAsSelector
(
ds
.
Spec
.
Selector
)
selector
,
err
:=
metav1
.
LabelSelectorAsSelector
(
label
Selector
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
nil
,
err
return
nil
,
nil
,
err
}
}
historyList
,
err
:=
apps
.
ControllerRevisions
(
ds
.
N
amespace
)
.
List
(
metav1
.
ListOptions
{
LabelSelector
:
selector
.
String
()})
historyList
,
err
:=
apps
.
ControllerRevisions
(
n
amespace
)
.
List
(
metav1
.
ListOptions
{
LabelSelector
:
selector
.
String
()})
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
nil
,
err
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
)
}
for
i
:=
range
historyList
.
Items
{
for
i
:=
range
historyList
.
Items
{
history
:=
historyList
.
Items
[
i
]
history
:=
historyList
.
Items
[
i
]
// Only add history that belongs to the
DaemonSe
t
// Only add history that belongs to the
API objec
t
if
metav1
.
IsControlledBy
(
&
history
,
ds
)
{
if
metav1
.
IsControlledBy
(
&
history
,
accessor
)
{
result
=
append
(
result
,
&
history
)
result
=
append
(
result
,
&
history
)
}
}
}
}
return
ds
,
result
,
nil
return
obj
,
result
,
nil
}
}
// applyHistory returns a specific revision of DaemonSet by applying the given history to a copy of the given DaemonSet
// applyHistory returns a specific revision of DaemonSet by applying the given history to a copy of the given DaemonSet
...
...
pkg/kubectl/rollback.go
View file @
ebdbafd2
...
@@ -39,6 +39,7 @@ import (
...
@@ -39,6 +39,7 @@ import (
clientset
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
clientset
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/controller/daemon"
"k8s.io/kubernetes/pkg/controller/daemon"
deploymentutil
"k8s.io/kubernetes/pkg/controller/deployment/util"
deploymentutil
"k8s.io/kubernetes/pkg/controller/deployment/util"
"k8s.io/kubernetes/pkg/controller/statefulset"
sliceutil
"k8s.io/kubernetes/pkg/kubectl/util/slice"
sliceutil
"k8s.io/kubernetes/pkg/kubectl/util/slice"
printersinternal
"k8s.io/kubernetes/pkg/printers/internalversion"
printersinternal
"k8s.io/kubernetes/pkg/printers/internalversion"
)
)
...
@@ -59,6 +60,8 @@ func RollbackerFor(kind schema.GroupKind, c clientset.Interface) (Rollbacker, er
...
@@ -59,6 +60,8 @@ func RollbackerFor(kind schema.GroupKind, c clientset.Interface) (Rollbacker, er
return
&
DeploymentRollbacker
{
c
},
nil
return
&
DeploymentRollbacker
{
c
},
nil
case
extensions
.
Kind
(
"DaemonSet"
),
apps
.
Kind
(
"DaemonSet"
)
:
case
extensions
.
Kind
(
"DaemonSet"
),
apps
.
Kind
(
"DaemonSet"
)
:
return
&
DaemonSetRollbacker
{
c
},
nil
return
&
DaemonSetRollbacker
{
c
},
nil
case
apps
.
Kind
(
"StatefulSet"
)
:
return
&
StatefulSetRollbacker
{
c
},
nil
}
}
return
nil
,
fmt
.
Errorf
(
"no rollbacker has been implemented for %q"
,
kind
)
return
nil
,
fmt
.
Errorf
(
"no rollbacker has been implemented for %q"
,
kind
)
}
}
...
@@ -221,32 +224,22 @@ func (r *DaemonSetRollbacker) Rollback(obj runtime.Object, updatedAnnotations ma
...
@@ -221,32 +224,22 @@ func (r *DaemonSetRollbacker) Rollback(obj runtime.Object, updatedAnnotations ma
if
!
ok
{
if
!
ok
{
return
""
,
fmt
.
Errorf
(
"passed object is not a DaemonSet: %#v"
,
obj
)
return
""
,
fmt
.
Errorf
(
"passed object is not a DaemonSet: %#v"
,
obj
)
}
}
versionedExtensionsClient
:=
versionedExtensionsClientV1beta1
(
r
.
c
)
versionedAppsClient
:=
versionedAppsClientV1beta1
(
r
.
c
)
versionedAppsClient
:=
versionedAppsClientV1beta1
(
r
.
c
)
versionedDS
,
allHistory
,
err
:=
controlledHistories
(
versionedExtensionsClient
,
versionedAppsClient
,
ds
.
Namespace
,
ds
.
Name
)
versionedExtensionsClient
:=
versionedExtensionsClientV1beta1
(
r
.
c
)
versionedObj
,
allHistory
,
err
:=
controlledHistories
(
versionedAppsClient
,
versionedExtensionsClient
,
ds
.
Namespace
,
ds
.
Name
,
"DaemonSet"
)
if
err
!=
nil
{
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"unable to find history controlled by DaemonSet %s: %v"
,
ds
.
Name
,
err
)
return
""
,
fmt
.
Errorf
(
"unable to find history controlled by DaemonSet %s: %v"
,
ds
.
Name
,
err
)
}
}
versionedDS
,
ok
:=
versionedObj
.
(
*
externalextensions
.
DaemonSet
)
if
!
ok
{
return
""
,
fmt
.
Errorf
(
"unexpected non-DaemonSet object returned: %v"
,
versionedDS
)
}
if
toRevision
==
0
&&
len
(
allHistory
)
<=
1
{
if
toRevision
==
0
&&
len
(
allHistory
)
<=
1
{
return
""
,
fmt
.
Errorf
(
"no last revision to roll back to"
)
return
""
,
fmt
.
Errorf
(
"no last revision to roll back to"
)
}
}
// Find the history to rollback to
toHistory
:=
findHistory
(
toRevision
,
allHistory
)
var
toHistory
*
appsv1beta1
.
ControllerRevision
if
toRevision
==
0
{
// If toRevision == 0, find the latest revision (2nd max)
sort
.
Sort
(
historiesByRevision
(
allHistory
))
toHistory
=
allHistory
[
len
(
allHistory
)
-
2
]
}
else
{
for
_
,
h
:=
range
allHistory
{
if
h
.
Revision
==
toRevision
{
// If toRevision != 0, find the history with matching revision
toHistory
=
h
break
}
}
}
if
toHistory
==
nil
{
if
toHistory
==
nil
{
return
""
,
revisionNotFoundErr
(
toRevision
)
return
""
,
revisionNotFoundErr
(
toRevision
)
}
}
...
@@ -256,14 +249,7 @@ func (r *DaemonSetRollbacker) Rollback(obj runtime.Object, updatedAnnotations ma
...
@@ -256,14 +249,7 @@ func (r *DaemonSetRollbacker) Rollback(obj runtime.Object, updatedAnnotations ma
if
err
!=
nil
{
if
err
!=
nil
{
return
""
,
err
return
""
,
err
}
}
content
:=
bytes
.
NewBuffer
([]
byte
{})
return
printPodTemplate
(
&
appliedDS
.
Spec
.
Template
)
w
:=
printersinternal
.
NewPrefixWriter
(
content
)
internalTemplate
:=
&
api
.
PodTemplateSpec
{}
if
err
:=
apiv1
.
Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec
(
&
appliedDS
.
Spec
.
Template
,
internalTemplate
,
nil
);
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"failed to convert podtemplate while printing: %v"
,
err
)
}
printersinternal
.
DescribePodTemplate
(
internalTemplate
,
w
)
return
fmt
.
Sprintf
(
"will roll back to %s"
,
content
.
String
()),
nil
}
}
// Skip if the revision already matches current DaemonSet
// Skip if the revision already matches current DaemonSet
...
@@ -283,6 +269,104 @@ func (r *DaemonSetRollbacker) Rollback(obj runtime.Object, updatedAnnotations ma
...
@@ -283,6 +269,104 @@ func (r *DaemonSetRollbacker) Rollback(obj runtime.Object, updatedAnnotations ma
return
rollbackSuccess
,
nil
return
rollbackSuccess
,
nil
}
}
type
StatefulSetRollbacker
struct
{
c
clientset
.
Interface
}
// toRevision is a non-negative integer, with 0 being reserved to indicate rolling back to previous configuration
func
(
r
*
StatefulSetRollbacker
)
Rollback
(
obj
runtime
.
Object
,
updatedAnnotations
map
[
string
]
string
,
toRevision
int64
,
dryRun
bool
)
(
string
,
error
)
{
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"
)
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"unable to find history controlled by StatefulSet %s: %v"
,
ss
.
Name
,
err
)
}
versionedSS
,
ok
:=
versionedObj
.
(
*
appsv1beta1
.
StatefulSet
)
if
!
ok
{
return
""
,
fmt
.
Errorf
(
"unexpected non-StatefulSet object returned: %v"
,
versionedSS
)
}
if
toRevision
==
0
&&
len
(
allHistory
)
<=
1
{
return
""
,
fmt
.
Errorf
(
"no last revision to roll back to"
)
}
toHistory
:=
findHistory
(
toRevision
,
allHistory
)
if
toHistory
==
nil
{
return
""
,
revisionNotFoundErr
(
toRevision
)
}
if
dryRun
{
appliedSS
,
err
:=
statefulset
.
ApplyRevision
(
versionedSS
,
toHistory
)
if
err
!=
nil
{
return
""
,
err
}
return
printPodTemplate
(
&
appliedSS
.
Spec
.
Template
)
}
// Skip if the revision already matches current StatefulSet
done
,
err
:=
statefulset
.
Match
(
versionedSS
,
toHistory
)
if
err
!=
nil
{
return
""
,
err
}
if
done
{
return
fmt
.
Sprintf
(
"%s (current template already matches revision %d)"
,
rollbackSkipped
,
toRevision
),
nil
}
// Restore revision
if
_
,
err
=
versionedAppsClient
.
StatefulSets
(
ss
.
Namespace
)
.
Patch
(
ss
.
Name
,
types
.
StrategicMergePatchType
,
toHistory
.
Data
.
Raw
);
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"failed restoring revision %d: %v"
,
toRevision
,
err
)
}
return
rollbackSuccess
,
nil
}
// findHistory returns a controllerrevision of a specific revision from the given controllerrevisions.
// It returns nil if no such controllerrevision exists.
// If toRevision is 0, the last previously used history is returned.
func
findHistory
(
toRevision
int64
,
allHistory
[]
*
appsv1beta1
.
ControllerRevision
)
*
appsv1beta1
.
ControllerRevision
{
if
toRevision
==
0
&&
len
(
allHistory
)
<=
1
{
return
nil
}
// Find the history to rollback to
var
toHistory
*
appsv1beta1
.
ControllerRevision
if
toRevision
==
0
{
// If toRevision == 0, find the latest revision (2nd max)
sort
.
Sort
(
historiesByRevision
(
allHistory
))
toHistory
=
allHistory
[
len
(
allHistory
)
-
2
]
}
else
{
for
_
,
h
:=
range
allHistory
{
if
h
.
Revision
==
toRevision
{
// If toRevision != 0, find the history with matching revision
return
h
}
}
}
return
toHistory
}
// printPodTemplate converts a given pod template into a human-readable string.
func
printPodTemplate
(
specTemplate
*
v1
.
PodTemplateSpec
)
(
string
,
error
)
{
content
:=
bytes
.
NewBuffer
([]
byte
{})
w
:=
printersinternal
.
NewPrefixWriter
(
content
)
internalTemplate
:=
&
api
.
PodTemplateSpec
{}
if
err
:=
apiv1
.
Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec
(
specTemplate
,
internalTemplate
,
nil
);
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"failed to convert podtemplate while printing: %v"
,
err
)
}
printersinternal
.
DescribePodTemplate
(
internalTemplate
,
w
)
return
fmt
.
Sprintf
(
"will roll back to %s"
,
content
.
String
()),
nil
}
func
revisionNotFoundErr
(
r
int64
)
error
{
func
revisionNotFoundErr
(
r
int64
)
error
{
return
fmt
.
Errorf
(
"unable to find specified revision %v in history"
,
r
)
return
fmt
.
Errorf
(
"unable to find specified revision %v in history"
,
r
)
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment