Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow version upgrades for specific containers and initContainers #425

Merged
merged 6 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/go.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '>=1.20.2'
go-version: '>=1.22'
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
Expand All @@ -29,6 +29,6 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '>=1.20.2'
go-version: '>=1.22'
- name: unit tests
run: make test
7 changes: 3 additions & 4 deletions .github/workflows/manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '>=1.20.2'
go-version: '>=1.22'
- run: make generate manifests

- uses: CatChen/check-git-status-action@v1
with:
fail-if-not-clean: true
- name: Ensure no changes
run: git diff --exit-code
8 changes: 8 additions & 0 deletions api/v1/cosmosfullnode_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,14 @@ type ChainVersion struct {
// The docker image for this version in "repository:tag" format. E.g. busybox:latest.
Image string `json:"image"`

// Version overrides for initContainers of the fullnode/sentry pods.
// +optional
InitContainers map[string]string `json:"initContainers"`

// Version overrides for containers of the fullnode/sentry pods.
// +optional
Containers map[string]string `json:"containers"`

// Determines if the node should forcefully halt at the upgrade height.
// +optional
SetHaltHeight bool `json:"setHaltHeight,omitempty"`
Expand Down
25 changes: 20 additions & 5 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5,202 changes: 2,621 additions & 2,581 deletions config/crd/bases/cosmos.strange.love_cosmosfullnodes.yaml

Large diffs are not rendered by default.

213 changes: 103 additions & 110 deletions config/crd/bases/cosmos.strange.love_scheduledvolumesnapshots.yaml

Large diffs are not rendered by default.

6,466 changes: 3,355 additions & 3,111 deletions config/crd/bases/cosmos.strange.love_statefuljobs.yaml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: manager-role
rules:
- apiGroups:
Expand Down
23 changes: 23 additions & 0 deletions internal/fullnode/build_pods.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,36 @@ func BuildPods(crd *cosmosv1.CosmosFullNode, cksums ConfigChecksums) ([]diff.Res
return pods, nil
}

func setChainContainerImages(pod *corev1.Pod, v *cosmosv1.ChainVersion) {
setChainContainerImage(pod, v.Image)

for name, image := range v.InitContainers {
for i := range pod.Spec.InitContainers {
if pod.Spec.InitContainers[i].Name == name {
pod.Spec.InitContainers[i].Image = image
break
}
}
}

for name, image := range v.Containers {
for i := range pod.Spec.Containers {
if pod.Spec.Containers[i].Name == name {
pod.Spec.Containers[i].Image = image
break
}
}
}
}

func setChainContainerImage(pod *corev1.Pod, image string) {
for i := range pod.Spec.Containers {
if pod.Spec.Containers[i].Name == mainContainer {
pod.Spec.Containers[i].Image = image
break
}
}

for i := range pod.Spec.InitContainers {
if pod.Spec.InitContainers[i].Name == chainInitContainer {
pod.Spec.InitContainers[i].Image = image
Expand Down
22 changes: 12 additions & 10 deletions internal/fullnode/pod_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,22 +181,28 @@ func podReadinessProbes(crd *cosmosv1.CosmosFullNode) []*corev1.Probe {
func (b PodBuilder) Build() (*corev1.Pod, error) {
pod := b.pod.DeepCopy()

if err := kube.ApplyStrategicMergePatch(pod, podPatch(b.crd)); err != nil {
return nil, err
}

if len(b.crd.Spec.ChainSpec.Versions) > 0 {
instanceHeight := uint64(0)
if height, ok := b.crd.Status.Height[pod.Name]; ok {
instanceHeight = height
}
var image string
for _, version := range b.crd.Spec.ChainSpec.Versions {
if instanceHeight < version.UpgradeHeight {
var vrs *cosmosv1.ChainVersion
for _, v := range b.crd.Spec.ChainSpec.Versions {
v := v
if instanceHeight < v.UpgradeHeight {
break
}
image = version.Image
vrs = &v
}
if image != "" {
setChainContainerImage(pod, image)
if vrs != nil {
setChainContainerImages(pod, vrs)
}
}

if o, ok := b.crd.Spec.InstanceOverrides[pod.Name]; ok {
if o.DisableStrategy != nil {
return nil, nil
Expand All @@ -206,10 +212,6 @@ func (b PodBuilder) Build() (*corev1.Pod, error) {
}
}

if err := kube.ApplyStrategicMergePatch(pod, podPatch(b.crd)); err != nil {
return nil, err
}

kube.NormalizeMetadata(&pod.ObjectMeta)
return pod, nil
}
Expand Down
89 changes: 81 additions & 8 deletions internal/fullnode/pod_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -606,27 +606,100 @@ gaiad start --home /home/operator/cosmos`
}
crd.Spec.ChainSpec.Versions = []cosmosv1.ChainVersion{
{
UpgradeHeight: 1,
UpgradeHeight: 0,
Image: "image:v1.0.0",
},
{
UpgradeHeight: 100,
Image: "image:v2.0.0",
},
{
UpgradeHeight: 300,
Image: "image:v3.0.0",
InitContainers: map[string]string{
"chain-init": "chain-init:v3.0.0",
"new-init": "new-init:v3.0.0",
},
Containers: map[string]string{
"new-sidecar": "new-sidecar:v3.0.0",
},
},
{
UpgradeHeight: 400,
Image: "image:v4.0.0",
},
}

crd.Status.Height = map[string]uint64{
"osmosis-0": 1,
"osmosis-1": 150,
"osmosis-2": 300,
}

builder := NewPodBuilder(&crd)
pod, err := builder.WithOrdinal(0).Build()

pod0, err := builder.WithOrdinal(0).Build()
require.NoError(t, err)

containers := lo.SliceToMap(pod.Spec.Containers, func(c corev1.Container) (string, corev1.Container) { return c.Name, c })
containers := lo.SliceToMap(pod0.Spec.Containers, func(c corev1.Container) (string, corev1.Container) { return c.Name, c })
require.ElementsMatch(t, []string{"node", "new-sidecar", "healthcheck", "version-check-interval"}, lo.Keys(containers))
})

test.HasTypeLabel(t, func(crd cosmosv1.CosmosFullNode) []map[string]string {
builder := NewPodBuilder(&crd)
pod, _ := builder.WithOrdinal(5).Build()
return []map[string]string{pod.Labels}
initContainers := lo.SliceToMap(pod0.Spec.InitContainers, func(c corev1.Container) (string, corev1.Container) { return c.Name, c })
require.ElementsMatch(t, []string{"chain-init", "new-init", "genesis-init", "addrbook-init", "config-merge", "version-check", "clean-init"}, lo.Keys(initContainers))

require.Equal(t, "osmosis-0", pod0.Name)

require.Equal(t, "node", pod0.Spec.Containers[0].Name)
require.Equal(t, "image:v1.0.0", pod0.Spec.Containers[0].Image)

require.Equal(t, "chain-init", pod0.Spec.InitContainers[1].Name)
require.Equal(t, "image:v1.0.0", pod0.Spec.InitContainers[1].Image)

pod1, err := builder.WithOrdinal(1).Build()
require.NoError(t, err)

require.Equal(t, "osmosis-1", pod1.Name)

require.Equal(t, "node", pod1.Spec.Containers[0].Name)
require.Equal(t, "image:v2.0.0", pod1.Spec.Containers[0].Image)

require.Equal(t, "chain-init", pod1.Spec.InitContainers[1].Name)
require.Equal(t, "image:v2.0.0", pod1.Spec.InitContainers[1].Image)

pod2, err := builder.WithOrdinal(2).Build()
require.NoError(t, err)

require.Equal(t, "osmosis-2", pod2.Name)

require.Equal(t, "node", pod2.Spec.Containers[0].Name)
require.Equal(t, "image:v3.0.0", pod2.Spec.Containers[0].Image)

require.Equal(t, "new-sidecar", pod2.Spec.Containers[1].Name)
require.Equal(t, "new-sidecar:v3.0.0", pod2.Spec.Containers[1].Image)

require.Equal(t, "chain-init", pod2.Spec.InitContainers[1].Name)
require.Equal(t, "chain-init:v3.0.0", pod2.Spec.InitContainers[1].Image)

require.Equal(t, "new-init", pod2.Spec.InitContainers[2].Name)
require.Equal(t, "new-init:v3.0.0", pod2.Spec.InitContainers[2].Image)

crd.Status.Height["osmosis-2"] = 400
pod2, err = builder.WithOrdinal(2).Build()
require.NoError(t, err)

require.Equal(t, "osmosis-2", pod2.Name)

require.Equal(t, "node", pod2.Spec.Containers[0].Name)
require.Equal(t, "image:v4.0.0", pod2.Spec.Containers[0].Image)

require.Equal(t, "new-sidecar", pod2.Spec.Containers[1].Name)
require.Equal(t, "new-sidecar:latest", pod2.Spec.Containers[1].Image)

require.Equal(t, "chain-init", pod2.Spec.InitContainers[1].Name)
require.Equal(t, "image:v4.0.0", pod2.Spec.InitContainers[1].Image)

require.Equal(t, "new-init", pod2.Spec.InitContainers[2].Name)
require.Equal(t, "new-init:latest", pod2.Spec.InitContainers[2].Image)
})
}

Expand Down
Loading