github.phpd.cn/hashicorp/packer@v1.3.2/builder/openstack/builder.go (about) 1 // The openstack package contains a packer.Builder implementation that 2 // builds Images for openstack. 3 4 package openstack 5 6 import ( 7 "fmt" 8 "log" 9 10 "github.com/hashicorp/packer/common" 11 "github.com/hashicorp/packer/helper/communicator" 12 "github.com/hashicorp/packer/helper/config" 13 "github.com/hashicorp/packer/helper/multistep" 14 "github.com/hashicorp/packer/packer" 15 "github.com/hashicorp/packer/template/interpolate" 16 ) 17 18 // The unique ID for this builder 19 const BuilderId = "mitchellh.openstack" 20 21 type Config struct { 22 common.PackerConfig `mapstructure:",squash"` 23 24 AccessConfig `mapstructure:",squash"` 25 ImageConfig `mapstructure:",squash"` 26 RunConfig `mapstructure:",squash"` 27 28 ctx interpolate.Context 29 } 30 31 type Builder struct { 32 config Config 33 runner multistep.Runner 34 } 35 36 func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { 37 err := config.Decode(&b.config, &config.DecodeOpts{ 38 Interpolate: true, 39 InterpolateContext: &b.config.ctx, 40 }, raws...) 41 if err != nil { 42 return nil, err 43 } 44 45 // Accumulate any errors 46 var errs *packer.MultiError 47 errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...) 48 errs = packer.MultiErrorAppend(errs, b.config.ImageConfig.Prepare(&b.config.ctx)...) 49 errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...) 50 51 if errs != nil && len(errs.Errors) > 0 { 52 return nil, errs 53 } 54 55 if b.config.ImageConfig.ImageDiskFormat != "" && !b.config.RunConfig.UseBlockStorageVolume { 56 return nil, fmt.Errorf("use_blockstorage_volume must be true if image_disk_format is specified.") 57 } 58 59 // By default, instance name is same as image name 60 if b.config.InstanceName == "" { 61 b.config.InstanceName = b.config.ImageName 62 } 63 64 packer.LogSecretFilter.Set(b.config.Password) 65 return nil, nil 66 } 67 68 func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { 69 computeClient, err := b.config.computeV2Client() 70 if err != nil { 71 return nil, fmt.Errorf("Error initializing compute client: %s", err) 72 } 73 74 // Setup the state bag and initial state for the steps 75 state := new(multistep.BasicStateBag) 76 state.Put("config", &b.config) 77 state.Put("hook", hook) 78 state.Put("ui", ui) 79 80 // Build the steps 81 steps := []multistep.Step{ 82 &StepLoadFlavor{ 83 Flavor: b.config.Flavor, 84 }, 85 &StepKeyPair{ 86 Debug: b.config.PackerDebug, 87 Comm: &b.config.Comm, 88 DebugKeyPath: fmt.Sprintf("os_%s.pem", b.config.PackerBuildName), 89 }, 90 &StepSourceImageInfo{ 91 SourceImage: b.config.RunConfig.SourceImage, 92 SourceImageName: b.config.RunConfig.SourceImageName, 93 SourceImageOpts: b.config.RunConfig.sourceImageOpts, 94 SourceMostRecent: b.config.SourceImageFilters.MostRecent, 95 }, 96 &StepCreateVolume{ 97 UseBlockStorageVolume: b.config.UseBlockStorageVolume, 98 VolumeName: b.config.VolumeName, 99 VolumeType: b.config.VolumeType, 100 VolumeAvailabilityZone: b.config.VolumeAvailabilityZone, 101 }, 102 &StepRunSourceServer{ 103 Name: b.config.InstanceName, 104 SecurityGroups: b.config.SecurityGroups, 105 Networks: b.config.Networks, 106 Ports: b.config.Ports, 107 AvailabilityZone: b.config.AvailabilityZone, 108 UserData: b.config.UserData, 109 UserDataFile: b.config.UserDataFile, 110 ConfigDrive: b.config.ConfigDrive, 111 InstanceMetadata: b.config.InstanceMetadata, 112 UseBlockStorageVolume: b.config.UseBlockStorageVolume, 113 }, 114 &StepGetPassword{ 115 Debug: b.config.PackerDebug, 116 Comm: &b.config.RunConfig.Comm, 117 }, 118 &StepWaitForRackConnect{ 119 Wait: b.config.RackconnectWait, 120 }, 121 &StepAllocateIp{ 122 FloatingIPNetwork: b.config.FloatingIPNetwork, 123 FloatingIP: b.config.FloatingIP, 124 ReuseIPs: b.config.ReuseIPs, 125 }, 126 &communicator.StepConnect{ 127 Config: &b.config.RunConfig.Comm, 128 Host: CommHost( 129 computeClient, 130 b.config.Comm.SSHInterface, 131 b.config.Comm.SSHIPVersion), 132 SSHConfig: b.config.RunConfig.Comm.SSHConfigFunc(), 133 }, 134 &common.StepProvision{}, 135 &common.StepCleanupTempKeys{ 136 Comm: &b.config.RunConfig.Comm, 137 }, 138 &StepStopServer{}, 139 &StepDetachVolume{ 140 UseBlockStorageVolume: b.config.UseBlockStorageVolume, 141 }, 142 &stepCreateImage{ 143 UseBlockStorageVolume: b.config.UseBlockStorageVolume, 144 }, 145 &stepUpdateImageVisibility{}, 146 &stepAddImageMembers{}, 147 } 148 149 // Run! 150 b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) 151 b.runner.Run(state) 152 153 // If there was an error, return that 154 if rawErr, ok := state.GetOk("error"); ok { 155 return nil, rawErr.(error) 156 } 157 158 // If there are no images, then just return 159 if _, ok := state.GetOk("image"); !ok { 160 return nil, nil 161 } 162 163 // Build the artifact and return it 164 artifact := &Artifact{ 165 ImageId: state.Get("image").(string), 166 BuilderIdValue: BuilderId, 167 Client: computeClient, 168 } 169 170 return artifact, nil 171 } 172 173 func (b *Builder) Cancel() { 174 if b.runner != nil { 175 log.Println("Cancelling the step runner...") 176 b.runner.Cancel() 177 } 178 }