Skip to content

Commit b635933

Browse files
Merge pull request #2473 from Fedosin/openstack_auto_image_2
OpenStack: automatically populate RHCOS image
2 parents 0626e59 + 545daea commit b635933

File tree

30 files changed

+1236
-58
lines changed

30 files changed

+1236
-58
lines changed

Gopkg.lock

+5-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

data/data/openstack/bootstrap/main.tf

+1-6
Original file line numberDiff line numberDiff line change
@@ -109,19 +109,14 @@ EOF
109109
}
110110
}
111111

112-
data "openstack_images_image_v2" "bootstrap_image" {
113-
name = var.image_name
114-
most_recent = true
115-
}
116-
117112
data "openstack_compute_flavor_v2" "bootstrap_flavor" {
118113
name = var.flavor_name
119114
}
120115

121116
resource "openstack_compute_instance_v2" "bootstrap" {
122117
name = "${var.cluster_id}-bootstrap"
123118
flavor_id = data.openstack_compute_flavor_v2.bootstrap_flavor.id
124-
image_id = data.openstack_images_image_v2.bootstrap_image.id
119+
image_id = var.base_image_id
125120

126121
user_data = data.ignition_config.redirect.rendered
127122

data/data/openstack/bootstrap/variables.tf

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
variable "image_name" {
1+
variable "base_image_id" {
22
type = string
3-
description = "The name of the Glance image for the bootstrap node."
3+
description = "The identifier of the Glance image for the bootstrap node."
44
}
55

66
variable "extra_tags" {

data/data/openstack/main.tf

+20-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ module "bootstrap" {
2727

2828
cluster_id = var.cluster_id
2929
extra_tags = var.openstack_extra_tags
30-
image_name = var.openstack_base_image
30+
base_image_id = data.openstack_images_image_v2.base_image.id
3131
flavor_name = var.openstack_master_flavor_name
3232
ignition = var.ignition_bootstrap
3333
api_int_ip = var.openstack_api_int_ip
@@ -42,7 +42,7 @@ module "bootstrap" {
4242
module "masters" {
4343
source = "./masters"
4444

45-
base_image = var.openstack_base_image
45+
base_image_id = data.openstack_images_image_v2.base_image.id
4646
cluster_id = var.cluster_id
4747
flavor_name = var.openstack_master_flavor_name
4848
instance_count = var.master_count
@@ -72,3 +72,21 @@ module "topology" {
7272
trunk_support = var.openstack_trunk_support
7373
octavia_support = var.openstack_octavia_support
7474
}
75+
76+
resource "openstack_images_image_v2" "base_image" {
77+
// we need to create a new image only if the base image url has been provided, plus base image name is <cluster_id>-rhcos
78+
count = var.openstack_base_image_url != "" && var.openstack_base_image_name == "${var.cluster_id}-rhcos" ? 1 : 0
79+
80+
name = var.openstack_base_image_name
81+
image_source_url = var.openstack_base_image_url
82+
container_format = "bare"
83+
disk_format = "qcow2"
84+
85+
tags = ["openshiftClusterID=${var.cluster_id}"]
86+
}
87+
88+
data "openstack_images_image_v2" "base_image" {
89+
name = var.openstack_base_image_name
90+
91+
depends_on = ["openstack_images_image_v2.base_image"]
92+
}

data/data/openstack/masters/main.tf

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
data "openstack_images_image_v2" "masters_img" {
2-
name = var.base_image
3-
most_recent = true
4-
}
5-
61
data "openstack_compute_flavor_v2" "masters_flavor" {
72
name = var.flavor_name
83
}
@@ -38,15 +33,15 @@ resource "openstack_blockstorage_volume_v3" "master_volume" {
3833

3934
size = var.root_volume_size
4035
volume_type = var.root_volume_type
41-
image_id = data.openstack_images_image_v2.masters_img.id
36+
image_id = var.base_image_id
4237
}
4338

4439
resource "openstack_compute_instance_v2" "master_conf" {
4540
name = "${var.cluster_id}-master-${count.index}"
4641
count = var.instance_count
4742

4843
flavor_id = data.openstack_compute_flavor_v2.masters_flavor.id
49-
image_id = var.root_volume_size == null ? data.openstack_images_image_v2.masters_img.id : null
44+
image_id = var.root_volume_size == null ? var.base_image_id : null
5045
security_groups = var.master_sg_ids
5146
user_data = element(
5247
data.ignition_config.master_ignition_config.*.rendered,

data/data/openstack/masters/variables.tf

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
variable "base_image" {
2-
type = string
1+
variable "base_image_id" {
2+
type = string
3+
description = "The identifier of the Glance image for master nodes."
34
}
45

56
variable "cluster_id" {

data/data/openstack/variables-openstack.tf

+7-2
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@ variable "openstack_master_root_volume_size" {
1010
description = "The size of the volume in gigabytes for the root block device of master nodes."
1111
}
1212

13-
variable "openstack_base_image" {
13+
variable "openstack_base_image_name" {
1414
type = string
15-
default = "rhcos"
1615
description = "Name of the base image to use for the nodes."
1716
}
1817

18+
variable "openstack_base_image_url" {
19+
type = string
20+
default = ""
21+
description = "URL of the base image to use for the nodes."
22+
}
23+
1924
variable "openstack_credentials_auth_url" {
2025
type = string
2126
default = ""

pkg/asset/cluster/tfvars.go

+2
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,8 @@ func (t *TerraformVariables) Generate(parents asset.Parents) error {
293293
ingressVIP.String(),
294294
installConfig.Config.Platform.OpenStack.TrunkSupport,
295295
installConfig.Config.Platform.OpenStack.OctaviaSupport,
296+
string(*rhcosImage),
297+
clusterID.InfraID,
296298
)
297299
if err != nil {
298300
return errors.Wrapf(err, "failed to get %s Terraform variables", platform)

pkg/asset/machines/master.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"github.com/openshift/installer/pkg/asset/machines/machineconfig"
3737
"github.com/openshift/installer/pkg/asset/machines/openstack"
3838
"github.com/openshift/installer/pkg/asset/rhcos"
39+
rhcosutils "github.com/openshift/installer/pkg/rhcos"
3940
"github.com/openshift/installer/pkg/types"
4041
awstypes "github.com/openshift/installer/pkg/types/aws"
4142
awsdefaults "github.com/openshift/installer/pkg/types/aws/defaults"
@@ -181,7 +182,10 @@ func (m *Master) Generate(dependencies asset.Parents) error {
181182
mpool.Set(ic.Platform.OpenStack.DefaultMachinePlatform)
182183
mpool.Set(pool.Platform.OpenStack)
183184
pool.Platform.OpenStack = &mpool
184-
machines, err = openstack.Machines(clusterID.InfraID, ic, pool, string(*rhcosImage), "master", "master-user-data")
185+
186+
imageName, _ := rhcosutils.GenerateOpenStackImageName(string(*rhcosImage), clusterID.InfraID)
187+
188+
machines, err = openstack.Machines(clusterID.InfraID, ic, pool, imageName, "master", "master-user-data")
185189
if err != nil {
186190
return errors.Wrap(err, "failed to create master machine objects")
187191
}

pkg/asset/machines/worker.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"github.com/openshift/installer/pkg/asset/machines/machineconfig"
3737
"github.com/openshift/installer/pkg/asset/machines/openstack"
3838
"github.com/openshift/installer/pkg/asset/rhcos"
39+
rhcosutils "github.com/openshift/installer/pkg/rhcos"
3940
"github.com/openshift/installer/pkg/types"
4041
awstypes "github.com/openshift/installer/pkg/types/aws"
4142
awsdefaults "github.com/openshift/installer/pkg/types/aws/defaults"
@@ -247,7 +248,9 @@ func (w *Worker) Generate(dependencies asset.Parents) error {
247248
mpool.Set(pool.Platform.OpenStack)
248249
pool.Platform.OpenStack = &mpool
249250

250-
sets, err := openstack.MachineSets(clusterID.InfraID, ic, &pool, string(*rhcosImage), "worker", "worker-user-data")
251+
imageName, _ := rhcosutils.GenerateOpenStackImageName(string(*rhcosImage), clusterID.InfraID)
252+
253+
sets, err := openstack.MachineSets(clusterID.InfraID, ic, &pool, imageName, "worker", "worker-user-data")
251254
if err != nil {
252255
return errors.Wrap(err, "failed to create master machine objects")
253256
}

pkg/asset/rhcos/image.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func osImage(config *types.InstallConfig) (string, error) {
7878
case libvirt.Name:
7979
osimage, err = rhcos.QEMU(ctx)
8080
case openstack.Name:
81-
osimage = "rhcos"
81+
osimage, err = rhcos.OpenStack(ctx)
8282
case azure.Name:
8383
osimage, err = rhcos.VHD(ctx)
8484
case baremetal.Name:

pkg/destroy/openstack/openstack.go

+40
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/gophercloud/gophercloud"
1313
"github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes"
1414
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
15+
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
1516
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/apiversions"
1617
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/loadbalancers"
1718
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
@@ -133,6 +134,7 @@ func populateDeleteFuncs(funcs map[string]deleteFunc) {
133134
funcs["deleteContainers"] = deleteContainers
134135
funcs["deleteVolumes"] = deleteVolumes
135136
funcs["deleteFloatingIPs"] = deleteFloatingIPs
137+
funcs["deleteImages"] = deleteImages
136138
}
137139

138140
// filterObjects will do client-side filtering given an appropriately filled out
@@ -876,3 +878,41 @@ func deleteFloatingIPs(opts *clientconfig.ClientOpts, filter Filter, logger logr
876878
}
877879
return len(allFloatingIPs) == 0, nil
878880
}
881+
882+
func deleteImages(opts *clientconfig.ClientOpts, filter Filter, logger logrus.FieldLogger) (bool, error) {
883+
logger.Debug("Deleting openstack base image")
884+
defer logger.Debugf("Exiting deleting openstack base image")
885+
886+
conn, err := clientconfig.NewServiceClient("image", opts)
887+
if err != nil {
888+
logger.Fatalf("%v", err)
889+
os.Exit(1)
890+
}
891+
892+
listOpts := images.ListOpts{
893+
Tags: filterTags(filter),
894+
}
895+
896+
allPages, err := images.List(conn, listOpts).AllPages()
897+
if err != nil {
898+
logger.Fatalf("%v", err)
899+
os.Exit(1)
900+
}
901+
902+
allImages, err := images.ExtractImages(allPages)
903+
if err != nil {
904+
logger.Fatalf("%v", err)
905+
os.Exit(1)
906+
}
907+
908+
for _, image := range allImages {
909+
logger.Debugf("Deleting image: %+v", image.ID)
910+
err := images.Delete(conn, image.ID).ExtractErr()
911+
if err != nil {
912+
// This can fail if the image is still in use by other VMs
913+
logger.Debugf("Deleting Image failed: %v", err)
914+
return false, nil
915+
}
916+
}
917+
return true, nil
918+
}

pkg/rhcos/openstack.go

+14
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,17 @@ func OpenStack(ctx context.Context) (string, error) {
2727

2828
return base.ResolveReference(relOpenStack).String(), nil
2929
}
30+
31+
// GenerateOpenStackImageName returns Glance image name for instances.
32+
func GenerateOpenStackImageName(rhcosImage, infraID string) (imageName string, isURL bool) {
33+
// Here we check whether rhcosImage is a URL or not. If this is the first case, it means that Glance image
34+
// should be created by the installer with the universal name "<infraID>-rhcos". Otherwise, it means
35+
// that we are given the name of the pre-created Glance image, which the installer should use for node
36+
// provisioning.
37+
_, err := url.ParseRequestURI(rhcosImage)
38+
if err != nil {
39+
return rhcosImage, false
40+
}
41+
42+
return infraID + "-rhcos", true
43+
}

pkg/tfvars/openstack/openstack.go

+22-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ package openstack
44
import (
55
"encoding/json"
66

7+
"github.com/openshift/installer/pkg/rhcos"
8+
79
"sigs.k8s.io/cluster-api-provider-openstack/pkg/apis/openstackproviderconfig/v1alpha1"
810
)
911

1012
type config struct {
11-
BaseImage string `json:"openstack_base_image,omitempty"`
13+
BaseImageName string `json:"openstack_base_image_name,omitempty"`
14+
BaseImageURL string `json:"openstack_base_image_url,omitempty"`
1215
ExternalNetwork string `json:"openstack_external_network,omitempty"`
1316
Cloud string `json:"openstack_credentials_cloud,omitempty"`
1417
FlavorName string `json:"openstack_master_flavor_name,omitempty"`
@@ -23,9 +26,8 @@ type config struct {
2326
}
2427

2528
// TFVars generates OpenStack-specific Terraform variables.
26-
func TFVars(masterConfig *v1alpha1.OpenstackProviderSpec, cloud string, externalNetwork string, lbFloatingIP string, apiVIP string, dnsVIP string, ingressVIP string, trunkSupport string, octaviaSupport string) ([]byte, error) {
29+
func TFVars(masterConfig *v1alpha1.OpenstackProviderSpec, cloud string, externalNetwork string, lbFloatingIP string, apiVIP string, dnsVIP string, ingressVIP string, trunkSupport string, octaviaSupport string, baseImage string, infraID string) ([]byte, error) {
2730
cfg := &config{
28-
BaseImage: masterConfig.Image,
2931
ExternalNetwork: externalNetwork,
3032
Cloud: cloud,
3133
FlavorName: masterConfig.Flavor,
@@ -36,6 +38,23 @@ func TFVars(masterConfig *v1alpha1.OpenstackProviderSpec, cloud string, external
3638
TrunkSupport: trunkSupport,
3739
OctaviaSupport: octaviaSupport,
3840
}
41+
42+
// Normally baseImage contains a URL that we will use to create a new Glance image, but for testing
43+
// purposes we also allow to set a custom Glance image name to skip the uploading. Here we check
44+
// whether baseImage is a URL or not. If this is the first case, it means that the image should be
45+
// created by the installer from the URL. Otherwise, it means that we are given the name of the pre-created
46+
// Glance image, which we should use for instances.
47+
imageName, isURL := rhcos.GenerateOpenStackImageName(baseImage, infraID)
48+
cfg.BaseImageName = imageName
49+
if isURL {
50+
// Valid URL -> use baseImage as a URL that will be used to create new Glance image with name "<infraID>-rhcos".
51+
cfg.BaseImageURL = baseImage
52+
} else {
53+
// Not a URL -> use baseImage value as a Glance image name.
54+
55+
// TODO(mfedosin): add validations that this image exists and there are no other images with this name.
56+
}
57+
3958
if masterConfig.RootVolume != nil {
4059
cfg.RootVolumeSize = masterConfig.RootVolume.Size
4160
cfg.RootVolumeType = masterConfig.RootVolume.VolumeType

vendor/github.com/gophercloud/gophercloud/internal/pkg.go

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/gophercloud/gophercloud/internal/util.go

+34
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)