diff --git a/builder/ucloud/uhost/access_config.go b/builder/ucloud/uhost/access_config.go index 101da2561..ae1f074cc 100644 --- a/builder/ucloud/uhost/access_config.go +++ b/builder/ucloud/uhost/access_config.go @@ -85,6 +85,22 @@ func (c *AccessConfig) Config() error { } +func (c *AccessConfig) ValidateProjectId(projectId string) error { + + supportedProjectIds, err := c.getSupportedProjectIds() + if err != nil { + return err + } + + for _, supportedProjectId := range supportedProjectIds { + if projectId == supportedProjectId { + return nil + } + } + + return fmt.Errorf("%q is invalid, should be an valid ucloud project_id, got %q", "project_id", projectId) +} + func (c *AccessConfig) ValidateRegion(region string) error { supportedRegions, err := c.getSupportedRegions() @@ -98,7 +114,7 @@ func (c *AccessConfig) ValidateRegion(region string) error { } } - return fmt.Errorf("%q is valid, should be an valid ucloud region, got %q", "region", region) + return fmt.Errorf("%q is invalid, should be an valid ucloud region, got %q", "region", region) } func (c *AccessConfig) ValidateZone(region, zone string) error { @@ -114,7 +130,30 @@ func (c *AccessConfig) ValidateZone(region, zone string) error { } } - return fmt.Errorf("%q is valid, should be an valid ucloud zone, got %q", "availability_zone", zone) + return fmt.Errorf("%q is invalid, should be an valid ucloud zone, got %q", "availability_zone", zone) +} + +func (c *AccessConfig) getSupportedProjectIds() ([]string, error) { + client, err := c.Client() + conn := client.uaccountconn + if err != nil { + return nil, err + } + + req := conn.NewGetProjectListRequest() + resp, err := conn.GetProjectList(req) + if err != nil { + return nil, err + } + + validProjectIds := make([]string, len(resp.ProjectSet)) + for _, val := range resp.ProjectSet { + if !isStringIn(val.ProjectId, validProjectIds) { + validProjectIds = append(validProjectIds, val.ProjectId) + } + } + + return validProjectIds, nil } func (c *AccessConfig) getSupportedRegions() ([]string, error) { diff --git a/builder/ucloud/uhost/builder.go b/builder/ucloud/uhost/builder.go index 5f5aae2de..3ec4393bb 100644 --- a/builder/ucloud/uhost/builder.go +++ b/builder/ucloud/uhost/builder.go @@ -77,6 +77,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack // Build the steps steps = []multistep.Step{ &stepPreValidate{ + ProjectId: b.config.ProjectId, Region: b.config.Region, Zone: b.config.Zone, ImageDestinations: b.config.ImageDestinations, diff --git a/builder/ucloud/uhost/step_pre_validate.go b/builder/ucloud/uhost/step_pre_validate.go index 01fc38c71..5c578d08a 100644 --- a/builder/ucloud/uhost/step_pre_validate.go +++ b/builder/ucloud/uhost/step_pre_validate.go @@ -7,12 +7,17 @@ import ( ) type stepPreValidate struct { + ProjectId string Region string Zone string ImageDestinations []ImageDestination } func (s *stepPreValidate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { + if err := s.validateProjectIds(state); err != nil { + return halt(state, err, "") + } + if err := s.validateRegions(state); err != nil { return halt(state, err, "") } @@ -24,6 +29,30 @@ func (s *stepPreValidate) Run(ctx context.Context, state multistep.StateBag) mul return multistep.ActionContinue } +func (s *stepPreValidate) validateProjectIds(state multistep.StateBag) error { + ui := state.Get("ui").(packer.Ui) + config := state.Get("config").(*Config) + + ui.Say("Validating project_id and copied project_ids...") + + var errs *packer.MultiError + if err := config.ValidateProjectId(s.ProjectId); err != nil { + errs = packer.MultiErrorAppend(errs, err) + } + + for _, imageDestination := range s.ImageDestinations { + if err := config.ValidateProjectId(imageDestination.ProjectId); err != nil { + errs = packer.MultiErrorAppend(errs, err) + } + } + + if errs != nil && len(errs.Errors) > 0 { + return errs + } + + return nil +} + func (s *stepPreValidate) validateRegions(state multistep.StateBag) error { ui := state.Get("ui").(packer.Ui) config := state.Get("config").(*Config) diff --git a/go.mod b/go.mod index 77f959adf..3359cad79 100644 --- a/go.mod +++ b/go.mod @@ -117,7 +117,7 @@ require ( golang.org/x/sync v0.0.0-20190423024810-112230192c58 golang.org/x/sys v0.0.0-20190425145619-16072639606e golang.org/x/text v0.3.1 // indirect - golang.org/x/tools v0.0.0-20190612232758-d4e310b4a8a5 // indirect + golang.org/x/tools v0.0.0-20190613204242-ed0dc450797f // indirect google.golang.org/api v0.3.1 google.golang.org/grpc v1.19.1 gopkg.in/h2non/gock.v1 v1.0.12 // indirect diff --git a/go.sum b/go.sum index 8eee8a358..27be84e5b 100644 --- a/go.sum +++ b/go.sum @@ -511,6 +511,8 @@ golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b h1:/mJ+GKieZA6hFDQGdWZrjj4 golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190612232758-d4e310b4a8a5 h1:WfRBLVK37R+k1gUOKuZX8JtangyEXmuopHz5tazlZRo= golang.org/x/tools v0.0.0-20190612232758-d4e310b4a8a5/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190613204242-ed0dc450797f h1:+zypR5600WBcnJgA2nzZAsBlM8cArEGa8dhhiNE4u3w= +golang.org/x/tools v0.0.0-20190613204242-ed0dc450797f/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0 h1:K6z2u68e86TPdSdefXdzvXgR1zEMa+459vBSfWYAZkI= diff --git a/website/source/docs/builders/ucloud-uhost.html.md b/website/source/docs/builders/ucloud-uhost.html.md index faa0cbdac..328dbaa81 100644 --- a/website/source/docs/builders/ucloud-uhost.html.md +++ b/website/source/docs/builders/ucloud-uhost.html.md @@ -17,8 +17,6 @@ customized images based on an existing base images. This builder builds an UCloud image by launching an UHost instance from a source image, provisioning that running machine, and then creating an image from that machine. -\~> **Note:** This builder only support ssh authenticating with username and given password. - ## Configuration Reference The following configuration options available for building UCloud images. They are @@ -28,6 +26,8 @@ In addition to the options listed here, a [communicator](../templates/communicator.html) can be configured for this builder. +\~> **Note:** This builder only support ssh authenticating with username and given password. + ### Required: - `public_key` - (string) This is the UCloud public key. It must be provided, but it can also be sourced from the `UCLOUD_PUBLIC_KEY` environment variable.