-
Notifications
You must be signed in to change notification settings - Fork 1.5k
pkg/asset/installconfig/aws/metadata: Store AWS metadata #2512
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
Changes from all commits
49ff49b
d9b87db
e08f50d
68994b7
1b4c1bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| package aws | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "github.com/aws/aws-sdk-go/aws" | ||
| "github.com/aws/aws-sdk-go/aws/session" | ||
| "github.com/aws/aws-sdk-go/service/ec2" | ||
| "github.com/pkg/errors" | ||
| ) | ||
|
|
||
| // availabilityZones retrieves a list of availability zones for the given region. | ||
| func availabilityZones(ctx context.Context, session *session.Session, region string) ([]string, error) { | ||
| client := ec2.New(session, aws.NewConfig().WithRegion(region)) | ||
| resp, err := client.DescribeAvailabilityZonesWithContext(ctx, &ec2.DescribeAvailabilityZonesInput{ | ||
| Filters: []*ec2.Filter{ | ||
| { | ||
| Name: aws.String("region-name"), | ||
| Values: []*string{aws.String(region)}, | ||
| }, | ||
| { | ||
| Name: aws.String("state"), | ||
| Values: []*string{aws.String("available")}, | ||
| }, | ||
| }, | ||
| }) | ||
| if err != nil { | ||
| return nil, errors.Wrap(err, "fetching availability zones") | ||
| } | ||
|
|
||
| zones := []string{} | ||
| for _, zone := range resp.AvailabilityZones { | ||
| zones = append(zones, *zone.ZoneName) | ||
| } | ||
|
|
||
| if len(zones) == 0 { | ||
| return nil, errors.Errorf("no available zones in %s", region) | ||
| } | ||
|
|
||
| return zones, nil | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| // Package aws collects AWS-specific configuration. | ||
| package aws |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| package aws | ||
|
|
||
| import ( | ||
| "context" | ||
| "sync" | ||
|
|
||
| "github.com/aws/aws-sdk-go/aws/session" | ||
| "github.com/pkg/errors" | ||
| ) | ||
|
|
||
| // Metadata holds additional metadata for InstallConfig resources that | ||
| // does not need to be user-supplied (e.g. because it can be retrieved | ||
| // from external APIs). | ||
| type Metadata struct { | ||
| session *session.Session | ||
| availabilityZones []string | ||
| region string | ||
| mutex sync.Mutex | ||
| } | ||
|
|
||
| // NewMetadata initializes a new Metadata object. | ||
| func NewMetadata(region string) *Metadata { | ||
| return &Metadata{region: region} | ||
| } | ||
|
|
||
| // Session holds an AWS session which can be used for AWS API calls | ||
| // during asset generation. | ||
| func (m *Metadata) Session(ctx context.Context) (*session.Session, error) { | ||
| m.mutex.Lock() | ||
| defer m.mutex.Unlock() | ||
|
|
||
| return m.unlockedSession(ctx) | ||
| } | ||
|
|
||
| func (m *Metadata) unlockedSession(ctx context.Context) (*session.Session, error) { | ||
| if m.session == nil { | ||
| var err error | ||
| m.session, err = GetSession() | ||
| if err != nil { | ||
| return nil, errors.Wrap(err, "creating AWS session") | ||
| } | ||
| } | ||
|
|
||
| return m.session, nil | ||
| } | ||
|
|
||
| // AvailabilityZones retrieves a list of availability zones for the configured region. | ||
| func (m *Metadata) AvailabilityZones(ctx context.Context) ([]string, error) { | ||
| m.mutex.Lock() | ||
| defer m.mutex.Unlock() | ||
|
|
||
| if len(m.availabilityZones) == 0 { | ||
| session, err := m.unlockedSession(ctx) | ||
wking marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| m.availabilityZones, err = availabilityZones(ctx, session, m.region) | ||
| if err != nil { | ||
| return nil, errors.Wrap(err, "creating AWS session") | ||
| } | ||
| } | ||
|
|
||
| return m.availabilityZones, nil | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| package aws | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "sort" | ||
| "strings" | ||
|
|
||
| "github.com/openshift/installer/pkg/types/aws" | ||
| "github.com/openshift/installer/pkg/types/aws/validation" | ||
| "github.com/pkg/errors" | ||
| "github.com/sirupsen/logrus" | ||
| survey "gopkg.in/AlecAivazis/survey.v1" | ||
| ) | ||
|
|
||
| // Platform collects AWS-specific configuration. | ||
| func Platform() (*aws.Platform, error) { | ||
| longRegions := make([]string, 0, len(validation.Regions)) | ||
| shortRegions := make([]string, 0, len(validation.Regions)) | ||
| for id, location := range validation.Regions { | ||
| longRegions = append(longRegions, fmt.Sprintf("%s (%s)", id, location)) | ||
| shortRegions = append(shortRegions, id) | ||
| } | ||
| regionTransform := survey.TransformString(func(s string) string { | ||
| return strings.SplitN(s, " ", 2)[0] | ||
| }) | ||
|
|
||
| defaultRegion := "us-east-1" | ||
| _, ok := validation.Regions[defaultRegion] | ||
| if !ok { | ||
| panic(fmt.Sprintf("installer bug: invalid default AWS region %q", defaultRegion)) | ||
| } | ||
|
|
||
| ssn, err := GetSession() | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| defaultRegionPointer := ssn.Config.Region | ||
| if defaultRegionPointer != nil && *defaultRegionPointer != "" { | ||
| _, ok := validation.Regions[*defaultRegionPointer] | ||
| if ok { | ||
| defaultRegion = *defaultRegionPointer | ||
| } else { | ||
| logrus.Warnf("Unrecognized AWS region %q, defaulting to %s", *defaultRegionPointer, defaultRegion) | ||
| } | ||
| } | ||
|
|
||
| sort.Strings(longRegions) | ||
| sort.Strings(shortRegions) | ||
|
|
||
| var region string | ||
| err = survey.Ask([]*survey.Question{ | ||
| { | ||
| Prompt: &survey.Select{ | ||
| Message: "Region", | ||
| Help: "The AWS region to be used for installation.", | ||
| Default: fmt.Sprintf("%s (%s)", defaultRegion, validation.Regions[defaultRegion]), | ||
| Options: longRegions, | ||
| }, | ||
| Validate: survey.ComposeValidators(survey.Required, func(ans interface{}) error { | ||
| choice := regionTransform(ans).(string) | ||
| i := sort.SearchStrings(shortRegions, choice) | ||
| if i == len(shortRegions) || shortRegions[i] != choice { | ||
| return errors.Errorf("invalid region %q", choice) | ||
| } | ||
| return nil | ||
| }), | ||
| Transform: regionTransform, | ||
| }, | ||
| }, ®ion) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return &aws.Platform{ | ||
| Region: region, | ||
| }, nil | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ import ( | |
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
|
|
||
| "github.com/openshift/installer/pkg/asset" | ||
| "github.com/openshift/installer/pkg/asset/installconfig/aws" | ||
| "github.com/openshift/installer/pkg/types" | ||
| "github.com/openshift/installer/pkg/types/conversion" | ||
| "github.com/openshift/installer/pkg/types/defaults" | ||
|
|
@@ -23,6 +24,7 @@ const ( | |
| type InstallConfig struct { | ||
| Config *types.InstallConfig `json:"config"` | ||
| File *asset.File `json:"file"` | ||
| AWS *aws.Metadata | ||
| } | ||
|
|
||
| var _ asset.WritableAsset = (*InstallConfig)(nil) | ||
|
|
@@ -75,23 +77,7 @@ func (a *InstallConfig) Generate(parents asset.Parents) error { | |
| a.Config.GCP = platform.GCP | ||
| a.Config.BareMetal = platform.BareMetal | ||
|
|
||
| if err := a.setDefaults(); err != nil { | ||
| return errors.Wrap(err, "failed to set defaults for install config") | ||
| } | ||
|
|
||
| if err := validation.ValidateInstallConfig(a.Config, openstackvalidation.NewValidValuesFetcher()).ToAggregate(); err != nil { | ||
| return errors.Wrap(err, "invalid install config") | ||
| } | ||
|
|
||
| data, err := yaml.Marshal(a.Config) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would like to keep this part in the asset itself. and
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We currently marshal in
You want
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't care enough. It's fine as is. |
||
| if err != nil { | ||
| return errors.Wrap(err, "failed to Marshal InstallConfig") | ||
| } | ||
| a.File = &asset.File{ | ||
| Filename: installConfigFilename, | ||
| Data: data, | ||
| } | ||
| return nil | ||
| return a.finish("") | ||
| } | ||
|
|
||
| // Name returns the human-friendly name of the asset. | ||
|
|
@@ -124,37 +110,38 @@ func (a *InstallConfig) Load(f asset.FileFetcher) (found bool, err error) { | |
| a.Config = config | ||
|
|
||
| // Upconvert any deprecated fields | ||
| if err := a.convert(); err != nil { | ||
| if err := conversion.ConvertInstallConfig(a.Config); err != nil { | ||
| return false, errors.Wrap(err, "failed to upconvert install config") | ||
| } | ||
|
|
||
| if err := a.setDefaults(); err != nil { | ||
| return false, errors.Wrap(err, "failed to set defaults for install config") | ||
| err = a.finish(installConfigFilename) | ||
| if err != nil { | ||
| return false, err | ||
| } | ||
| return true, nil | ||
| } | ||
|
|
||
| func (a *InstallConfig) finish(filename string) error { | ||
| defaults.SetInstallConfigDefaults(a.Config) | ||
|
|
||
| if a.Config.AWS != nil { | ||
| a.AWS = aws.NewMetadata(a.Config.Platform.AWS.Region) | ||
| } | ||
|
|
||
| if err := validation.ValidateInstallConfig(a.Config, openstackvalidation.NewValidValuesFetcher()).ToAggregate(); err != nil { | ||
| return false, errors.Wrapf(err, "invalid %q file", installConfigFilename) | ||
| if filename == "" { | ||
| return errors.Wrap(err, "invalid install config") | ||
| } | ||
| return errors.Wrapf(err, "invalid %q file", filename) | ||
| } | ||
|
|
||
| data, err := yaml.Marshal(a.Config) | ||
| if err != nil { | ||
| return false, errors.Wrap(err, "failed to Marshal InstallConfig") | ||
| return errors.Wrap(err, "failed to Marshal InstallConfig") | ||
| } | ||
| a.File = &asset.File{ | ||
| Filename: installConfigFilename, | ||
| Data: data, | ||
| } | ||
|
|
||
| return true, nil | ||
| } | ||
|
|
||
| func (a *InstallConfig) setDefaults() error { | ||
| defaults.SetInstallConfigDefaults(a.Config) | ||
| return nil | ||
| } | ||
|
|
||
| // convert converts possibly older versions of the install config to | ||
| // the current version, relocating deprecated fields. | ||
| func (a *InstallConfig) convert() error { | ||
| return conversion.ConvertInstallConfig(a.Config) | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.