Skip to content

Commit 13f3e2a

Browse files
authored
[Feature] Container runtime image update (#787)
1 parent c65c8d9 commit 13f3e2a

34 files changed

+1152
-61
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A)
44
- Update UBI Image to 8.4
55
- Fix ArangoSync Liveness Prove
6+
- Allow runtime update of Sidecar images
67

78
## [1.2.2](https://github.com/arangodb/kube-arangodb/tree/1.2.2) (2021-09-09)
89
- Update 'github.com/arangodb/arangosync-client' dependency to v0.7.0

pkg/apis/deployment/v1/arango_member_pod_template.go

+16-3
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,16 @@ func GetArangoMemberPodTemplate(pod *core.PodTemplateSpec, podSpecChecksum strin
3636
return nil, err
3737
}
3838

39+
checksum := fmt.Sprintf("%0x", sha256.Sum256(data))
40+
41+
if podSpecChecksum == "" {
42+
podSpecChecksum = checksum
43+
}
44+
3945
return &ArangoMemberPodTemplate{
4046
PodSpec: pod,
4147
PodSpecChecksum: podSpecChecksum,
42-
Checksum: fmt.Sprintf("%0x", sha256.Sum256(data)),
48+
Checksum: checksum,
4349
}, nil
4450
}
4551

@@ -49,6 +55,13 @@ type ArangoMemberPodTemplate struct {
4955
Checksum string `json:"checksum,omitempty"`
5056
}
5157

58+
func (a *ArangoMemberPodTemplate) GetChecksum() string {
59+
if a == nil {
60+
return ""
61+
}
62+
return a.Checksum
63+
}
64+
5265
func (a *ArangoMemberPodTemplate) Equals(b *ArangoMemberPodTemplate) bool {
5366
if a == nil && b == nil {
5467
return true
@@ -58,7 +71,7 @@ func (a *ArangoMemberPodTemplate) Equals(b *ArangoMemberPodTemplate) bool {
5871
return false
5972
}
6073

61-
return a.Checksum == b.Checksum && a.PodSpecChecksum == b.PodSpecChecksum
74+
return a.Checksum == b.Checksum
6275
}
6376

6477
func (a *ArangoMemberPodTemplate) RotationNeeded(b *ArangoMemberPodTemplate) bool {
@@ -70,7 +83,7 @@ func (a *ArangoMemberPodTemplate) RotationNeeded(b *ArangoMemberPodTemplate) boo
7083
return true
7184
}
7285

73-
return a.PodSpecChecksum != b.PodSpecChecksum
86+
return a.Checksum != b.Checksum
7487
}
7588

7689
func (a *ArangoMemberPodTemplate) EqualPodSpecChecksum(checksum string) bool {

pkg/apis/deployment/v1/arango_member_status.go

-8
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,8 @@
2222

2323
package v1
2424

25-
const (
26-
ArangoMemberConditionPendingRestart ConditionType = "pending-restart"
27-
)
28-
2925
type ArangoMemberStatus struct {
3026
Conditions ConditionList `json:"conditions,omitempty"`
3127

3228
Template *ArangoMemberPodTemplate `json:"template,omitempty"`
3329
}
34-
35-
func (a ArangoMemberStatus) IsPendingRestart() bool {
36-
return a.Conditions.IsTrue(ArangoMemberConditionPendingRestart)
37-
}

pkg/apis/deployment/v1/conditions.go

+6
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ const (
7777
ConditionTypeRestart ConditionType = "Restart"
7878
// ConditionTypePendingTLSRotation indicates that TLS rotation is pending
7979
ConditionTypePendingTLSRotation ConditionType = "PendingTLSRotation"
80+
// ConditionTypePendingUpdate indicates that runtime update is pending
81+
ConditionTypePendingUpdate ConditionType = "PendingUpdate"
82+
// ConditionTypeUpdating indicates that runtime update is in progress
83+
ConditionTypeUpdating ConditionType = "Updating"
84+
// ConditionTypeUpdateFailed indicates that runtime update failed
85+
ConditionTypeUpdateFailed ConditionType = "UpdateFailed"
8086
)
8187

8288
// Condition represents one current condition of a deployment or deployment member.

pkg/apis/deployment/v1/plan.go

+27
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ const (
165165
ActionTypeArangoMemberUpdatePodSpec ActionType = "ArangoMemberUpdatePodSpec"
166166
// ActionTypeArangoMemberUpdatePodStatus updates pod spec
167167
ActionTypeArangoMemberUpdatePodStatus ActionType = "ArangoMemberUpdatePodStatus"
168+
169+
// Runtime Updates
170+
// ActionTypeRuntimeContainerImageUpdate updates container image in runtime
171+
ActionTypeRuntimeContainerImageUpdate ActionType = "RuntimeContainerImageUpdate"
168172
)
169173

170174
const (
@@ -245,6 +249,29 @@ func NewAction(actionType ActionType, group ServerGroup, memberID string, reason
245249
return a
246250
}
247251

252+
// ActionBuilder allows to generate actions based on predefined group and member id
253+
type ActionBuilder interface {
254+
// NewAction instantiates a new Action.
255+
NewAction(actionType ActionType, reason ...string) Action
256+
}
257+
258+
type actionBuilder struct {
259+
group ServerGroup
260+
memberID string
261+
}
262+
263+
func (a actionBuilder) NewAction(actionType ActionType, reason ...string) Action {
264+
return NewAction(actionType, a.group, a.memberID, reason...)
265+
}
266+
267+
// NewActionBuilder create new action builder with provided group and id
268+
func NewActionBuilder(group ServerGroup, memberID string) ActionBuilder {
269+
return actionBuilder{
270+
group: group,
271+
memberID: memberID,
272+
}
273+
}
274+
248275
// SetImage sets the Image field to the given value and returns the modified
249276
// action.
250277
func (a Action) SetImage(image string) Action {

pkg/apis/deployment/v1/timeouts.go

+5
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,14 @@ const (
3333
)
3434

3535
type Timeouts struct {
36+
// AddMember action timeout
3637
AddMember *Timeout `json:"addMember,omitempty"`
3738

39+
// MaintenanceGracePeriod action timeout
3840
MaintenanceGracePeriod *Timeout `json:"maintenanceGracePeriod,omitempty"`
41+
42+
// RuntimeContainerImageUpdate action timeout
43+
RuntimeContainerImageUpdate *Timeout `json:"runtimeContainerImageUpdate,omitempty"`
3944
}
4045

4146
func (t *Timeouts) GetMaintenanceGracePeriod() time.Duration {

pkg/apis/deployment/v1/zz_generated.deepcopy.go

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/deployment/v2alpha1/arango_member_pod_template.go

+16-3
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,16 @@ func GetArangoMemberPodTemplate(pod *core.PodTemplateSpec, podSpecChecksum strin
3636
return nil, err
3737
}
3838

39+
checksum := fmt.Sprintf("%0x", sha256.Sum256(data))
40+
41+
if podSpecChecksum == "" {
42+
podSpecChecksum = checksum
43+
}
44+
3945
return &ArangoMemberPodTemplate{
4046
PodSpec: pod,
4147
PodSpecChecksum: podSpecChecksum,
42-
Checksum: fmt.Sprintf("%0x", sha256.Sum256(data)),
48+
Checksum: checksum,
4349
}, nil
4450
}
4551

@@ -49,6 +55,13 @@ type ArangoMemberPodTemplate struct {
4955
Checksum string `json:"checksum,omitempty"`
5056
}
5157

58+
func (a *ArangoMemberPodTemplate) GetChecksum() string {
59+
if a == nil {
60+
return ""
61+
}
62+
return a.Checksum
63+
}
64+
5265
func (a *ArangoMemberPodTemplate) Equals(b *ArangoMemberPodTemplate) bool {
5366
if a == nil && b == nil {
5467
return true
@@ -58,7 +71,7 @@ func (a *ArangoMemberPodTemplate) Equals(b *ArangoMemberPodTemplate) bool {
5871
return false
5972
}
6073

61-
return a.Checksum == b.Checksum && a.PodSpecChecksum == b.PodSpecChecksum
74+
return a.Checksum == b.Checksum
6275
}
6376

6477
func (a *ArangoMemberPodTemplate) RotationNeeded(b *ArangoMemberPodTemplate) bool {
@@ -70,7 +83,7 @@ func (a *ArangoMemberPodTemplate) RotationNeeded(b *ArangoMemberPodTemplate) boo
7083
return true
7184
}
7285

73-
return a.PodSpecChecksum != b.PodSpecChecksum
86+
return a.Checksum != b.Checksum
7487
}
7588

7689
func (a *ArangoMemberPodTemplate) EqualPodSpecChecksum(checksum string) bool {

pkg/apis/deployment/v2alpha1/arango_member_status.go

-8
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,8 @@
2222

2323
package v2alpha1
2424

25-
const (
26-
ArangoMemberConditionPendingRestart ConditionType = "pending-restart"
27-
)
28-
2925
type ArangoMemberStatus struct {
3026
Conditions ConditionList `json:"conditions,omitempty"`
3127

3228
Template *ArangoMemberPodTemplate `json:"template,omitempty"`
3329
}
34-
35-
func (a ArangoMemberStatus) IsPendingRestart() bool {
36-
return a.Conditions.IsTrue(ArangoMemberConditionPendingRestart)
37-
}

pkg/apis/deployment/v2alpha1/conditions.go

+6
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ const (
7777
ConditionTypeRestart ConditionType = "Restart"
7878
// ConditionTypePendingTLSRotation indicates that TLS rotation is pending
7979
ConditionTypePendingTLSRotation ConditionType = "PendingTLSRotation"
80+
// ConditionTypePendingUpdate indicates that runtime update is pending
81+
ConditionTypePendingUpdate ConditionType = "PendingUpdate"
82+
// ConditionTypeUpdating indicates that runtime update is in progress
83+
ConditionTypeUpdating ConditionType = "Updating"
84+
// ConditionTypeUpdateFailed indicates that runtime update failed
85+
ConditionTypeUpdateFailed ConditionType = "UpdateFailed"
8086
)
8187

8288
// Condition represents one current condition of a deployment or deployment member.

pkg/apis/deployment/v2alpha1/plan.go

+27
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ const (
165165
ActionTypeArangoMemberUpdatePodSpec ActionType = "ArangoMemberUpdatePodSpec"
166166
// ActionTypeArangoMemberUpdatePodStatus updates pod spec
167167
ActionTypeArangoMemberUpdatePodStatus ActionType = "ArangoMemberUpdatePodStatus"
168+
169+
// Runtime Updates
170+
// ActionTypeRuntimeContainerImageUpdate updates container image in runtime
171+
ActionTypeRuntimeContainerImageUpdate ActionType = "RuntimeContainerImageUpdate"
168172
)
169173

170174
const (
@@ -245,6 +249,29 @@ func NewAction(actionType ActionType, group ServerGroup, memberID string, reason
245249
return a
246250
}
247251

252+
// ActionBuilder allows to generate actions based on predefined group and member id
253+
type ActionBuilder interface {
254+
// NewAction instantiates a new Action.
255+
NewAction(actionType ActionType, reason ...string) Action
256+
}
257+
258+
type actionBuilder struct {
259+
group ServerGroup
260+
memberID string
261+
}
262+
263+
func (a actionBuilder) NewAction(actionType ActionType, reason ...string) Action {
264+
return NewAction(actionType, a.group, a.memberID, reason...)
265+
}
266+
267+
// NewActionBuilder create new action builder with provided group and id
268+
func NewActionBuilder(group ServerGroup, memberID string) ActionBuilder {
269+
return actionBuilder{
270+
group: group,
271+
memberID: memberID,
272+
}
273+
}
274+
248275
// SetImage sets the Image field to the given value and returns the modified
249276
// action.
250277
func (a Action) SetImage(image string) Action {

pkg/apis/deployment/v2alpha1/timeouts.go

+5
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,14 @@ const (
3333
)
3434

3535
type Timeouts struct {
36+
// AddMember action timeout
3637
AddMember *Timeout `json:"addMember,omitempty"`
3738

39+
// MaintenanceGracePeriod action timeout
3840
MaintenanceGracePeriod *Timeout `json:"maintenanceGracePeriod,omitempty"`
41+
42+
// RuntimeContainerImageUpdate action timeout
43+
RuntimeContainerImageUpdate *Timeout `json:"runtimeContainerImageUpdate,omitempty"`
3944
}
4045

4146
func (t *Timeouts) GetMaintenanceGracePeriod() time.Duration {

pkg/apis/deployment/v2alpha1/zz_generated.deepcopy.go

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/deployment/reconcile/action.go

+16
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,22 @@ type Action interface {
5353
MemberID() string
5454
}
5555

56+
// ActionPost keep interface which is executed after action is completed.
57+
type ActionPost interface {
58+
Action
59+
60+
// Post execute after action is completed
61+
Post(ctx context.Context) error
62+
}
63+
64+
func getActionPost(a Action, ctx context.Context) error {
65+
if c, ok := a.(ActionPost); !ok {
66+
return nil
67+
} else {
68+
return c.Post(ctx)
69+
}
70+
}
71+
5672
// ActionReloadCachedStatus keeps information about CachedStatus reloading (executed after action has been executed)
5773
type ActionReloadCachedStatus interface {
5874
Action

pkg/deployment/reconcile/action_arango_membed_update_pod_status.go

+15
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ func init() {
3636
registerAction(api.ActionTypeArangoMemberUpdatePodStatus, newArangoMemberUpdatePodStatusAction)
3737
}
3838

39+
const (
40+
ActionTypeArangoMemberUpdatePodStatusChecksum = "checksum"
41+
)
42+
3943
// newArangoMemberUpdatePodStatusAction creates a new Action that implements the given
4044
// planned ArangoMemberUpdatePodStatus action.
4145
func newArangoMemberUpdatePodStatusAction(log zerolog.Logger, action api.Action, actionCtx ActionContext) Action {
@@ -74,6 +78,17 @@ func (a *actionArangoMemberUpdatePodStatus) Start(ctx context.Context) (bool, er
7478
return false, err
7579
}
7680

81+
if c, ok := a.action.GetParam(ActionTypeArangoMemberUpdatePodStatusChecksum); ok {
82+
if member.Spec.Template == nil {
83+
return true, nil
84+
}
85+
86+
if member.Spec.Template.Checksum != c {
87+
// Checksum is invalid
88+
return true, nil
89+
}
90+
}
91+
7792
if member.Status.Template == nil || !member.Status.Template.Equals(member.Spec.Template) {
7893
if err := a.actionCtx.WithArangoMemberStatusUpdate(context.Background(), member.GetNamespace(), member.GetName(), func(obj *api.ArangoMember, status *api.ArangoMemberStatus) bool {
7994
if status.Template == nil || !status.Template.Equals(member.Spec.Template) {

pkg/deployment/reconcile/action_context.go

+17
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ package reconcile
2626
import (
2727
"context"
2828

29+
"github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned"
30+
monitoringClient "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1"
31+
"k8s.io/client-go/kubernetes"
32+
2933
"github.com/arangodb/kube-arangodb/pkg/deployment/resources"
3034

3135
inspectorInterface "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector"
@@ -53,6 +57,7 @@ type ActionContext interface {
5357
resources.DeploymentAgencyMaintenance
5458
resources.ArangoMemberContext
5559
resources.DeploymentPodRenderer
60+
resources.DeploymentCLIGetter
5661

5762
// GetAPIObject returns the deployment as k8s object.
5863
GetAPIObject() k8sutil.APIObject
@@ -163,6 +168,18 @@ type actionContext struct {
163168
cachedStatus inspectorInterface.Inspector
164169
}
165170

171+
func (ac *actionContext) GetKubeCli() kubernetes.Interface {
172+
return ac.context.GetKubeCli()
173+
}
174+
175+
func (ac *actionContext) GetMonitoringV1Cli() monitoringClient.MonitoringV1Interface {
176+
return ac.context.GetMonitoringV1Cli()
177+
}
178+
179+
func (ac *actionContext) GetArangoCli() versioned.Interface {
180+
return ac.context.GetArangoCli()
181+
}
182+
166183
func (ac *actionContext) RenderPodForMemberFromCurrent(ctx context.Context, cachedStatus inspectorInterface.Inspector, memberID string) (*core.Pod, error) {
167184
return ac.context.RenderPodForMemberFromCurrent(ctx, cachedStatus, memberID)
168185
}

0 commit comments

Comments
 (0)