/
openstack.go
131 lines (112 loc) · 3.96 KB
/
openstack.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package openstacktest
import (
"fmt"
"os"
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack"
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata"
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
)
const WaitTimeout = 30 * 60 // 30 minutes in seconds
func UploadImageToOpenStack(p *gophercloud.ProviderClient, imagePath string, imageName string) (*images.Image, error) {
client, err := openstack.NewImageServiceV2(p, gophercloud.EndpointOpts{
Region: os.Getenv("OS_REGION_NAME"),
})
if err != nil {
return nil, fmt.Errorf("Error creating ImageService client: %v", err)
}
// create a new image which gives us the ID
image, err := images.Create(client, images.CreateOpts{
Name: imageName,
DiskFormat: "qcow2",
ContainerFormat: "bare",
}).Extract()
if err != nil {
return image, fmt.Errorf("Creating image failed: %v", err)
}
// then upload the actual binary data
imageData, err := os.Open(imagePath)
if err != nil {
return image, fmt.Errorf("Error opening %s: %v", imagePath, err)
}
defer imageData.Close()
err = imagedata.Upload(client, image.ID, imageData).ExtractErr()
if err != nil {
return image, fmt.Errorf("Upload to OpenStack failed: %v", err)
}
// wait for the status to change from Queued to Active
err = gophercloud.WaitFor(WaitTimeout, func() (bool, error) {
actual, err := images.Get(client, image.ID).Extract()
return actual.Status == images.ImageStatusActive, err
})
if err != nil {
return image, fmt.Errorf("Waiting for image to become Active failed: %v", err)
}
return image, nil
}
func DeleteImageFromOpenStack(p *gophercloud.ProviderClient, imageUUID string) error {
client, err := openstack.NewImageServiceV2(p, gophercloud.EndpointOpts{
Region: os.Getenv("OS_REGION_NAME"),
})
if err != nil {
return fmt.Errorf("Error creating ImageService client: %v", err)
}
err = images.Delete(client, imageUUID).ExtractErr()
if err != nil {
return fmt.Errorf("cannot delete the image: %v", err)
}
return nil
}
func WithBootedImageInOpenStack(p *gophercloud.ProviderClient, imageID, userData string, f func(address string) error) (retErr error) {
client, err := openstack.NewComputeV2(p, gophercloud.EndpointOpts{
Region: os.Getenv("OS_REGION_NAME"),
})
if err != nil {
return fmt.Errorf("Error creating Compute client: %v", err)
}
server, err := servers.Create(client, servers.CreateOpts{
Name: "osbuild-composer-vm-for-" + imageID,
FlavorRef: "f2c4469b-f516-46d1-8b87-1dcca68fb3d9", // ci-ssd.standard.medium
Networks: []servers.Network{ // shared_net_2
servers.Network{UUID: "0bb5a1a2-cf3b-4371-9b31-3ae78313971d"},
},
ImageRef: imageID,
UserData: []byte(userData),
}).Extract()
if err != nil {
return fmt.Errorf("Cannot create instance: %v", err)
}
// cleanup
defer func() {
err := servers.ForceDelete(client, server.ID).ExtractErr()
if err != nil {
fmt.Printf("Force deleting instance %s failed: %v", server.ID, err)
return
}
}()
// wait for the status to become Active
err = servers.WaitForStatus(client, server.ID, "ACTIVE", WaitTimeout)
if err != nil {
return fmt.Errorf("Waiting for instance %s to become Active failed: %v", server.ID, err)
}
// get server details again to refresh the IP addresses
server, err = servers.Get(client, server.ID).Extract()
if err != nil {
return fmt.Errorf("Cannot get instance details: %v\n", err)
}
// server.AccessIPv4 is empty so list all addresses and
// get the first fixed one. ssh should be equally happy with v4 or v6
var fixedIP string
for _, networkAddresses := range server.Addresses["shared_net_2"].([]interface{}) {
address := networkAddresses.(map[string]interface{})
if address["OS-EXT-IPS:type"] == "fixed" {
fixedIP = address["addr"].(string)
break
}
}
if fixedIP == "" {
return fmt.Errorf("Cannot find IP address for instance %s", server.ID)
}
return f(fixedIP)
}