diff --git a/internal/juju/client.go b/internal/juju/client.go index f6085140..eab2ba6e 100644 --- a/internal/juju/client.go +++ b/internal/juju/client.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "strconv" + "strings" "sync" "time" @@ -21,15 +22,16 @@ import ( ) const ( - PrefixCloud = "cloud-" - PrefixModel = "model-" - PrefixCharm = "charm-" - PrefixUser = "user-" - PrefixMachine = "machine-" - PrefixApplication = "application-" - PrefixStorage = "storage-" - UnspecifiedRevision = -1 - connectionTimeout = 30 * time.Second + PrefixCloud = "cloud-" + PrefixModel = "model-" + PrefixCharm = "charm-" + PrefixUser = "user-" + PrefixMachine = "machine-" + PrefixApplication = "application-" + PrefixStorage = "storage-" + UnspecifiedRevision = -1 + connectionTimeout = 30 * time.Second + serviceAccountSuffix = "@serviceaccount" ) type ControllerConfiguration struct { @@ -54,7 +56,8 @@ type Client struct { Secrets secretsClient Jaas jaasClient - isJAAS func() bool + isJAAS func() bool + username string } // IsJAAS returns a boolean to indicate whether the controller configured is a JAAS controller. @@ -63,6 +66,12 @@ func (c Client) IsJAAS() bool { return c.isJAAS() } +// Username returns the username specified in the Juju provider or, if specified, the +// service account username. +func (c Client) Username() string { + return c.username +} + type jujuModel struct { name string modelType model.ModelType @@ -104,6 +113,11 @@ func NewClient(ctx context.Context, config ControllerConfiguration) (*Client, er defaultJAASCheck = true } + user := config.Username + if config.ClientID != "" && !strings.HasSuffix(config.ClientID, serviceAccountSuffix) { + user = fmt.Sprintf("%s%s", config.ClientID, serviceAccountSuffix) + } + return &Client{ Applications: *newApplicationClient(sc), Clouds: *newKubernetesCloudsClient(sc), @@ -117,6 +131,7 @@ func NewClient(ctx context.Context, config ControllerConfiguration) (*Client, er Secrets: *newSecretsClient(sc), Jaas: *newJaasClient(sc), isJAAS: func() bool { return sc.IsJAAS(defaultJAASCheck) }, + username: user, }, nil } diff --git a/internal/juju/offers.go b/internal/juju/offers.go index b8428417..eb2fb973 100644 --- a/internal/juju/offers.go +++ b/internal/juju/offers.go @@ -36,6 +36,7 @@ type CreateOfferInput struct { Endpoint string ModelName string ModelOwner string + OfferOwner string Name string } @@ -117,7 +118,8 @@ func (c offersClient) CreateOffer(input *CreateOfferInput) (*CreateOfferResponse if err != nil { return nil, append(errs, err) } - result, err := client.Offer(modelUUID, input.ApplicationName, []string{input.Endpoint}, "admin", offerName, "") + + result, err := client.Offer(modelUUID, input.ApplicationName, []string{input.Endpoint}, input.OfferOwner, offerName, "") if err != nil { return nil, append(errs, err) } diff --git a/internal/juju/sshKeys.go b/internal/juju/sshKeys.go index 3122ac74..78b1744b 100644 --- a/internal/juju/sshKeys.go +++ b/internal/juju/sshKeys.go @@ -17,11 +17,13 @@ type sshKeysClient struct { } type CreateSSHKeyInput struct { + Username string ModelName string Payload string } type ReadSSHKeyInput struct { + Username string ModelName string KeyIdentifier string } @@ -32,6 +34,7 @@ type ReadSSHKeyOutput struct { } type DeleteSSHKeyInput struct { + Username string ModelName string KeyIdentifier string } @@ -53,7 +56,7 @@ func (c *sshKeysClient) CreateSSHKey(input *CreateSSHKeyInput) error { // NOTE // Juju only stores ssh keys at a global level. - params, err := client.AddKeys("admin", input.Payload) + params, err := client.AddKeys(input.Username, input.Payload) if err != nil { return err } @@ -85,7 +88,7 @@ func (c *sshKeysClient) ReadSSHKey(input *ReadSSHKeyInput) (*ReadSSHKeyOutput, e // NOTE: At this moment Juju only uses global ssh keys. // We hardcode the user to be admin. - returnedKeys, err := client.ListKeys(ssh.FullKeys, "admin") + returnedKeys, err := client.ListKeys(ssh.FullKeys, input.Username) if err != nil { return nil, err } @@ -118,7 +121,7 @@ func (c *sshKeysClient) DeleteSSHKey(input *DeleteSSHKeyInput) error { // that impacts the current Juju logic. As a temporal workaround // we will check if this is the latest SSH key of this model and // skip the delete. - returnedKeys, err := client.ListKeys(ssh.FullKeys, "admin") + returnedKeys, err := client.ListKeys(ssh.FullKeys, input.Username) if err != nil { return err } @@ -133,7 +136,7 @@ func (c *sshKeysClient) DeleteSSHKey(input *DeleteSSHKeyInput) error { } // NOTE: Right now Juju uses global users for keys - params, err := client.DeleteKeys("admin", input.KeyIdentifier) + params, err := client.DeleteKeys(input.Username, input.KeyIdentifier) if len(params) != 0 { messages := make([]string, 0) for _, e := range params { diff --git a/internal/provider/resource_offer.go b/internal/provider/resource_offer.go index 34dc822e..fcf65e25 100644 --- a/internal/provider/resource_offer.go +++ b/internal/provider/resource_offer.go @@ -143,6 +143,7 @@ func (o *offerResource) Create(ctx context.Context, req resource.CreateRequest, Name: offerName, ApplicationName: plan.ApplicationName.ValueString(), Endpoint: plan.EndpointName.ValueString(), + OfferOwner: o.client.Username(), }) if errs != nil { // TODO 10-Aug-2023 diff --git a/internal/provider/resource_ssh_key.go b/internal/provider/resource_ssh_key.go index 8e3dbe4e..2e563fb0 100644 --- a/internal/provider/resource_ssh_key.go +++ b/internal/provider/resource_ssh_key.go @@ -122,6 +122,7 @@ func (s *sshKeyResource) Create(ctx context.Context, req resource.CreateRequest, modelName := plan.ModelName.ValueString() if err := s.client.SSHKeys.CreateSSHKey(&juju.CreateSSHKeyInput{ + Username: s.client.Username(), ModelName: modelName, Payload: payload, }); err != nil { @@ -173,6 +174,7 @@ func (s *sshKeyResource) Read(ctx context.Context, req resource.ReadRequest, res } result, err := s.client.SSHKeys.ReadSSHKey(&juju.ReadSSHKeyInput{ + Username: s.client.Username(), ModelName: modelName, KeyIdentifier: keyIdentifier, }) @@ -221,6 +223,7 @@ func (s *sshKeyResource) Update(ctx context.Context, req resource.UpdateRequest, // Delete the key if err := s.client.SSHKeys.DeleteSSHKey(&juju.DeleteSSHKeyInput{ + Username: s.client.Username(), ModelName: modelName, KeyIdentifier: keyIdentifier, }); err != nil { @@ -231,6 +234,7 @@ func (s *sshKeyResource) Update(ctx context.Context, req resource.UpdateRequest, // Create a new key if err := s.client.SSHKeys.CreateSSHKey(&juju.CreateSSHKeyInput{ + Username: s.client.Username(), ModelName: plan.ModelName.ValueString(), Payload: plan.Payload.ValueString(), }); err != nil { @@ -274,6 +278,7 @@ func (s *sshKeyResource) Delete(ctx context.Context, req resource.DeleteRequest, // Delete the key if err := s.client.SSHKeys.DeleteSSHKey(&juju.DeleteSSHKeyInput{ + Username: s.client.Username(), ModelName: modelName, KeyIdentifier: keyIdentifier, }); err != nil {