diff --git a/state/migration_export.go b/state/migration_export.go index c13557079922..a992a7edd98b 100644 --- a/state/migration_export.go +++ b/state/migration_export.go @@ -129,10 +129,15 @@ func (st *State) exportImpl(cfg ExportConfig) (description.Model, error) { return nil, errors.Trace(err) } + region, err := deriveCloudRegion(dbModel) + if err != nil { + return nil, errors.Annotate(err, "deriving cloud region") + } + args := description.ModelArgs{ Type: string(dbModel.Type()), Cloud: dbModel.CloudName(), - CloudRegion: dbModel.CloudRegion(), + CloudRegion: region, Owner: dbModel.Owner(), Config: modelConfig.Settings, PasswordHash: dbModel.doc.PasswordHash, @@ -246,6 +251,30 @@ func (st *State) exportImpl(cfg ExportConfig) (description.Model, error) { return export.model, nil } +// deriveCloudRegion accommodates migration of the model's cloud region +// for legacy Oracle models that derived region from credentials. +// If this model is on OCI and its credential has a region attribute, +// we'll use that. Otherwise, it's the model's region as usual. +func deriveCloudRegion(m *Model) (string, error) { + cloud, err := m.Cloud() + if err != nil { + return "", errors.Trace(err) + } + + if cloud.Type == "oci" { + cred, _, err := m.CloudCredential() + if err != nil { + return "", errors.Trace(err) + } + + if region := cred.Attributes["region"]; region != "" { + return region, nil + } + } + + return m.CloudRegion(), nil +} + // ExportStateMigration defines a migration for exporting various entities into // a destination description model from the source state. // It accumulates a series of migrations to run at a later time. diff --git a/state/migration_export_test.go b/state/migration_export_test.go index 85248e76c3c5..7d9b725c12ab 100644 --- a/state/migration_export_test.go +++ b/state/migration_export_test.go @@ -6,6 +6,7 @@ package state_test import ( "bytes" "fmt" + "github.com/juju/juju/cloud" "io/ioutil" "math/rand" "time" @@ -220,6 +221,29 @@ func (s *MigrationExportSuite) TestModelInfo(c *gc.C) { }) } +func (s *MigrationExportSuite) TestModelRegionForOCICLoud(c *gc.C) { + cl, err := s.Model.Cloud() + c.Assert(err, jc.ErrorIsNil) + + cl.Type = "oci" + err = s.State.UpdateCloud(cl) + c.Assert(err, jc.ErrorIsNil) + + tag := names.NewCloudCredentialTag(fmt.Sprintf("%s/owner/name", cl.Name)) + err = s.State.UpdateCloudCredential(tag, cloud.NewCredential(cloud.EmptyAuthType, map[string]string{ + "region": "nether", + })) + c.Assert(err, jc.ErrorIsNil) + + _, err = s.Model.SetCloudCredential(tag) + c.Assert(err, jc.ErrorIsNil) + + model, err := s.State.Export() + c.Assert(err, jc.ErrorIsNil) + + c.Check(model.CloudRegion(), gc.Equals, "nether") +} + func (s *MigrationExportSuite) TestModelUsers(c *gc.C) { // Make sure we have some last connection times for the admin user, // and create a few other users.