github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/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 // By default, instance name is same as image name 56 if b.config.InstanceName == "" { 57 b.config.InstanceName = b.config.ImageName 58 } 59 60 log.Println(common.ScrubConfig(b.config, b.config.Password)) 61 return nil, nil 62 } 63 64 func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { 65 computeClient, err := b.config.computeV2Client() 66 if err != nil { 67 return nil, fmt.Errorf("Error initializing compute client: %s", err) 68 } 69 70 // Setup the state bag and initial state for the steps 71 state := new(multistep.BasicStateBag) 72 state.Put("config", b.config) 73 state.Put("hook", hook) 74 state.Put("ui", ui) 75 76 // Build the steps 77 steps := []multistep.Step{ 78 &StepLoadFlavor{ 79 Flavor: b.config.Flavor, 80 }, 81 &StepKeyPair{ 82 Debug: b.config.PackerDebug, 83 DebugKeyPath: fmt.Sprintf("os_%s.pem", b.config.PackerBuildName), 84 KeyPairName: b.config.SSHKeyPairName, 85 TemporaryKeyPairName: b.config.TemporaryKeyPairName, 86 PrivateKeyFile: b.config.RunConfig.Comm.SSHPrivateKey, 87 SSHAgentAuth: b.config.RunConfig.Comm.SSHAgentAuth, 88 }, 89 &StepRunSourceServer{ 90 Name: b.config.InstanceName, 91 SourceImage: b.config.SourceImage, 92 SourceImageName: b.config.SourceImageName, 93 SecurityGroups: b.config.SecurityGroups, 94 Networks: b.config.Networks, 95 AvailabilityZone: b.config.AvailabilityZone, 96 UserData: b.config.UserData, 97 UserDataFile: b.config.UserDataFile, 98 ConfigDrive: b.config.ConfigDrive, 99 InstanceMetadata: b.config.InstanceMetadata, 100 }, 101 &StepGetPassword{ 102 Debug: b.config.PackerDebug, 103 Comm: &b.config.RunConfig.Comm, 104 }, 105 &StepWaitForRackConnect{ 106 Wait: b.config.RackconnectWait, 107 }, 108 &StepAllocateIp{ 109 FloatingIpPool: b.config.FloatingIpPool, 110 FloatingIp: b.config.FloatingIp, 111 ReuseIps: b.config.ReuseIps, 112 }, 113 &communicator.StepConnect{ 114 Config: &b.config.RunConfig.Comm, 115 Host: CommHost( 116 computeClient, 117 b.config.SSHInterface, 118 b.config.SSHIPVersion), 119 SSHConfig: SSHConfig( 120 b.config.RunConfig.Comm.SSHAgentAuth, 121 b.config.RunConfig.Comm.SSHUsername, 122 b.config.RunConfig.Comm.SSHPassword), 123 }, 124 &common.StepProvision{}, 125 &StepStopServer{}, 126 &stepCreateImage{}, 127 &stepUpdateImageVisibility{}, 128 &stepAddImageMembers{}, 129 } 130 131 // Run! 132 b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) 133 b.runner.Run(state) 134 135 // If there was an error, return that 136 if rawErr, ok := state.GetOk("error"); ok { 137 return nil, rawErr.(error) 138 } 139 140 // If there are no images, then just return 141 if _, ok := state.GetOk("image"); !ok { 142 return nil, nil 143 } 144 145 // Build the artifact and return it 146 artifact := &Artifact{ 147 ImageId: state.Get("image").(string), 148 BuilderIdValue: BuilderId, 149 Client: computeClient, 150 } 151 152 return artifact, nil 153 } 154 155 func (b *Builder) Cancel() { 156 if b.runner != nil { 157 log.Println("Cancelling the step runner...") 158 b.runner.Cancel() 159 } 160 }