diff --git a/pkg/client/openstack/factory.go b/pkg/client/openstack/factory.go index 6dd538abb1..2a35dd3499 100644 --- a/pkg/client/openstack/factory.go +++ b/pkg/client/openstack/factory.go @@ -35,22 +35,22 @@ type NotAvailableFactory struct { } func (_ NotAvailableFactory) KlusterClientFor(*kubernikus_v1.Kluster) (openstack_kluster.KlusterClient, error) { - return nil, errors.New("Openstack not configured") + return nil, errors.New("Openstack not configured #1") } func (_ NotAvailableFactory) ProjectClientFor(authOptions *tokens.AuthOptions) (openstack_project.ProjectClient, error) { - return nil, errors.New("Openstack not configured") + return nil, errors.New("Openstack not configured #2") } func (_ NotAvailableFactory) ProjectAdminClientFor(string) (openstack_project.ProjectClient, error) { - return nil, errors.New("Openstack not configured") + return nil, errors.New("Openstack not configured #3") } func (_ NotAvailableFactory) ProviderClientFor(authOptions *tokens.AuthOptions, logger log.Logger) (*gophercloud.ProviderClient, error) { - return nil, errors.New("Openstack not configured") + return nil, errors.New("Openstack not configured #4") } func (_ NotAvailableFactory) ProviderClientForKluster(kluster *kubernikus_v1.Kluster, logger log.Logger) (*gophercloud.ProviderClient, error) { - return nil, errors.New("Openstack not configured") + return nil, errors.New("Openstack not configured #5") } func (_ NotAvailableFactory) AdminClient() (admin.AdminClient, error) { - return nil, errors.New("Openstack not configured") + return nil, errors.New("Openstack not configured #6") } type factory struct { @@ -222,27 +222,27 @@ func (f *factory) ProviderClientFor(authOptions *tokens.AuthOptions, logger log. func (f *factory) serviceClientsFor(authOptions *tokens.AuthOptions, logger log.Logger) (*gophercloud.ServiceClient, *gophercloud.ServiceClient, *gophercloud.ServiceClient, *gophercloud.ServiceClient, error) { providerClient, err := f.ProviderClientFor(authOptions, logger) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, nil, nil, fmt.Errorf("Can't create provider client: %v", err) } identity, err := openstack.NewIdentityV3(providerClient, gophercloud.EndpointOpts{}) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, nil, nil, fmt.Errorf("Can't create identity client: %v", err) } compute, err := openstack.NewComputeV2(providerClient, gophercloud.EndpointOpts{}) compute.Microversion = "2.52" // 2.52 supports specifying server tags during create if err != nil { - return nil, nil, nil, nil, err + return nil, nil, nil, nil, fmt.Errorf("Can't create compute client: %v", err) } network, err := openstack.NewNetworkV2(providerClient, gophercloud.EndpointOpts{}) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, nil, nil, fmt.Errorf("Can't create network client: %v", err) } image, err := openstack.NewImageServiceV2(providerClient, gophercloud.EndpointOpts{}) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, nil, nil, fmt.Errorf("Can't create image client: %v", err) } return identity, compute, network, image, nil diff --git a/pkg/cmd/kubernikus/operator.go b/pkg/cmd/kubernikus/operator.go index 858e354c25..d9557c4f99 100644 --- a/pkg/cmd/kubernikus/operator.go +++ b/pkg/cmd/kubernikus/operator.go @@ -62,6 +62,9 @@ func (o *Options) BindFlags(flags *pflag.FlagSet) { flags.StringVar(&o.Context, "context", "", "Override context") flags.StringVar(&o.ChartDirectory, "chart-directory", o.ChartDirectory, "Directory containing the kubernikus related charts") flags.StringVar(&o.Region, "region", o.Region, "Local region. (used for container image localization)") + flags.StringVar(&o.ApplicationCredentialID, "application-credential-id", o.ApplicationCredentialID, "Openstack application credential id") + flags.StringVar(&o.ApplicationCredentialName, "application-credential-name", o.ApplicationCredentialName, "Openstack application credential name") + flags.StringVar(&o.ApplicationCredentialSecret, "application-credential-secret", o.ApplicationCredentialSecret, "Openstack application credential secret") flags.StringVar(&o.AuthURL, "auth-url", o.AuthURL, "Openstack keystone url") flags.StringVar(&o.AuthUsername, "auth-username", o.AuthUsername, "Service user for kubernikus") flags.StringVar(&o.AuthPassword, "auth-password", "", "Service user password (if unset its read from env var OS_PASSWORD)") @@ -86,8 +89,20 @@ func (o *Options) Validate(c *cobra.Command, args []string) error { o.AuthPassword = os.Getenv("OS_PASSWORD") } - if o.AuthURL != "" && o.AuthPassword == "" { - return errors.New("you must specify the auth-password flag") + if o.ApplicationCredentialID == "" { + o.ApplicationCredentialID = os.Getenv("OS_APPLICATION_CREDENTIAL_ID") + } + + if o.ApplicationCredentialName == "" { + o.ApplicationCredentialName = os.Getenv("OS_APPLICATION_CREDENTIAL_NAME") + } + + if o.ApplicationCredentialSecret == "" { + o.ApplicationCredentialSecret = os.Getenv("OS_APPLICATION_CREDENTIAL_SECRET") + } + + if o.AuthURL != "" && o.AuthPassword == "" && o.ApplicationCredentialSecret == "" { + return errors.New("you must specify the auth-password or application credential flag") } return nil diff --git a/pkg/controller/config/config.go b/pkg/controller/config/config.go index e6d11f09a9..0201369bf5 100644 --- a/pkg/controller/config/config.go +++ b/pkg/controller/config/config.go @@ -20,12 +20,15 @@ type Controller interface { } type OpenstackConfig struct { - AuthURL string - AuthUsername string - AuthPassword string - AuthDomain string - AuthProject string - AuthProjectDomain string + ApplicationCredentialID string + ApplicationCredentialName string + ApplicationCredentialSecret string + AuthURL string + AuthUsername string + AuthPassword string + AuthDomain string + AuthProject string + AuthProjectDomain string } type HelmConfig struct { diff --git a/pkg/controller/operator.go b/pkg/controller/operator.go index 83347e6e45..e024357396 100644 --- a/pkg/controller/operator.go +++ b/pkg/controller/operator.go @@ -41,13 +41,16 @@ type KubernikusOperatorOptions struct { ChartDirectory string - AuthURL string - AuthUsername string - AuthPassword string - AuthDomain string - AuthProject string - AuthProjectDomain string - Region string + ApplicationCredentialID string + ApplicationCredentialName string + ApplicationCredentialSecret string + AuthURL string + AuthUsername string + AuthPassword string + AuthDomain string + AuthProject string + AuthProjectDomain string + Region string KubernikusDomain string KubernikusProjectID string @@ -81,13 +84,6 @@ func NewKubernikusOperator(options *KubernikusOperatorOptions, logger log.Logger o := &KubernikusOperator{ Config: config.Config{ - Openstack: config.OpenstackConfig{ - AuthURL: options.AuthURL, - AuthUsername: options.AuthUsername, - AuthPassword: options.AuthPassword, - AuthProject: options.AuthProjectDomain, - AuthProjectDomain: options.AuthProjectDomain, - }, Helm: config.HelmConfig{ ChartDirectory: options.ChartDirectory, }, @@ -103,6 +99,23 @@ func NewKubernikusOperator(options *KubernikusOperatorOptions, logger log.Logger Logger: logger, } + if options.ApplicationCredentialSecret != "" { + o.Config.Openstack = config.OpenstackConfig{ + ApplicationCredentialID: options.ApplicationCredentialID, + ApplicationCredentialName: options.ApplicationCredentialName, + ApplicationCredentialSecret: options.ApplicationCredentialSecret, + AuthURL: options.AuthURL, + } + } else { + o.Config.Openstack = config.OpenstackConfig{ + AuthURL: options.AuthURL, + AuthUsername: options.AuthUsername, + AuthPassword: options.AuthPassword, + AuthProject: options.AuthProjectDomain, + AuthProjectDomain: options.AuthProjectDomain, + } + } + o.Clients.Kubernetes, err = kube.NewClient(options.KubeConfig, options.Context, logger) if err != nil { @@ -132,16 +145,28 @@ func NewKubernikusOperator(options *KubernikusOperatorOptions, logger log.Logger return nil, fmt.Errorf("Couldn't create CRD: %s", err) } - adminAuthOptions := &tokens.AuthOptions{ - IdentityEndpoint: options.AuthURL, - Username: options.AuthUsername, - Password: options.AuthPassword, - DomainName: options.AuthDomain, - AllowReauth: true, - Scope: tokens.Scope{ - ProjectName: options.AuthProject, - DomainName: options.AuthProjectDomain, - }, + var adminAuthOptions *tokens.AuthOptions + + if options.ApplicationCredentialSecret != "" { + adminAuthOptions = &tokens.AuthOptions{ + IdentityEndpoint: options.AuthURL, + ApplicationCredentialID: options.ApplicationCredentialID, + ApplicationCredentialName: options.ApplicationCredentialName, + ApplicationCredentialSecret: options.ApplicationCredentialSecret, + AllowReauth: true, + } + } else { + adminAuthOptions = &tokens.AuthOptions{ + IdentityEndpoint: options.AuthURL, + Username: options.AuthUsername, + Password: options.AuthPassword, + DomainName: options.AuthDomain, + AllowReauth: true, + Scope: tokens.Scope{ + ProjectName: options.AuthProject, + DomainName: options.AuthProjectDomain, + }, + } } o.Factories.Kubernikus = kubernikus_informers.NewFilteredSharedInformerFactory(o.Clients.Kubernikus, DEFAULT_RECONCILIATION, options.Namespace, nil)