github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/builder/profitbricks/step_create_server.go (about) 1 package profitbricks 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "github.com/mitchellh/multistep" 8 "github.com/mitchellh/packer/packer" 9 "github.com/profitbricks/profitbricks-sdk-go" 10 "strconv" 11 "strings" 12 "time" 13 ) 14 15 type stepCreateServer struct{} 16 17 func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction { 18 ui := state.Get("ui").(packer.Ui) 19 c := state.Get("config").(*Config) 20 21 profitbricks.SetAuth(c.PBUsername, c.PBPassword) 22 profitbricks.SetDepth("5") 23 if sshkey, ok := state.GetOk("publicKey"); ok { 24 c.SSHKey = sshkey.(string) 25 } 26 ui.Say("Creating Virtual Data Center...") 27 img := s.getImageId(c.Image, c) 28 29 datacenter := profitbricks.Datacenter{ 30 Properties: profitbricks.DatacenterProperties{ 31 Name: c.SnapshotName, 32 Location: c.Region, 33 }, 34 Entities: profitbricks.DatacenterEntities{ 35 Servers: &profitbricks.Servers{ 36 Items: []profitbricks.Server{ 37 { 38 Properties: profitbricks.ServerProperties{ 39 Name: c.SnapshotName, 40 Ram: c.Ram, 41 Cores: c.Cores, 42 }, 43 Entities: &profitbricks.ServerEntities{ 44 Volumes: &profitbricks.Volumes{ 45 Items: []profitbricks.Volume{ 46 { 47 Properties: profitbricks.VolumeProperties{ 48 Type: c.DiskType, 49 Size: c.DiskSize, 50 Name: c.SnapshotName, 51 Image: img, 52 }, 53 }, 54 }, 55 }, 56 }, 57 }, 58 }, 59 }, 60 }, 61 } 62 if c.SSHKey != "" { 63 datacenter.Entities.Servers.Items[0].Entities.Volumes.Items[0].Properties.SshKeys = []string{c.SSHKey} 64 } 65 66 if c.Comm.SSHPassword != "" { 67 datacenter.Entities.Servers.Items[0].Entities.Volumes.Items[0].Properties.ImagePassword = c.Comm.SSHPassword 68 } 69 70 datacenter = profitbricks.CompositeCreateDatacenter(datacenter) 71 if datacenter.StatusCode > 299 { 72 if datacenter.StatusCode > 299 { 73 var restError RestError 74 json.Unmarshal([]byte(datacenter.Response), &restError) 75 if len(restError.Messages) > 0 { 76 ui.Error(restError.Messages[0].Message) 77 } else { 78 ui.Error(datacenter.Response) 79 } 80 return multistep.ActionHalt 81 } 82 } 83 84 err := s.waitTillProvisioned(datacenter.Headers.Get("Location"), *c) 85 if err != nil { 86 ui.Error(fmt.Sprintf("Error occured while creating a datacenter %s", err.Error())) 87 return multistep.ActionHalt 88 } 89 90 state.Put("datacenter_id", datacenter.Id) 91 92 lan := profitbricks.CreateLan(datacenter.Id, profitbricks.Lan{ 93 Properties: profitbricks.LanProperties{ 94 Public: true, 95 Name: c.SnapshotName, 96 }, 97 }) 98 99 if lan.StatusCode > 299 { 100 ui.Error(fmt.Sprintf("Error occured %s", parseErrorMessage(lan.Response))) 101 return multistep.ActionHalt 102 } 103 104 err = s.waitTillProvisioned(lan.Headers.Get("Location"), *c) 105 if err != nil { 106 ui.Error(fmt.Sprintf("Error occured while creating a LAN %s", err.Error())) 107 return multistep.ActionHalt 108 } 109 110 lanId, _ := strconv.Atoi(lan.Id) 111 nic := profitbricks.CreateNic(datacenter.Id, datacenter.Entities.Servers.Items[0].Id, profitbricks.Nic{ 112 Properties: profitbricks.NicProperties{ 113 Name: c.SnapshotName, 114 Lan: lanId, 115 Dhcp: true, 116 }, 117 }) 118 119 if lan.StatusCode > 299 { 120 ui.Error(fmt.Sprintf("Error occured %s", parseErrorMessage(nic.Response))) 121 return multistep.ActionHalt 122 } 123 124 err = s.waitTillProvisioned(nic.Headers.Get("Location"), *c) 125 if err != nil { 126 ui.Error(fmt.Sprintf("Error occured while creating a NIC %s", err.Error())) 127 return multistep.ActionHalt 128 } 129 130 state.Put("volume_id", datacenter.Entities.Servers.Items[0].Entities.Volumes.Items[0].Id) 131 132 server := profitbricks.GetServer(datacenter.Id, datacenter.Entities.Servers.Items[0].Id) 133 134 state.Put("server_ip", server.Entities.Nics.Items[0].Properties.Ips[0]) 135 136 return multistep.ActionContinue 137 } 138 139 func (s *stepCreateServer) Cleanup(state multistep.StateBag) { 140 c := state.Get("config").(*Config) 141 ui := state.Get("ui").(packer.Ui) 142 143 ui.Say("Removing Virtual Data Center...") 144 145 profitbricks.SetAuth(c.PBUsername, c.PBPassword) 146 147 if dcId, ok := state.GetOk("datacenter_id"); ok { 148 resp := profitbricks.DeleteDatacenter(dcId.(string)) 149 s.checkForErrors(resp) 150 err := s.waitTillProvisioned(resp.Headers.Get("Location"), *c) 151 if err != nil { 152 ui.Error(fmt.Sprintf( 153 "Error deleting Virtual Data Center. Please destroy it manually: %s", err)) 154 } 155 } 156 } 157 158 func (d *stepCreateServer) waitTillProvisioned(path string, config Config) error { 159 d.setPB(config.PBUsername, config.PBPassword, config.PBUrl) 160 waitCount := 120 161 if config.Retries > 0 { 162 waitCount = config.Retries 163 } 164 for i := 0; i < waitCount; i++ { 165 request := profitbricks.GetRequestStatus(path) 166 if request.Metadata.Status == "DONE" { 167 return nil 168 } 169 if request.Metadata.Status == "FAILED" { 170 return errors.New(request.Metadata.Message) 171 } 172 time.Sleep(1 * time.Second) 173 i++ 174 } 175 return nil 176 } 177 178 func (d *stepCreateServer) setPB(username string, password string, url string) { 179 profitbricks.SetAuth(username, password) 180 profitbricks.SetEndpoint(url) 181 } 182 183 func (d *stepCreateServer) checkForErrors(instance profitbricks.Resp) error { 184 if instance.StatusCode > 299 { 185 return errors.New(fmt.Sprintf("Error occured %s", string(instance.Body))) 186 } 187 return nil 188 } 189 190 type RestError struct { 191 HttpStatus int `json:"httpStatus,omitempty"` 192 Messages []Message `json:"messages,omitempty"` 193 } 194 195 type Message struct { 196 ErrorCode string `json:"errorCode,omitempty"` 197 Message string `json:"message,omitempty"` 198 } 199 200 func (d *stepCreateServer) getImageId(imageName string, c *Config) string { 201 d.setPB(c.PBUsername, c.PBPassword, c.PBUrl) 202 203 images := profitbricks.ListImages() 204 205 for i := 0; i < len(images.Items); i++ { 206 imgName := "" 207 if images.Items[i].Properties.Name != "" { 208 imgName = images.Items[i].Properties.Name 209 } 210 diskType := c.DiskType 211 if c.DiskType == "SSD" { 212 diskType = "HDD" 213 } 214 if imgName != "" && strings.Contains(strings.ToLower(imgName), strings.ToLower(imageName)) && images.Items[i].Properties.ImageType == diskType && images.Items[i].Properties.Location == c.Region && images.Items[i].Properties.Public == true { 215 return images.Items[i].Id 216 } 217 } 218 return "" 219 } 220 221 func parseErrorMessage(raw string) (toreturn string) { 222 var tmp map[string]interface{} 223 json.Unmarshal([]byte(raw), &tmp) 224 225 for _, v := range tmp["messages"].([]interface{}) { 226 for index, i := range v.(map[string]interface{}) { 227 if index == "message" { 228 toreturn = toreturn + i.(string) + "\n" 229 } 230 } 231 } 232 return toreturn 233 }