Repository: kubernetes/kops (go)

Issue:
Creating new clusters in OpenStack broken
/kind bug

**1. What `kops` version are you running? The command `kops version`, will display
 this information.**

master

**2. What Kubernetes version are you running? `kubectl version` will print the
 version if a cluster is running or provide the Kubernetes version specified as
 a `kops` flag.**

1.25.3

**3. What cloud provider are you using?**

openstack


**4. What commands did you run?  What is the simplest way to reproduce this issue?**

```
./kops create cluster \                         
  --cloud openstack \
  --name jessetesti.k8s.local \
  --state ${KOPS_STATE_STORE} \
  --zones espsti,esptnl,helpa \
  --network-cidr 10.2.0.0/16 \
  --image ubuntu-2004-281022-devops \
  --master-count=3 \
  --node-count=2 \
  --node-size m1.medium \
  --master-size m1.medium \
  --etcd-storage-type solidfire \
  --topology private \
  --bastion \
  --networking calico \
  --api-loadbalancer-type public \
  --os-octavia=true \
  --os-ext-net foo-nap \
  --os-ext-subnet ext-ha-v4 \
  --os-lb-floating-subnet ext-ha-v4 \
  --os-dns-servers 8.8.8.8,1.1.1.1
```

**5. What happened after the commands executed?**

```
I1227 14:43:28.810984   55851 executor.go:111] Tasks: 121 done / 160 total; 13 can run
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x105b579c8]

goroutine 944 [running]:
github.com/gophercloud/gophercloud.(*ServiceClient).ResourceBaseURL(...)
        github.com/gophercloud/gophercloud@v1.1.1/service_client.go:39
github.com/gophercloud/gophercloud.(*ServiceClient).ServiceURL(...)
        github.com/gophercloud/gophercloud@v1.1.1/service_client.go:47
github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/loadbalancers.rootURL(0x140014ab078?)
        github.com/gophercloud/gophercloud@v1.1.1/openstack/loadbalancer/v2/loadbalancers/urls.go:14 +0x48
github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/loadbalancers.List(0x0, {0x107add640, 0x140009e6000})
        github.com/gophercloud/gophercloud@v1.1.1/openstack/loadbalancer/v2/loadbalancers/requests.go:59 +0x40
k8s.io/kops/upup/pkg/fi/cloudup/openstacktasks.(*LB).Find(0x14000aa3b80, 0x2?)
        k8s.io/kops/upup/pkg/fi/cloudup/openstacktasks/lb.go:153 +0xac
reflect.Value.call({0x10769ffc0?, 0x14000aa3b80?, 0x13?}, {0x105eb4bb9, 0x4}, {0x14001638168, 0x1, 0x0?})
        reflect/value.go:584 +0x688
reflect.Value.Call({0x10769ffc0?, 0x14000aa3b80?, 0x105ef0d18?}, {0x14001638168?, 0x140001cc740?, 0xa3a657461747320?})
        reflect/value.go:368 +0x90
k8s.io/kops/util/pkg/reflectutils.InvokeMethod({0x10769ffc0, 0x14000aa3b80}, {0x105eb4c55, 0x4}, {0x140016f5dc8, 0x1, 0x2020202020202020?})
        k8s.io/kops/util/pkg/reflectutils/walk.go:78 +0x348
k8s.io/kops/upup/pkg/fi.invokeFind[...]({0x107adb180, 0x14000aa3b80?}, 0x2?)
        k8s.io/kops/upup/pkg/fi/default_methods.go:144 +0x64
k8s.io/kops/upup/pkg/fi.defaultDeltaRunMethod[...]({0x107adb180, 0x14000aa3b80?}, 0x14000ffce10)
        k8s.io/kops/upup/pkg/fi/default_methods.go:68 +0x120
k8s.io/kops/upup/pkg/fi.CloudupDefaultDeltaRunMethod(...)
        k8s.io/kops/upup/pkg/fi/default_methods.go:41
k8s.io/kops/upup/pkg/fi/cloudup/openstacktasks.(*LB).Run(0x14000dc8720?, 0x107adb180?)
        k8s.io/kops/upup/pkg/fi/cloudup/openstacktasks/lb.go:174 +0x34
k8s.io/kops/upup/pkg/fi.(*executor[...]).forkJoin.func1(0x5)
        k8s.io/kops/upup/pkg/fi/executor.go:195 +0x250
created by k8s.io/kops/upup/pkg/fi.(*executor[...]).forkJoin
        k8s.io/kops/upup/pkg/fi/executor.go:183 +0xcc
```

**6. What did you expect to happen?**

**7. Please provide your cluster manifest. Execute
  `kops get --name my.example.com -o yaml` to display your cluster manifest.
  You may want to remove your cluster name and other sensitive information.**

```yaml
```

**8. Please run the commands with most verbose logging by adding the `-v 10` flag.
  Paste the logs into this report, or in a gist and provide the gist link here.**

**9. Anything else do we need to know?**


Pull request:
set loadbalancer configs before initializing the OS clients
fixes #14886 

the problem was that Openstack cloud clients were called and initialised before setting up base setup for loadbalancer.

cc @olemarkus I think you modified this part of code sometime ago.

Patch:
diff --git a/upup/pkg/fi/cloudup/new_cluster.go b/upup/pkg/fi/cloudup/new_cluster.go
index 12b7259c2a..78227a3f52 100644
--- a/upup/pkg/fi/cloudup/new_cluster.go
+++ b/upup/pkg/fi/cloudup/new_cluster.go
@@ -333,6 +333,7 @@ func NewCluster(opt *NewClusterOptions, clientset simple.Clientset) (*NewCluster
 				MaxRetries: fi.PtrTo(3),
 			},
 		}
+		initializeOpenstackAPI(opt, cluster)
 		osCloud, err := openstack.NewOpenstackCloud(cluster, "openstackmodel")
 		if err != nil {
 			return nil, err
@@ -1324,9 +1325,7 @@ func setupTopology(opt *NewClusterOptions, cluster *api.Cluster, allZones sets.S
 func setupAPI(opt *NewClusterOptions, cluster *api.Cluster) error {
 	// Populate the API access, so that it can be discoverable
 	klog.Infof("Cloud Provider ID: %q", cluster.Spec.GetCloudProvider())
-	if cluster.Spec.GetCloudProvider() == api.CloudProviderOpenstack {
-		initializeOpenstackAPI(opt, cluster)
-	} else if cluster.Spec.GetCloudProvider() == api.CloudProviderAzure {
+	if cluster.Spec.GetCloudProvider() == api.CloudProviderAzure {
 		// Do nothing to disable the use of loadbalancer for the k8s API server.
 		// TODO(kenji): Remove this condition once we support the loadbalancer
 		// in pkg/model/azuremodel/api_loadbalancer.go.
diff --git a/upup/pkg/fi/cloudup/openstack/cloud.go b/upup/pkg/fi/cloudup/openstack/cloud.go
index 0c04076e77..3c6fa44b07 100644
--- a/upup/pkg/fi/cloudup/openstack/cloud.go
+++ b/upup/pkg/fi/cloudup/openstack/cloud.go
@@ -363,12 +363,15 @@ func NewOpenstackCloud(cluster *kops.Cluster, uagent string) (OpenstackCloud, er
 		return nil, fmt.Errorf("error building openstack authenticated client: %v", err)
 	}
 
-	tags := map[string]string{
-		TagClusterName: cluster.Name,
+	if cluster != nil {
+		hasDNS := !cluster.IsGossip() && !cluster.UsesNoneDNS()
+		tags := map[string]string{
+			TagClusterName: cluster.Name,
+		}
+		return buildClients(provider, tags, cluster.Spec.CloudProvider.Openstack, config, region, hasDNS)
 	}
-
-	hasDNS := !cluster.IsGossip() && !cluster.UsesNoneDNS()
-	return buildClients(provider, tags, cluster.Spec.CloudProvider.Openstack, config, region, hasDNS)
+	// used by protokube
+	return buildClients(provider, nil, nil, config, region, false)
 }
 
 func buildClients(provider *gophercloud.ProviderClient, tags map[string]string, spec *kops.OpenstackSpec, config vfs.OpenstackConfig, region string, hasDNS bool) (OpenstackCloud, error) {


Test patch:
diff --git a/tests/integration/create_cluster/ha_openstack/expected-v1alpha2.yaml b/tests/integration/create_cluster/ha_openstack/expected-v1alpha2.yaml
index e3540b18ba..fdef2d2274 100644
--- a/tests/integration/create_cluster/ha_openstack/expected-v1alpha2.yaml
+++ b/tests/integration/create_cluster/ha_openstack/expected-v1alpha2.yaml
@@ -4,6 +4,9 @@ metadata:
   creationTimestamp: "2017-01-01T00:00:00Z"
   name: minimal.k8s.local
 spec:
+  api:
+    loadBalancer:
+      type: Public
   authorization:
     rbac: {}
   channel: stable