Commit 8f237b7b authored by Matt Page's avatar Matt Page

Allow specifying project for source images in GCE

Within GCE, images may be shared across projects. Prior to this
commit, there was no way to inform the GCE builder that a source
image belonged to a specific project. This adds an optional
'source_image_project_id' key to the GCE builder config.
parent 70cc5551
...@@ -16,25 +16,26 @@ import ( ...@@ -16,25 +16,26 @@ import (
type Config struct { type Config struct {
common.PackerConfig `mapstructure:",squash"` common.PackerConfig `mapstructure:",squash"`
BucketName string `mapstructure:"bucket_name"` BucketName string `mapstructure:"bucket_name"`
ClientSecretsFile string `mapstructure:"client_secrets_file"` ClientSecretsFile string `mapstructure:"client_secrets_file"`
DiskSizeGb int64 `mapstructure:"disk_size"` DiskSizeGb int64 `mapstructure:"disk_size"`
ImageName string `mapstructure:"image_name"` ImageName string `mapstructure:"image_name"`
ImageDescription string `mapstructure:"image_description"` ImageDescription string `mapstructure:"image_description"`
InstanceName string `mapstructure:"instance_name"` InstanceName string `mapstructure:"instance_name"`
MachineType string `mapstructure:"machine_type"` MachineType string `mapstructure:"machine_type"`
Metadata map[string]string `mapstructure:"metadata"` Metadata map[string]string `mapstructure:"metadata"`
Network string `mapstructure:"network"` Network string `mapstructure:"network"`
Passphrase string `mapstructure:"passphrase"` Passphrase string `mapstructure:"passphrase"`
PrivateKeyFile string `mapstructure:"private_key_file"` PrivateKeyFile string `mapstructure:"private_key_file"`
ProjectId string `mapstructure:"project_id"` ProjectId string `mapstructure:"project_id"`
SourceImage string `mapstructure:"source_image"` SourceImage string `mapstructure:"source_image"`
SSHUsername string `mapstructure:"ssh_username"` SourceImageProjectId string `mapstructure:"source_image_project_id"`
SSHPort uint `mapstructure:"ssh_port"` SSHUsername string `mapstructure:"ssh_username"`
RawSSHTimeout string `mapstructure:"ssh_timeout"` SSHPort uint `mapstructure:"ssh_port"`
RawStateTimeout string `mapstructure:"state_timeout"` RawSSHTimeout string `mapstructure:"ssh_timeout"`
Tags []string `mapstructure:"tags"` RawStateTimeout string `mapstructure:"state_timeout"`
Zone string `mapstructure:"zone"` Tags []string `mapstructure:"tags"`
Zone string `mapstructure:"zone"`
clientSecrets *clientSecrets clientSecrets *clientSecrets
instanceName string instanceName string
...@@ -103,21 +104,22 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { ...@@ -103,21 +104,22 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
// Process Templates // Process Templates
templates := map[string]*string{ templates := map[string]*string{
"bucket_name": &c.BucketName, "bucket_name": &c.BucketName,
"client_secrets_file": &c.ClientSecretsFile, "client_secrets_file": &c.ClientSecretsFile,
"image_name": &c.ImageName, "image_name": &c.ImageName,
"image_description": &c.ImageDescription, "image_description": &c.ImageDescription,
"instance_name": &c.InstanceName, "instance_name": &c.InstanceName,
"machine_type": &c.MachineType, "machine_type": &c.MachineType,
"network": &c.Network, "network": &c.Network,
"passphrase": &c.Passphrase, "passphrase": &c.Passphrase,
"private_key_file": &c.PrivateKeyFile, "private_key_file": &c.PrivateKeyFile,
"project_id": &c.ProjectId, "project_id": &c.ProjectId,
"source_image": &c.SourceImage, "source_image": &c.SourceImage,
"ssh_username": &c.SSHUsername, "source_image_project_id": &c.SourceImageProjectId,
"ssh_timeout": &c.RawSSHTimeout, "ssh_username": &c.SSHUsername,
"state_timeout": &c.RawStateTimeout, "ssh_timeout": &c.RawSSHTimeout,
"zone": &c.Zone, "state_timeout": &c.RawStateTimeout,
"zone": &c.Zone,
} }
for n, ptr := range templates { for n, ptr := range templates {
......
...@@ -23,10 +23,15 @@ type Driver interface { ...@@ -23,10 +23,15 @@ type Driver interface {
WaitForInstance(state, zone, name string) <-chan error WaitForInstance(state, zone, name string) <-chan error
} }
type Image struct {
Name string
ProjectId string
}
type InstanceConfig struct { type InstanceConfig struct {
Description string Description string
DiskSizeGb int64 DiskSizeGb int64
Image string Image Image
MachineType string MachineType string
Metadata map[string]string Metadata map[string]string
Name string Name string
......
...@@ -134,7 +134,7 @@ func (d *driverGCE) RunInstance(c *InstanceConfig) (<-chan error, error) { ...@@ -134,7 +134,7 @@ func (d *driverGCE) RunInstance(c *InstanceConfig) (<-chan error, error) {
} }
// Get the image // Get the image
d.ui.Message(fmt.Sprintf("Loading image: %s", c.Image)) d.ui.Message(fmt.Sprintf("Loading image: %s in project %s", c.Image.Name, c.Image.ProjectId))
image, err := d.getImage(c.Image) image, err := d.getImage(c.Image)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -229,17 +229,17 @@ func (d *driverGCE) WaitForInstance(state, zone, name string) <-chan error { ...@@ -229,17 +229,17 @@ func (d *driverGCE) WaitForInstance(state, zone, name string) <-chan error {
return errCh return errCh
} }
func (d *driverGCE) getImage(name string) (image *compute.Image, err error) { func (d *driverGCE) getImage(img Image) (image *compute.Image, err error) {
projects := []string{d.projectId, "centos-cloud", "coreos-cloud", "debian-cloud", "google-containers", "opensuse-cloud", "rhel-cloud", "suse-cloud", "windows-cloud"} projects := []string{img.ProjectId, "centos-cloud", "coreos-cloud", "debian-cloud", "google-containers", "opensuse-cloud", "rhel-cloud", "suse-cloud", "windows-cloud"}
for _, project := range projects { for _, project := range projects {
image, err = d.service.Images.Get(project, name).Do() image, err = d.service.Images.Get(project, img.Name).Do()
if err == nil && image != nil && image.SelfLink != "" { if err == nil && image != nil && image.SelfLink != "" {
return return
} }
image = nil image = nil
} }
err = fmt.Errorf("Image %s could not be found in any of these projects: %s", name, projects) err = fmt.Errorf("Image %s could not be found in any of these projects: %s", img.Name, projects)
return return
} }
......
...@@ -16,6 +16,14 @@ type StepCreateInstance struct { ...@@ -16,6 +16,14 @@ type StepCreateInstance struct {
instanceName string instanceName string
} }
func (config *Config) getImage() (Image) {
project := config.ProjectId
if config.SourceImageProjectId != "" {
project = config.SourceImageProjectId
}
return Image{Name: config.SourceImage, ProjectId: project}
}
// Run executes the Packer build step that creates a GCE instance. // Run executes the Packer build step that creates a GCE instance.
func (s *StepCreateInstance) Run(state multistep.StateBag) multistep.StepAction { func (s *StepCreateInstance) Run(state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config) config := state.Get("config").(*Config)
...@@ -29,7 +37,7 @@ func (s *StepCreateInstance) Run(state multistep.StateBag) multistep.StepAction ...@@ -29,7 +37,7 @@ func (s *StepCreateInstance) Run(state multistep.StateBag) multistep.StepAction
errCh, err := driver.RunInstance(&InstanceConfig{ errCh, err := driver.RunInstance(&InstanceConfig{
Description: "New instance created by Packer", Description: "New instance created by Packer",
DiskSizeGb: config.DiskSizeGb, DiskSizeGb: config.DiskSizeGb,
Image: config.SourceImage, Image: config.getImage(),
MachineType: config.MachineType, MachineType: config.MachineType,
Metadata: map[string]string{ Metadata: map[string]string{
"sshKeys": fmt.Sprintf("%s:%s", config.SSHUsername, sshPublicKey), "sshKeys": fmt.Sprintf("%s:%s", config.SSHUsername, sshPublicKey),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment