Add image update API and use for "upgrade plan"

This commit is contained in:
Malte Poll 2022-11-29 11:39:07 +01:00 committed by Malte Poll
parent 954cbad214
commit ebf852b3ba
9 changed files with 806 additions and 394 deletions

View file

@ -66,18 +66,18 @@ func NewUpgrader(outWriter io.Writer) (*Upgrader, error) {
}
// Upgrade upgrades the cluster to the given measurements and image.
func (u *Upgrader) Upgrade(ctx context.Context, image string, measurements measurements.M) error {
func (u *Upgrader) Upgrade(ctx context.Context, imageReference, imageVersion string, measurements measurements.M) error {
if err := u.updateMeasurements(ctx, measurements); err != nil {
return fmt.Errorf("updating measurements: %w", err)
}
if err := u.updateImage(ctx, image); err != nil {
if err := u.updateImage(ctx, imageReference, imageVersion); err != nil {
return fmt.Errorf("updating image: %w", err)
}
return nil
}
// GetCurrentImage returns the currently used image of the cluster.
// GetCurrentImage returns the currently used image version of the cluster.
func (u *Upgrader) GetCurrentImage(ctx context.Context) (*unstructured.Unstructured, string, error) {
imageStruct, err := u.dynamicInterface.getCurrent(ctx, "constellation-os")
if err != nil {
@ -93,16 +93,16 @@ func (u *Upgrader) GetCurrentImage(ctx context.Context) (*unstructured.Unstructu
if !ok {
return nil, "", retErr
}
currentImageDefinition, ok := specMap["image"]
currentImageVersion, ok := specMap["imageVersion"]
if !ok {
return nil, "", retErr
}
imageDefinition, ok := currentImageDefinition.(string)
imageVersion, ok := currentImageVersion.(string)
if !ok {
return nil, "", retErr
}
return imageStruct, imageDefinition, nil
return imageStruct, imageVersion, nil
}
// CurrentHelmVersion returns the version of the currently installed helm release.
@ -154,18 +154,19 @@ func (u *Upgrader) updateMeasurements(ctx context.Context, newMeasurements measu
return nil
}
func (u *Upgrader) updateImage(ctx context.Context, image string) error {
currentImage, currentImageDefinition, err := u.GetCurrentImage(ctx)
func (u *Upgrader) updateImage(ctx context.Context, imageReference, imageVersion string) error {
currentImage, currentImageVersion, err := u.GetCurrentImage(ctx)
if err != nil {
return fmt.Errorf("retrieving current image: %w", err)
}
if currentImageDefinition == image {
if currentImageVersion == imageVersion {
fmt.Fprintln(u.outWriter, "Cluster is already using the chosen image, skipping image upgrade")
return nil
}
currentImage.Object["spec"].(map[string]any)["image"] = image
currentImage.Object["spec"].(map[string]any)["image"] = imageReference
currentImage.Object["spec"].(map[string]any)["imageVersion"] = imageVersion
if _, err := u.dynamicInterface.update(ctx, currentImage); err != nil {
return fmt.Errorf("setting new image: %w", err)
}

View file

@ -149,35 +149,40 @@ func (u *stubClientInterface) kubernetesVersion() (string, error) {
func TestUpdateImage(t *testing.T) {
someErr := errors.New("error")
testCases := map[string]struct {
updater *stubImageUpdater
newImage string
wantUpdate bool
wantErr bool
updater *stubImageUpdater
newImageReference string
newImageVersion string
wantUpdate bool
wantErr bool
}{
"success": {
updater: &stubImageUpdater{
setImage: &unstructured.Unstructured{
Object: map[string]any{
"spec": map[string]any{
"image": "old-image",
"image": "old-image-ref",
"imageVersion": "old-image-ver",
},
},
},
},
newImage: "new-image",
wantUpdate: true,
newImageReference: "new-image-ref",
newImageVersion: "new-image-ver",
wantUpdate: true,
},
"image is the same": {
updater: &stubImageUpdater{
setImage: &unstructured.Unstructured{
Object: map[string]any{
"spec": map[string]any{
"image": "old-image",
"image": "old-image-ref",
"imageVersion": "old-image-ver",
},
},
},
},
newImage: "old-image",
newImageReference: "old-image-ref",
newImageVersion: "old-image-ver",
},
"getCurrent error": {
updater: &stubImageUpdater{getErr: someErr},
@ -188,14 +193,16 @@ func TestUpdateImage(t *testing.T) {
setImage: &unstructured.Unstructured{
Object: map[string]any{
"spec": map[string]any{
"image": "old-image",
"image": "old-image-ref",
"imageVersion": "old-image-ver",
},
},
},
updateErr: someErr,
},
newImage: "new-image",
wantErr: true,
newImageReference: "new-image-ref",
newImageVersion: "new-image-ver",
wantErr: true,
},
"no spec": {
updater: &stubImageUpdater{
@ -203,8 +210,9 @@ func TestUpdateImage(t *testing.T) {
Object: map[string]any{},
},
},
newImage: "new-image",
wantErr: true,
newImageReference: "new-image-ref",
newImageVersion: "new-image-ver",
wantErr: true,
},
"not a map": {
updater: &stubImageUpdater{
@ -214,8 +222,9 @@ func TestUpdateImage(t *testing.T) {
},
},
},
newImage: "new-image",
wantErr: true,
newImageReference: "new-image-ref",
newImageVersion: "new-image-ver",
wantErr: true,
},
"no spec.image": {
updater: &stubImageUpdater{
@ -225,8 +234,9 @@ func TestUpdateImage(t *testing.T) {
},
},
},
newImage: "new-image",
wantErr: true,
newImageReference: "new-image-ref",
newImageVersion: "new-image-ver",
wantErr: true,
},
}
@ -239,7 +249,7 @@ func TestUpdateImage(t *testing.T) {
outWriter: &bytes.Buffer{},
}
err := upgrader.updateImage(context.Background(), tc.newImage)
err := upgrader.updateImage(context.Background(), tc.newImageReference, tc.newImageVersion)
if tc.wantErr {
assert.Error(err)
@ -248,7 +258,8 @@ func TestUpdateImage(t *testing.T) {
assert.NoError(err)
if tc.wantUpdate {
assert.Equal(tc.newImage, tc.updater.updatedImage.Object["spec"].(map[string]any)["image"])
assert.Equal(tc.newImageReference, tc.updater.updatedImage.Object["spec"].(map[string]any)["image"])
assert.Equal(tc.newImageVersion, tc.updater.updatedImage.Object["spec"].(map[string]any)["imageVersion"])
} else {
assert.Nil(tc.updater.updatedImage)
}