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

feat(update-app-base): add support to update base for application charms #652

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

SimoneDutto
Copy link
Contributor

@SimoneDutto SimoneDutto commented Jan 7, 2025

Description

This PR adds support to update the base in application charms by requiring a replace in case of a machine charm, and perform the upgrade in case of a k8s charm.

Fixes: re #635

Type of change

  • Add support to update base for application charms

QA Steps

LXD

terraform {
  required_providers {
    juju = {
      version = "~> 0.15.0"
      source  = "juju/juju"
    }
  }
}

provider "juju" {
  controller_addresses = "10.229.36.127:17070"

  username = "admin"
  password = <redacted>

  ca_certificate = file("ca.crt")
}

resource "juju_model" "this" {
  name = "test-model"
}

resource "juju_application" "this" {
  model = juju_model.this.name
  name  = "test-app"
  charm {
    name = "ubuntu"
    base = "[email protected]"
  }
}

terraform apply
juju status and you should see base=22.04

Now update the base

resource "juju_application" "this" {
  model = juju_model.this.name
  name  = "test-app"
  charm {
    name = "ubuntu"
    base = "[email protected]"
  }
}

terraform plan and you should see ~ base = "[email protected]" -> "[email protected]" # forces replacement
terraform apply
Now we have two scenarios:

  • happy (maybe just in the tests): the changes go though and you now have your new charm with the updated charm.
  • sad: terraform tries to recreate the application before it was destroyed and errors out. If you rerun it, you now have your updated charm.
    juju status and you should see base=20.04

Microk8s

terraform {
  required_providers {
    juju = {
      version = "~> 0.15.0"
      source  = "juju/juju"
    }
  }
}

provider "juju" {
  controller_addresses = "10.152.183.78:17070"

  username = "admin"
  password = "<redacted>"

  ca_certificate = file("ca.crt")
}

resource "juju_model" "this" {
  name = "test-model"
}

resource "juju_application" "this" {
  model = juju_model.this.name
  name  = "test-app"
  charm {
    name    = "coredns"
    base    = "[email protected]"
    channel = "1.25/stable"
  }
}

terraform apply
juju show-application test-app -> check base ubuntu 22.04
Update plan

resource "juju_application" "this" {
  model = juju_model.this.name
  name  = "test-app"
  charm {
    name    = "coredns"
    base    = "[email protected]"
    channel = "1.25/stable"
  }
}

terraform plan -> check that the plan doesn't require replace.
terraform apply
juju show-application test-app -> check base ubuntu 20.04

@SimoneDutto SimoneDutto force-pushed the fix-change-base branch 2 times, most recently from cec578d to 19c361e Compare January 7, 2025 13:04
@SimoneDutto SimoneDutto requested a review from hmlanigan January 7, 2025 15:42
@SimoneDutto SimoneDutto requested a review from hmlanigan January 15, 2025 11:32
@alesstimec alesstimec added the state/codefreeze this pr cannot land until the code freeze has lifted. label Jan 20, 2025
@SimoneDutto SimoneDutto force-pushed the fix-change-base branch 2 times, most recently from 804ac33 to 5431e7c Compare January 22, 2025 14:43
Copy link
Member

@hmlanigan hmlanigan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're on the right track, just a few details to iron out.

The commit message should include WHY were fixing the bug the way it's being fixed.

internal/juju/applications.go Outdated Show resolved Hide resolved
internal/provider/modifer_applicationbaseupdate.go Outdated Show resolved Hide resolved
Comment on lines 1382 to 1397
} else if input.Base != "" {
base, err := corebase.ParseBaseFromString(input.Base)
if err != nil {
return nil, err
}
newOrigin.Base = base
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment: It may be okay, to not consider the revision and base together, in this if statement. When we resolve a charm by revision, the base is ignored by the upstream server.

internal/juju/applications.go Outdated Show resolved Hide resolved
Comment on lines 1415 to 1422
} else if input.Base != "" {
oldOrigin.Base = newOrigin.Base
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: This means that the revision and the base cannot change at the same time. Given that every charm revision has only 1 base, that is a problem when refreshing by revision rather than channel.

Take a look at line 1401 as well:

if !basesContain(oldOrigin.Base, supportedBases)

It's validating that the new potential charm supports the old base - which will cause problems if the base is being changed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i've moved base's ifs to a separate block.

Btw, the charmhub view is misleading because it seems that a revision can have multiple bases. (an example can be found here: https://charmhub.io/coredns).
image

Copy link
Contributor Author

@SimoneDutto SimoneDutto Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i've done one more qa test on my machine:
(microk8s)
from

resource "juju_application" "this" {
  model = juju_model.this.name
  name  = "test-app"
  charm {
    name     = "coredns"
    base     = "[email protected]"
    revision = 33
  }
}

to

resource "juju_application" "this" {
  model = juju_model.this.name
  name  = "test-app"
  charm {
    name     = "coredns"
    base     = "[email protected]"
    revision = 145
  }
}

and now works.

@@ -590,6 +605,7 @@ func (r *applicationResource) Create(ctx context.Context, req resource.CreateReq
plan.Placement = types.StringValue(readResp.Placement)
plan.Principal = types.BoolNull()
plan.ApplicationName = types.StringValue(createResp.AppName)
plan.ModelType = types.StringValue(modelType.String())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it doesn't have any ValueString. It's a struct from the juju lib, it only has a String() method

@@ -692,6 +708,12 @@ func (r *applicationResource) Read(ctx context.Context, req resource.ReadRequest
}
r.trace("read application", map[string]interface{}{"resource": appName, "response": response})

modelType, err := r.client.Applications.ModelType(modelName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: While technically harmless, this value should really be included in the CreateApplicationResponse and ReadApplicationResponse structures, rather than making a second call in each place. We're trying to keep a cleaner distinction between what the provider has to know and juju or other details.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i've add to both structs ModelType

Comment on lines 21 to 31
if req.State.Raw.IsKnown() {
var state applicationResourceModel
diags := req.State.Get(ctx, &state)
if diags.HasError() {
resp.Diagnostics.Append(diags...)
return
}
modelType := state.ModelType.ValueString()
resp.RequiresReplace = modelType == model.IAAS.String()
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment: Checking IfKnown on all of state is good. Though you've asked it of ALL the saved state is known. Which maybe too broad a question? I'd ask if the specific element IsKnown instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i've now moved it to ask for the model type specifically.

@SimoneDutto SimoneDutto force-pushed the fix-change-base branch 2 times, most recently from e04c126 to 963a08e Compare January 23, 2025 10:55
…harms

This PR adds support to update the base in application charms by requiring a replace in case of a
machine charm, and perform the upgrade in case of a k8s charm.

We add the model_type computed field on the application schema, and we
use it to make a decision in the planmodifier RequiresReplaceIf.

re juju#635
Copy link
Member

@hmlanigan hmlanigan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shaped up nicely.

Please let the code freeze end before merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
state/codefreeze this pr cannot land until the code freeze has lifted.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants