Skip to content

Commit 268d7cc

Browse files
committed
HIVE-2302, HIVE-2644: Destroyers use metadata.json
An earlier commit ensures that ClusterDeployments have an associated Secret containing the metadata.json emitted by the installer. This change adds a new generic destroyer via the (existing) `hiveutil deprovision` command that consumes this metadata.json to deprovision the cluster. This new behavior is the default, but we also include an escape hatch to run the platform-specific legacy destroyer by setting the following annotation on the ClusterDeployment: `hive.openshift.io/legacy-deprovision: "true"`
1 parent c0378f4 commit 268d7cc

File tree

22 files changed

+441
-143
lines changed

22 files changed

+441
-143
lines changed

apis/hive/v1/clusterdeprovision_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ type ClusterDeprovisionSpec struct {
2424
// BaseDomain is the DNS base domain.
2525
BaseDomain string `json:"baseDomain,omitempty"`
2626

27+
// MetaddataJSONSecretRef references the secret containing the metadata.json emitted by the
28+
// installer, potentially scrubbed for sensitive data.
29+
MetadataJSONSecretRef *corev1.LocalObjectReference `json:"metadataJSONSecretRef,omitempty"`
30+
2731
// Platform contains platform-specific configuration for a ClusterDeprovision
2832
Platform ClusterDeprovisionPlatform `json:"platform,omitempty"`
2933
}

apis/hive/v1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crds/hive.openshift.io_clusterdeprovisions.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@ spec:
6868
infraID:
6969
description: InfraID is the identifier generated during installation for a cluster. It is used for tagging/naming resources in cloud providers.
7070
type: string
71+
metadataJSONSecretRef:
72+
description: |-
73+
MetaddataJSONSecretRef references the secret containing the metadata.json emitted by the
74+
installer, potentially scrubbed for sensitive data.
75+
properties:
76+
name:
77+
default: ""
78+
description: |-
79+
Name of the referent.
80+
This field is effectively required, but due to backwards compatibility is
81+
allowed to be empty. Instances of this type with an empty value here are
82+
almost certainly wrong.
83+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
84+
type: string
85+
type: object
86+
x-kubernetes-map-type: atomic
7187
platform:
7288
description: Platform contains platform-specific configuration for a ClusterDeprovision
7389
properties:

contrib/pkg/deprovision/awstagdeprovision.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
)
1414

1515
// NewDeprovisionAWSWithTagsCommand is the entrypoint to create the 'aws-tag-deprovision' subcommand
16-
// TODO: Port to a sub-command of deprovision.
1716
func NewDeprovisionAWSWithTagsCommand() *cobra.Command {
1817
opt := &aws.ClusterUninstaller{}
1918
var credsDir string

contrib/pkg/deprovision/azure.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ type AzureOptions struct {
2323
}
2424

2525
// NewDeprovisionAzureCommand is the entrypoint to create the azure deprovision subcommand
26-
func NewDeprovisionAzureCommand() *cobra.Command {
27-
opt := &AzureOptions{}
26+
func NewDeprovisionAzureCommand(logLevel string) *cobra.Command {
27+
opt := &AzureOptions{
28+
logLevel: logLevel,
29+
}
2830
cmd := &cobra.Command{
2931
Use: "azure INFRAID [--azure-cloud-name CLOUDNAME] [--azure-resource-group-name RG] [--azure-base-domain-resource-group-name BDRG]",
3032
Short: "Deprovision Azure assets (as created by openshift-installer)",
@@ -46,7 +48,6 @@ func NewDeprovisionAzureCommand() *cobra.Command {
4648
},
4749
}
4850
flags := cmd.Flags()
49-
flags.StringVar(&opt.logLevel, "loglevel", "info", "log level, one of: debug, info, warn, error, fatal, panic")
5051
flags.StringVar(&opt.cloudName, "azure-cloud-name", installertypesazure.PublicCloud.Name(), "The name of the Azure cloud environment used to configure the Azure SDK")
5152
flags.StringVar(&opt.resourceGroupName, "azure-resource-group-name", "", "The name of the custom Azure resource group in which the cluster was created when not using the default installer-created resource group")
5253
flags.StringVar(&opt.baseDomainResourceGroupName, "azure-base-domain-resource-group-name", "", "The name of the custom Azure resource group in which the cluster's DNS records were created when not using the default installer-created resource group or custom resource group")
Lines changed: 135 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,154 @@
11
package deprovision
22

33
import (
4+
"encoding/json"
5+
"log"
6+
"os"
7+
8+
"sigs.k8s.io/controller-runtime/pkg/client"
9+
10+
"github.com/openshift/installer/pkg/destroy/providers"
11+
"github.com/openshift/installer/pkg/types"
12+
"github.com/openshift/installer/pkg/types/aws"
13+
"github.com/openshift/installer/pkg/types/azure"
14+
"github.com/openshift/installer/pkg/types/gcp"
15+
"github.com/openshift/installer/pkg/types/ibmcloud"
16+
"github.com/openshift/installer/pkg/types/nutanix"
17+
"github.com/openshift/installer/pkg/types/openstack"
18+
"github.com/openshift/installer/pkg/types/ovirt"
19+
"github.com/openshift/installer/pkg/types/vsphere"
20+
21+
"github.com/openshift/hive/contrib/pkg/utils"
22+
awsutil "github.com/openshift/hive/contrib/pkg/utils/aws"
23+
azureutil "github.com/openshift/hive/contrib/pkg/utils/azure"
24+
gcputil "github.com/openshift/hive/contrib/pkg/utils/gcp"
25+
ibmcloudutil "github.com/openshift/hive/contrib/pkg/utils/ibmcloud"
26+
nutanixutil "github.com/openshift/hive/contrib/pkg/utils/nutanix"
27+
openstackutil "github.com/openshift/hive/contrib/pkg/utils/openstack"
28+
ovirtutil "github.com/openshift/hive/contrib/pkg/utils/ovirt"
29+
vsphereutil "github.com/openshift/hive/contrib/pkg/utils/vsphere"
30+
"github.com/openshift/hive/pkg/constants"
31+
432
"github.com/spf13/cobra"
533
)
634

735
// NewDeprovisionCommand is the entrypoint to create the 'deprovision' subcommand
836
func NewDeprovisionCommand() *cobra.Command {
937
var credsDir string
38+
var mjSecretName string
39+
var logLevel string
1040
cmd := &cobra.Command{
1141
Use: "deprovision",
1242
Short: "Deprovision clusters in supported cloud providers",
43+
Long: `Platform subcommands use a legacy code path and are deprecated. \
44+
To run the generic destroyer, use the --metadata-json-secret-name parameter.`,
1345
Run: func(cmd *cobra.Command, args []string) {
14-
cmd.Usage()
46+
if mjSecretName == "" {
47+
cmd.Usage()
48+
return
49+
}
50+
51+
// Generic deprovision flow using metadata.json
52+
logger, err := utils.NewLogger(logLevel)
53+
if err != nil {
54+
log.Fatalf("failed to create logger: %s", err)
55+
}
56+
57+
c, err := utils.GetClient("hiveutil-deprovision-generic")
58+
if err != nil {
59+
logger.WithError(err).Fatal("failed to create kube client")
60+
}
61+
62+
// TODO: Refactor LoadSecretOrDie to avoid this setenv/getenv cycle
63+
k := "METADATA_JSON_SECRET_NAME"
64+
os.Setenv(k, mjSecretName)
65+
mjSecret := utils.LoadSecretOrDie(c, k)
66+
if mjSecret == nil {
67+
// This should not be reachable -- we should have Fatal()ed in LoadSecretOrDie()
68+
logger.WithField("secretName", mjSecretName).Fatal("failed to load metadata.json Secret")
69+
}
70+
71+
mjBytes, ok := mjSecret.Data[constants.MetadataJSONSecretKey]
72+
if !ok {
73+
logger.Fatalf("metadata.json Secret did not contain %q key", constants.MetadataJSONSecretKey)
74+
}
75+
76+
var metadata *types.ClusterMetadata
77+
if err = json.Unmarshal(mjBytes, &metadata); err != nil {
78+
logger.WithError(err).Fatal("failed to unmarshal metadata.json")
79+
}
80+
81+
platform := metadata.Platform()
82+
if platform == "" {
83+
logger.Fatal("no platform configured in metadata.json")
84+
}
85+
86+
// TODO: Make a registry or interface for this
87+
var ConfigureCreds func(client.Client)
88+
switch platform {
89+
case aws.Name:
90+
ConfigureCreds = awsutil.ConfigureCreds
91+
case azure.Name:
92+
ConfigureCreds = azureutil.ConfigureCreds
93+
case gcp.Name:
94+
ConfigureCreds = gcputil.ConfigureCreds
95+
case ibmcloud.Name:
96+
ConfigureCreds = ibmcloudutil.ConfigureCreds
97+
case nutanix.Name:
98+
// Snowflake! We need to inject the creds into the metadata.
99+
// If env vars are unset, the destroyer will fail organically.
100+
ConfigureCreds = func(c client.Client) {
101+
nutanixutil.ConfigureCreds(c)
102+
metadata.Nutanix.Username = os.Getenv(constants.NutanixUsernameEnvVar)
103+
metadata.Nutanix.Password = os.Getenv(constants.NutanixPasswordEnvVar)
104+
}
105+
case openstack.Name:
106+
ConfigureCreds = openstackutil.ConfigureCreds
107+
case ovirt.Name:
108+
ConfigureCreds = ovirtutil.ConfigureCreds
109+
case vsphere.Name:
110+
// Snowflake! We need to inject the creds into the metadata.
111+
// If env vars are unset, the destroyer will fail organically.
112+
ConfigureCreds = func(c client.Client) {
113+
vsphereutil.ConfigureCreds(c)
114+
metadata.VSphere.VCenter = os.Getenv(constants.VSphereVCenterEnvVar)
115+
metadata.VSphere.Username = os.Getenv(constants.VSphereUsernameEnvVar)
116+
metadata.VSphere.Password = os.Getenv(constants.VSpherePasswordEnvVar)
117+
}
118+
}
119+
ConfigureCreds(c)
120+
121+
destroyerBuilder, ok := providers.Registry[platform]
122+
if !ok {
123+
logger.WithField("platform", platform).Fatal("no destroyers registered for platform")
124+
}
125+
126+
destroyer, err := destroyerBuilder(logger, metadata)
127+
if err != nil {
128+
logger.WithError(err).Fatal("failed to create destroyer")
129+
}
130+
131+
// Ignore quota return
132+
_, err = destroyer.Run()
133+
if err != nil {
134+
logger.WithError(err).Fatal("destroyer returned an error")
135+
}
15136
},
16137
}
17138
flags := cmd.PersistentFlags()
139+
// TODO: Unused -- remove from here and generate.go
18140
flags.StringVar(&credsDir, "creds-dir", "", "directory of the creds. Changes in the creds will cause the program to terminate")
19-
cmd.AddCommand(NewDeprovisionAzureCommand())
20-
cmd.AddCommand(NewDeprovisionGCPCommand())
21-
cmd.AddCommand(NewDeprovisionIBMCloudCommand())
22-
cmd.AddCommand(NewDeprovisionOpenStackCommand())
23-
cmd.AddCommand(NewDeprovisionvSphereCommand())
24-
cmd.AddCommand(NewDeprovisionOvirtCommand())
25-
cmd.AddCommand(NewDeprovisionNutanixCommand())
141+
// TODO: Make this more useful to CLI users by accepting a path to a metadata.json file in the file system
142+
flags.StringVar(&mjSecretName, "metadata-json-secret-name", "", "name of a Secret in the current namespace containing `metadata.json` from the installer")
143+
flags.StringVar(&logLevel, "loglevel", "info", "log level, one of: debug, info, warn, error, fatal, panic")
144+
145+
// Legacy destroyers
146+
cmd.AddCommand(NewDeprovisionAzureCommand(logLevel))
147+
cmd.AddCommand(NewDeprovisionGCPCommand(logLevel))
148+
cmd.AddCommand(NewDeprovisionIBMCloudCommand(logLevel))
149+
cmd.AddCommand(NewDeprovisionOpenStackCommand(logLevel))
150+
cmd.AddCommand(NewDeprovisionvSphereCommand(logLevel))
151+
cmd.AddCommand(NewDeprovisionOvirtCommand(logLevel))
152+
cmd.AddCommand(NewDeprovisionNutanixCommand(logLevel))
26153
return cmd
27154
}

contrib/pkg/deprovision/gcp.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ type gcpOptions struct {
2626
}
2727

2828
// NewDeprovisionGCPCommand is the entrypoint to create the GCP deprovision subcommand
29-
func NewDeprovisionGCPCommand() *cobra.Command {
30-
opt := &gcpOptions{}
29+
func NewDeprovisionGCPCommand(logLevel string) *cobra.Command {
30+
opt := &gcpOptions{
31+
logLevel: logLevel,
32+
}
3133
cmd := &cobra.Command{
3234
Use: "gcp INFRAID --region=REGION",
3335
Short: "Deprovision GCP assets (as created by openshift-installer)",
@@ -45,7 +47,6 @@ func NewDeprovisionGCPCommand() *cobra.Command {
4547
},
4648
}
4749
flags := cmd.Flags()
48-
flags.StringVar(&opt.logLevel, "loglevel", "info", "log level, one of: debug, info, warn, error, fatal, panic")
4950
flags.StringVar(&opt.region, "region", "", "GCP region where the cluster is installed")
5051
flags.StringVar(&opt.networkProjectID, "network-project-id", "", "For shared VPC setups")
5152
return cmd

contrib/pkg/deprovision/ibmcloud.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ type ibmCloudDeprovisionOptions struct {
3030
}
3131

3232
// NewDeprovisionIBMCloudCommand is the entrypoint to create the IBM Cloud deprovision subcommand
33-
func NewDeprovisionIBMCloudCommand() *cobra.Command {
34-
opt := &ibmCloudDeprovisionOptions{}
33+
func NewDeprovisionIBMCloudCommand(logLevel string) *cobra.Command {
34+
opt := &ibmCloudDeprovisionOptions{
35+
logLevel: logLevel,
36+
}
3537
cmd := &cobra.Command{
3638
Use: "ibmcloud INFRAID --region=us-east --base-domain=BASE_DOMAIN --cluster-name=CLUSTERNAME",
3739
Short: "Deprovision IBM Cloud assets (as created by openshift-installer)",
@@ -50,7 +52,6 @@ func NewDeprovisionIBMCloudCommand() *cobra.Command {
5052
}
5153

5254
flags := cmd.Flags()
53-
flags.StringVar(&opt.logLevel, "loglevel", "info", "log level, one of: debug, info, warn, error, fatal, panic")
5455

5556
// Required flags
5657
flags.StringVar(&opt.baseDomain, "base-domain", "", "cluster's base domain")

contrib/pkg/deprovision/nutanix.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ type nutanixOptions struct {
2626
password string
2727
}
2828

29-
func NewDeprovisionNutanixCommand() *cobra.Command {
30-
opt := &nutanixOptions{}
29+
func NewDeprovisionNutanixCommand(logLevel string) *cobra.Command {
30+
opt := &nutanixOptions{
31+
logLevel: logLevel,
32+
}
3133

3234
cmd := &cobra.Command{
3335
Use: "nutanix INFRAID",
@@ -46,7 +48,6 @@ func NewDeprovisionNutanixCommand() *cobra.Command {
4648
},
4749
}
4850
flags := cmd.Flags()
49-
flags.StringVar(&opt.logLevel, "loglevel", "info", "log level, one of: debug, info, warn, error, fatal, panic")
5051
flags.StringVar(&opt.endpoint, constants.CliNutanixPcAddressOpt, "", "Domain name or IP address of the Nutanix Prism Central endpoint")
5152
flags.StringVar(&opt.port, constants.CliNutanixPcPortOpt, "", "Port of the Nutanix Prism Central endpoint")
5253
return cmd

contrib/pkg/deprovision/openstack.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ type openStackOptions struct {
2323
}
2424

2525
// NewDeprovisionOpenStackCommand is the entrypoint to create the OpenStack deprovision subcommand
26-
func NewDeprovisionOpenStackCommand() *cobra.Command {
27-
opt := &openStackOptions{}
26+
func NewDeprovisionOpenStackCommand(logLevel string) *cobra.Command {
27+
opt := &openStackOptions{
28+
logLevel: logLevel,
29+
}
2830
cmd := &cobra.Command{
2931
Use: "openstack INFRAID --cloud=OS_CLOUD",
3032
Short: "Deprovision OpenStack assets (as created by openshift-installer)",
@@ -42,7 +44,6 @@ func NewDeprovisionOpenStackCommand() *cobra.Command {
4244
},
4345
}
4446
flags := cmd.Flags()
45-
flags.StringVar(&opt.logLevel, "loglevel", "info", "log level, one of: debug, info, warn, error, fatal, panic")
4647
flags.StringVar(&opt.cloud, "cloud", "", "OpenStack cloud entry name from clouds.yaml for access/authentication")
4748
return cmd
4849
}

0 commit comments

Comments
 (0)