// Builds the awsInstance for the EC2 instance on which we are running.
// This is called when the AWSCloud is initialized, and should not be called otherwise (because the awsInstance for the local instance is a singleton with drive mapping state)
547482
func (c *Cloud) buildSelfAWSInstance() (*awsInstance, error) {
	if c.selfAWSInstance != nil {
		panic("do not call buildSelfAWSInstance directly")
	}
	instanceID, err := c.metadata.GetMetadata("instance-id")
	if err != nil {
		return nil, fmt.Errorf("error fetching instance-id from ec2 metadata service: %q", err)
	}

	// We want to fetch the hostname via the EC2 metadata service
	// (`GetMetadata("local-hostname")`): But see #11543 - we need to use
	// the EC2 API to get the privateDnsName in case of a private DNS zone
	// e.g. mydomain.io, because the metadata service returns the wrong
	// hostname.  Once we're doing that, we might as well get all our
	// information from the instance returned by the EC2 API - it is a
	// single API call to get all the information, and it means we don't
	// have two code paths.
	instance, err := c.getInstanceByID(instanceID)
	if err != nil {
		return nil, fmt.Errorf("error finding instance %s: %q", instanceID, err)
	}
	return newAWSInstance(c.ec2, instance), nil
}
1130207
func (vm *VM) Start() error {
	svc, err := getService(vm.Region)
	if err != nil {
		return fmt.Errorf("failed to get AWS service: %v", err)
	}

	if vm.InstanceID == "" {
		// Probably need to call Provision first.
		return ErrNoInstanceID
	}

	_, err = svc.StartInstances(&ec2.StartInstancesInput{
		InstanceIds: []*string{
			aws.String(vm.InstanceID),
		},
		DryRun: aws.Bool(false),
	})
	if err != nil {
		return fmt.Errorf("Failed to start instance: %v", err)
	}

	return nil
}
1328808
func initializeAWSAccount(region string) (*aws.Config, error) {
	cfg, err := external.LoadDefaultAWSConfig()
	if err != nil {
		return nil, fmt.Errorf("Cannot initialize aws connector: %s", err)
	}
	cfg.Region = region
	cfg.LogLevel = awsLogLevel
	return &cfg, nil
}
418720
func readAWSCloudConfig(config io.Reader, metadata EC2Metadata) (*CloudConfig, error) {
	var cfg CloudConfig
	var err error

	if config != nil {
		err = gcfg.ReadInto(&cfg, config)
		if err != nil {
			return nil, err
		}
	}

	if cfg.Global.Zone == "" {
		if metadata != nil {
			glog.Info("Zone not specified in configuration file; querying AWS metadata service")
			cfg.Global.Zone, err = getAvailabilityZone(metadata)
			if err != nil {
				return nil, err
			}
		}
		if cfg.Global.Zone == "" {
			return nil, fmt.Errorf("no zone specified in configuration file")
		}
	}

	return &cfg, nil
}
695256
func (d *driver) createVolume(
	ctx types.Context,
	volumeName, snapshotID string,
	opts *types.VolumeCreateOpts) (*awsec2.Volume, error) {

	var (
		err    error
		server awsec2.Instance
	)
	// Create volume using EC2 API call
	if server, err = d.getInstance(ctx); err != nil {
		return &awsec2.Volume{}, goof.WithError(
			"error creating volume with EC2 API call", err)
	}

	// Fill in Availability Zone if needed
	d.createVolumeEnsureAvailabilityZone(opts, &server)

	options := &awsec2.CreateVolumeInput{
		Size:             opts.Size,
		AvailabilityZone: opts.AvailabilityZone,
		Encrypted:        opts.Encrypted,
		VolumeType:       opts.Type,
	}
	if snapshotID != "" {
		options.SnapshotId = &snapshotID
	}
	if opts.IOPS != nil && *opts.IOPS > 0 {
		options.Iops = opts.IOPS
	}
	if opts.Encrypted != nil && *opts.Encrypted {
		if opts.EncryptionKey != nil && len(*opts.EncryptionKey) > 0 {
			ctx.Debug("creating encrypted volume w client enc key")
			options.KmsKeyId = opts.EncryptionKey
		} else if len(d.kmsKeyID) > 0 {
			ctx.Debug("creating encrypted volume w server enc key")
			options.KmsKeyId = aws.String(d.kmsKeyID)
		} else {
			ctx.Debug("creating encrypted volume w default enc key")
		}
	}

	var resp *awsec2.Volume

	if resp, err = mustSession(ctx).CreateVolume(options); err != nil {
		return &awsec2.Volume{}, goof.WithError(
			"error creating volume", err)
	}

	// Add tags to created volume
	if err = d.createTags(ctx, *resp.VolumeId, volumeName); err != nil {
		return &awsec2.Volume{}, goof.WithError(
			"error creating tags", err)
	}

	// Wait for volume status to change
	if err = d.waitVolumeComplete(
		ctx, *resp.VolumeId, waitVolumeCreate); err != nil {
		return &awsec2.Volume{}, goof.WithError(
			"error waiting for volume creation", err)
	}

	return resp, nil
}
789177
func FindAutoscalingLaunchConfiguration(cloud awsup.AWSCloud, name string) (*autoscaling.LaunchConfiguration, error) {
	glog.V(2).Infof("Retrieving Autoscaling LaunchConfigurations %q", name)

	var results []*autoscaling.LaunchConfiguration

	request := &autoscaling.DescribeLaunchConfigurationsInput{
		LaunchConfigurationNames: []*string{&name},
	}
	err := cloud.Autoscaling().DescribeLaunchConfigurationsPages(request, func(p *autoscaling.DescribeLaunchConfigurationsOutput, lastPage bool) bool {
		for _, t := range p.LaunchConfigurations {
			results = append(results, t)
		}
		return true
	})
	if err != nil {
		return nil, fmt.Errorf("error listing autoscaling LaunchConfigurations: %v", err)
	}

	if len(results) == 0 {
		return nil, nil
	}
	if len(results) != 1 {
		return nil, fmt.Errorf("Found multiple LaunchConfigurations with name %q", name)
	}
	return results[0], nil
}
1299844
func readAWSCloudConfig(config io.Reader) (*CloudConfig, error) {
	var cfg CloudConfig
	var err error

	if config != nil {
		err = gcfg.ReadInto(&cfg, config)
		if err != nil {
			return nil, err
		}
	}

	return &cfg, nil
}
45342
func (e *EC2Metadata) GetAWSUniqueID() (string, error) {
	if e.InstanceID == "" {
		return "", errors.New("unable to build AWSUniqueId (missing InstanceId)")
	}
	if e.AccountID == "" {
		return "", errors.New("unable to build AWSUniqueId (missing AccountId)")
	}
	if e.Region == "" {
		return "", errors.New("unable to build AWSUniqueId (missing Region)")
	}

	return fmt.Sprintf("%s_%s_%s", e.InstanceID, e.Region, e.AccountID), nil
}
454838
func (env *environ) newRawInstance(ctx context.ProviderCallContext, args environs.StartInstanceParams, spec *instances.InstanceSpec) (_ *google.Instance, err error) {

	hostname, err := env.namespace.Hostname(args.InstanceConfig.MachineId)
	if err != nil {
		return nil, common.ZoneIndependentError(err)
	}

	os, err := series.GetOSFromSeries(args.InstanceConfig.Series)
	if err != nil {
		return nil, common.ZoneIndependentError(err)
	}

	metadata, err := getMetadata(args, os)
	if err != nil {
		return nil, common.ZoneIndependentError(err)
	}
	tags := []string{
		env.globalFirewallName(),
		hostname,
	}

	imageURLBase, err := env.imageURLBase(os)
	if err != nil {
		return nil, common.ZoneIndependentError(err)
	}

	disks, err := getDisks(
		spec, args.Constraints,
		args.InstanceConfig.Series,
		env.Config().UUID(),
		imageURLBase,
	)
	if err != nil {
		return nil, common.ZoneIndependentError(err)
	}

	// TODO(ericsnow) Use the env ID for the network name (instead of default)?
	// TODO(ericsnow) Make the network name configurable?
	// TODO(ericsnow) Support multiple networks?
	// TODO(ericsnow) Use a different net interface name? Configurable?
	inst, err := env.gce.AddInstance(google.InstanceSpec{
		ID:                hostname,
		Type:              spec.InstanceType.Name,
		Disks:             disks,
		NetworkInterfaces: []string{"ExternalNAT"},
		Metadata:          metadata,
		Tags:              tags,
		AvailabilityZone:  args.AvailabilityZone,
		// Network is omitted (left empty).
	})
	if err != nil {
		// We currently treat all AddInstance failures
		// as being zone-specific, so we'll retry in
		// another zone.
		return nil, google.HandleCredentialError(errors.Trace(err), ctx)
	}
	return inst, nil
}
363846
func (c *rackspaceConfigurator) GetCloudConfig(args environs.StartInstanceParams) (cloudinit.CloudConfig, error) {
	series := args.Tools.OneSeries()
	cloudcfg, err := cloudinit.New(series)
	if err != nil {
		return nil, errors.Trace(err)
	}
	// Additional package required for sshInstanceConfigurator, to save
	// iptables state between restarts.
	cloudcfg.AddPackage("iptables-persistent")

	if args.InstanceConfig.EnableOSRefreshUpdate {
		// cloud-init often fails to update APT caches
		// during instance startup on RackSpace. Add an
		// extra call to "apt-get update" with a sleep
		// on failure to attempt to alleviate this.
		// See lp:1677425.
		os, err := jujuseries.GetOSFromSeries(series)
		if err == nil && os == jujuos.Ubuntu {
			cloudcfg.AddBootCmd("apt-get update || (sleep 30s; apt-get update)")
		}
	}

	return cloudcfg, nil
}
1003123
func (pool *LoadBalancedPool) GetSingleInstance() (Pool, error) {
	_, instance, _, err := pool.getInstance(nil, 1)
	return instance, err
}
468568
func (a *api) AttachServiceInstance(serviceID string, instanceID int, command string, args []string) error {
	var (
		targetHost      string
		targetContainer string
	)

	hostID, err := utils.HostID()
	if err != nil {
		return err
	}

	client, err := a.connectMaster()
	if err != nil {
		return err
	}

	// get the location of the running instance
	location, err := client.LocateServiceInstance(serviceID, instanceID)
	if err != nil {
		return err
	}

	targetHost = location.HostID
	targetContainer = location.ContainerID

	if command == "" {
		command = "/bin/bash"
	}

	// attach to the container
	if targetHost != hostID {
		cmd, err := a.getSSHCommand(location)
		if err != nil {
			return err
		}
		cmd = append(cmd, []string{"/usr/bin/docker", "exec", "-it", targetContainer}...)

		cmd = append(cmd, command)
		cmd = append(cmd, args...)
		return syscall.Exec(cmd[0], cmd[0:], os.Environ())
	} else {
		cmd := []string{command}
		cmd = append(cmd, args...)
		return utils.AttachAndExec(targetContainer, cmd)
	}
}
672235
func (c *Client) StopServiceInstance(serviceID string, instanceID int) error {
	req := ServiceInstanceRequest{
		ServiceID:  serviceID,
		InstanceID: instanceID,
	}
	err := c.call("StopServiceInstance", req, new(string))
	return err
}
78519
func (e *Environ) StartInstance(ctx context.ProviderCallContext, args environs.StartInstanceParams) (_ *environs.StartInstanceResult, err error) {
	if args.AvailabilityZone != "" {
		// args.AvailabilityZone should only be set if this OpenStack
		// supports zones; validate the zone.
		volumeAttachmentsZone, err := e.volumeAttachmentsZone(args.VolumeAttachments)
		if err != nil {
			common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
			return nil, common.ZoneIndependentError(err)
		}
		if err := validateAvailabilityZoneConsistency(args.AvailabilityZone, volumeAttachmentsZone); err != nil {
			common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
			return nil, common.ZoneIndependentError(err)
		}
		if err := common.ValidateAvailabilityZone(e, ctx, args.AvailabilityZone); err != nil {
			common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
			return nil, errors.Trace(err)
		}
	}

	series := args.Tools.OneSeries()
	arches := args.Tools.Arches()
	spec, err := findInstanceSpec(e, &instances.InstanceConstraint{
		Region:      e.cloud().Region,
		Series:      series,
		Arches:      arches,
		Constraints: args.Constraints,
	}, args.ImageMetadata)
	if err != nil {
		common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
		return nil, common.ZoneIndependentError(err)
	}
	tools, err := args.Tools.Match(tools.Filter{Arch: spec.Image.Arch})
	if err != nil {
		common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
		return nil, common.ZoneIndependentError(
			errors.Errorf("chosen architecture %v not present in %v", spec.Image.Arch, arches),
		)
	}

	if err := args.InstanceConfig.SetTools(tools); err != nil {
		common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
		return nil, common.ZoneIndependentError(err)
	}

	if err := instancecfg.FinishInstanceConfig(args.InstanceConfig, e.Config()); err != nil {
		common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
		return nil, common.ZoneIndependentError(err)
	}
	cloudcfg, err := e.configurator.GetCloudConfig(args)
	if err != nil {
		common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
		return nil, common.ZoneIndependentError(err)
	}
	userData, err := providerinit.ComposeUserData(args.InstanceConfig, cloudcfg, OpenstackRenderer{})
	if err != nil {
		common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
		return nil, common.ZoneIndependentError(errors.Annotate(err, "cannot make user data"))
	}
	logger.Debugf("openstack user data; %d bytes", len(userData))

	networks, err := e.networking.DefaultNetworks()
	if err != nil {
		common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
		return nil, common.ZoneIndependentError(errors.Annotate(err, "getting initial networks"))
	}
	usingNetwork := e.ecfg().network()
	networkId, err := e.networking.ResolveNetwork(usingNetwork, false)
	if err != nil {
		common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
		if usingNetwork == "" {
			// If there is no network configured, we only throw out when the
			// error reports multiple Openstack networks.
			// If there are no Openstack networks at all (such as Canonistack),
			// having no network config is not an error condition.
			if strings.HasPrefix(err.Error(), "multiple networks") {
				return nil, common.ZoneIndependentError(errors.New(noNetConfigMsg(err)))
			}
		} else {
			return nil, common.ZoneIndependentError(err)
		}
	} else {
		logger.Debugf("using network id %q", networkId)
		networks = append(networks, nova.ServerNetworks{NetworkId: networkId})
	}

	machineName := resourceName(
		e.namespace,
		e.name,
		args.InstanceConfig.MachineId,
	)

	if e.ecfg().useOpenstackGBP() {
		client := e.neutron()
		ptArg := neutron.PolicyTargetV2{
			Name:                fmt.Sprintf("juju-policytarget-%s", machineName),
			PolicyTargetGroupId: e.ecfg().policyTargetGroup(),
		}
		pt, err := client.CreatePolicyTargetV2(ptArg)
		if err != nil {
			common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
			return nil, errors.Trace(err)
		}
		networks = append(networks, nova.ServerNetworks{PortId: pt.PortId})
	}

	// For BUG 1680787: openstack: add support for neutron networks where port
	// security is disabled.
	// If any network specified for instance boot has PortSecurityEnabled equals
	// false, don't create security groups, instance boot will fail.
	createSecurityGroups := true
	if len(networks) > 0 && e.supportsNeutron() {
		client := e.neutron()
		for _, n := range networks {
			if n.NetworkId == "" {
				// It's a GBP network.
				continue
			}
			net, err := client.GetNetworkV2(n.NetworkId)
			if err != nil {
				common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
				return nil, common.ZoneIndependentError(err)
			}
			if net.PortSecurityEnabled != nil &&
				*net.PortSecurityEnabled == false {
				createSecurityGroups = *net.PortSecurityEnabled
				logger.Infof("network %q has port_security_enabled set to false. Not using security groups.", net.Id)
				break
			}
		}
	}

	var novaGroupNames = []nova.SecurityGroupName{}
	if createSecurityGroups {
		var apiPort int
		if args.InstanceConfig.Controller != nil {
			apiPort = args.InstanceConfig.Controller.Config.APIPort()
		} else {
			// All ports are the same so pick the first.
			apiPort = args.InstanceConfig.APIInfo.Ports()[0]
		}
		groupNames, err := e.firewaller.SetUpGroups(ctx, args.ControllerUUID, args.InstanceConfig.MachineId, apiPort)
		if err != nil {
			common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
			return nil, common.ZoneIndependentError(errors.Annotate(err, "cannot set up groups"))
		}
		novaGroupNames = make([]nova.SecurityGroupName, len(groupNames))
		for i, name := range groupNames {
			novaGroupNames[i].Name = name
		}
	}

	waitForActiveServerDetails := func(
		client *nova.Client,
		id string,
		timeout time.Duration,
	) (server *nova.ServerDetail, err error) {

		var errStillBuilding = errors.Errorf("instance %q has status BUILD", id)
		err = retry.Call(retry.CallArgs{
			Clock:       e.clock,
			Delay:       10 * time.Second,
			MaxDuration: timeout,
			Func: func() error {
				server, err = client.GetServer(id)
				if err != nil {
					return err
				}
				if server.Status == nova.StatusBuild {
					return errStillBuilding
				}
				return nil
			},
			NotifyFunc: func(lastError error, attempt int) {
				args.StatusCallback(status.Provisioning, fmt.Sprintf("%s, wait 10 seconds before retry, attempt %d", lastError, attempt), nil)
			},
			IsFatalError: func(err error) bool {
				return err != errStillBuilding
			},
		})
		if err != nil {
			common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
			return nil, err
		}
		return server, nil
	}

	tryStartNovaInstance := func(
		attempts utils.AttemptStrategy,
		client *nova.Client,
		instanceOpts nova.RunServerOpts,
	) (server *nova.Entity, err error) {
		for a := attempts.Start(); a.Next(); {
			server, err = client.RunServer(instanceOpts)
			if err != nil {
				common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
				break
			}
			if server == nil {
				logger.Warningf("may have lost contact with nova api while creating instances, some stray instances may be around and need to be deleted")
				break
			}
			var serverDetail *nova.ServerDetail
			serverDetail, err = waitForActiveServerDetails(client, server.Id, 5*time.Minute)
			if err != nil || serverDetail == nil {
				server = nil
				break
			} else if serverDetail.Status == nova.StatusActive {
				break
			} else if serverDetail.Status == nova.StatusError {
				// Perhaps there is an error case where a retry in the same AZ
				// is a good idea.
				faultMsg := " unable to determine fault details"
				if serverDetail.Fault != nil {
					faultMsg = fmt.Sprintf(" with fault %q", serverDetail.Fault.Message)
				} else {
					logger.Debugf("getting active server details from nova failed without fault details")
				}
				logger.Infof("Deleting instance %q in ERROR state%v", server.Id, faultMsg)
				if err = e.terminateInstances(ctx, []instance.Id{instance.Id(server.Id)}); err != nil {
					logger.Debugf("Failed to delete instance in ERROR state, %q", err)
				}
				server = nil
				err = errors.New(faultMsg)
				break
			}
		}
		return server, err
	}

	var opts = nova.RunServerOpts{
		Name:               machineName,
		FlavorId:           spec.InstanceType.Id,
		ImageId:            spec.Image.Id,
		UserData:           userData,
		SecurityGroupNames: novaGroupNames,
		Networks:           networks,
		Metadata:           args.InstanceConfig.Tags,
		AvailabilityZone:   args.AvailabilityZone,
	}
	e.configurator.ModifyRunServerOptions(&opts)

	server, err := tryStartNovaInstance(shortAttempt, e.nova(), opts)
	if err != nil || server == nil {
		common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
		// 'No valid host available' is typically a resource error,
		// let the provisioner know it is a good idea to try another
		// AZ if available.
		err := errors.Annotate(err, "cannot run instance")
		zoneSpecific := isNoValidHostsError(err)
		if !zoneSpecific {
			err = common.ZoneIndependentError(err)
		}
		return nil, err
	}

	detail, err := e.nova().GetServer(server.Id)
	if err != nil {
		common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
		return nil, common.ZoneIndependentError(errors.Annotate(err, "cannot get started instance"))
	}

	inst := &openstackInstance{
		e:            e,
		serverDetail: detail,
		arch:         &spec.Image.Arch,
		instType:     &spec.InstanceType,
	}
	logger.Infof("started instance %q", inst.Id())
	withPublicIP := e.ecfg().useFloatingIP()
	if withPublicIP {
		// If we don't lock here, AllocatePublicIP() can return the same
		// public IP for 2 different instances.  Only one will successfully
		// be assigned the public IP, the other will not have one.
		e.publicIPMutex.Lock()
		defer e.publicIPMutex.Unlock()
		var publicIP *string
		logger.Debugf("allocating public IP address for openstack node")
		if fip, err := e.networking.AllocatePublicIP(inst.Id()); err != nil {
			common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
			return nil, common.ZoneIndependentError(errors.Annotate(err, "cannot allocate a public IP as needed"))
		} else {
			publicIP = fip
			logger.Infof("allocated public IP %s", *publicIP)
		}
		if err := e.assignPublicIP(publicIP, string(inst.Id())); err != nil {
			if err := e.terminateInstances(ctx, []instance.Id{inst.Id()}); err != nil {
				common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
				// ignore the failure at this stage, just log it
				logger.Debugf("failed to terminate instance %q: %v", inst.Id(), err)
			}
			return nil, common.ZoneIndependentError(errors.Annotatef(err,
				"cannot assign public address %s to instance %q",
				*publicIP, inst.Id(),
			))
		}
		inst.floatingIP = publicIP
	}

	return &environs.StartInstanceResult{
		Instance: inst,
		Hardware: inst.hardwareCharacteristics(),
	}, nil
}
958843
func (actor Actor) CreateServiceInstance(spaceGUID, serviceName, servicePlanName, serviceInstanceName, brokerName string, params map[string]interface{}, tags []string) (ServiceInstance, Warnings, error) {
	var allWarnings Warnings
	plan, allWarnings, err := actor.getServicePlanForServiceInSpace(servicePlanName, serviceName, spaceGUID, brokerName)

	if err != nil {
		return ServiceInstance{}, allWarnings, err
	}

	instance, warnings, err := actor.CloudControllerClient.CreateServiceInstance(spaceGUID, plan.GUID, serviceInstanceName, params, tags)
	allWarnings = append(allWarnings, warnings...)
	if err != nil {
		return ServiceInstance{}, allWarnings, err
	}

	return ServiceInstance(instance), allWarnings, nil
}
18038
func NewEc2Storage(instance, instanceType string, ec2 *ec2.EC2) storageops.Ops {
	return &ec2Ops{
		instance:     instance,
		instanceType: instanceType,
		ec2:          ec2,
	}
}
185297
func (b *StorageAclBuilder) Build(c *fi.ModelBuilderContext) error {
	serviceAccount, err := b.Cloud.ServiceAccount()
	if err != nil {
		return fmt.Errorf("error fetching ServiceAccount: %v", err)
	}

	if featureflag.GoogleCloudBucketACL.Enabled() {
		clusterPath := b.Cluster.Spec.ConfigBase
		p, err := vfs.Context.BuildVfsPath(clusterPath)
		if err != nil {
			return fmt.Errorf("cannot parse cluster path %q: %v", clusterPath, err)
		}

		switch p := p.(type) {
		case *vfs.GSPath:
			// It's not ideal that we have to do this at the bucket level,
			// but GCS doesn't seem to have a way to do subtrees (like AWS IAM does)
			// Note this permission only lets us list objects, not read them
			c.AddTask(&gcetasks.StorageBucketAcl{
				Name:      s("serviceaccount-statestore-list"),
				Lifecycle: b.Lifecycle,
				Bucket:    s(p.Bucket()),
				Entity:    s("user-" + serviceAccount),
				Role:      s("READER"),
			})
		}
	}

	glog.Warningf("we need to split master / node roles")
	role := kops.InstanceGroupRoleMaster
	writeablePaths, err := iam.WriteableVFSPaths(b.Cluster, role)
	if err != nil {
		return err
	}

	buckets := sets.NewString()
	for _, p := range writeablePaths {
		if gcsPath, ok := p.(*vfs.GSPath); ok {
			bucket := gcsPath.Bucket()
			if buckets.Has(bucket) {
				continue
			}

			glog.Warningf("adding bucket level write ACL to gs://%s to support etcd backup", bucket)

			c.AddTask(&gcetasks.StorageBucketAcl{
				Name:      s("serviceaccount-backup-readwrite-" + bucket),
				Lifecycle: b.Lifecycle,
				Bucket:    s(bucket),
				Entity:    s("user-" + serviceAccount),
				Role:      s("WRITER"),
			})

			buckets.Insert(bucket)
		} else {
			glog.Warningf("unknown path, can't apply IAM policy: %q", p)
		}
	}

	return nil
}