Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions pkg/asset/manifests/openstack/cloudproviderconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package openstack

import (
"context"
"errors"
"os"
"strconv"
"strings"
Expand All @@ -25,6 +26,27 @@ type Error struct {
func (e Error) Error() string { return e.msg + ": " + e.err.Error() }
func (e Error) Unwrap() error { return e.err }

// isOctaviaAvailable checks if the Octavia (load-balancer) endpoint exists
// in the OpenStack service catalog.
func isOctaviaAvailable(ctx context.Context, clientOpts *clientconfig.ClientOpts) bool {
if clientOpts == nil {
// If no client options provided, assume Octavia is available
// to maintain backward compatibility
return true
}
_, err := openstackdefaults.NewServiceClient(ctx, "load-balancer", clientOpts)
if err != nil {
var gerr *gophercloud.ErrEndpointNotFound
if errors.As(err, &gerr) {
return false
}
// For other errors, assume Octavia might be available
// to avoid incorrectly disabling it
return true
}
return true
}

// CloudProviderConfigSecret generates the cloud provider config for the OpenStack
// platform, that will be stored in the system secret.
// TODO: I think this is crud for the legacy cloud-provider and is no longer needed. Burn it with fire?
Expand Down Expand Up @@ -78,7 +100,7 @@ func CloudProviderConfigSecret(cloud *clientconfig.Cloud) ([]byte, error) {
return []byte(res.String()), nil
}

func generateCloudProviderConfig(ctx context.Context, networkClient *gophercloud.ServiceClient, cloudConfig *clientconfig.Cloud, installConfig types.InstallConfig) (cloudProviderConfigData, cloudProviderConfigCABundleData string, err error) {
func generateCloudProviderConfig(ctx context.Context, networkClient *gophercloud.ServiceClient, cloudConfig *clientconfig.Cloud, clientOpts *clientconfig.ClientOpts, installConfig types.InstallConfig) (cloudProviderConfigData, cloudProviderConfigCABundleData string, err error) {
cloudProviderConfigData = `[Global]
secret-name = openstack-credentials
secret-namespace = kube-system
Expand All @@ -96,7 +118,13 @@ secret-namespace = kube-system
cloudProviderConfigCABundleData = string(caFile)
}

if installConfig.OpenStack.ExternalNetwork != "" {
switch {
case !isOctaviaAvailable(ctx, clientOpts):
// Explicitly disable LoadBalancer when Octavia is not available
// to prevent CCM from crashing on startup.
// See: https://issues.redhat.com/browse/OCPBUGS-64842
cloudProviderConfigData += "\n[LoadBalancer]\nenabled = false\n"
case installConfig.OpenStack.ExternalNetwork != "":
networkName := installConfig.OpenStack.ExternalNetwork // Yes, we use a name in install-config.yaml :/
networkID, err := networkutils.IDFromName(ctx, networkClient, networkName)
if err != nil {
Expand All @@ -123,5 +151,5 @@ func GenerateCloudProviderConfig(ctx context.Context, installConfig types.Instal
return "", "", Error{err, "failed to create a network client"}
}

return generateCloudProviderConfig(ctx, networkClient, session.CloudConfig, installConfig)
return generateCloudProviderConfig(ctx, networkClient, session.CloudConfig, session.ClientOpts, installConfig)
}
2 changes: 1 addition & 1 deletion pkg/asset/manifests/openstack/cloudproviderconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ region = my_region

for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
actualConfig, _, err := generateCloudProviderConfig(context.Background(), nil, &cloud, *tc.installConfig)
actualConfig, _, err := generateCloudProviderConfig(context.Background(), nil, &cloud, nil, *tc.installConfig)
assert.NoError(t, err, "unexpected error when generating cloud provider config")
assert.Equal(t, tc.expectedConfig, actualConfig, "unexpected cloud provider config")
})
Expand Down