Skip to content

Commit

Permalink
Allow authentication through environment variables
Browse files Browse the repository at this point in the history
  • Loading branch information
baurmatt committed Dec 6, 2024
1 parent 7c73ab7 commit 295d815
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 18 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The following parameters are supported:
|-----------------------|--------|-------------|
| `cloud` | string | Name of the cloud config from clouds.yaml to use |
| `clouds_config` | string | Optional. Path to clouds.yaml |
| `auth_from_env` | bool | Optional. Use environment variables for authentication |
| `name` | string | Name of the Auto Scaling Group (unique string that used to find instances) |
| `nova_microversion` | string | Optional. Microversion for the Openstack Nova client. Default 2.79 (which should be ok for Train+) |
| `boot_time` | string | Optional. Maximum wait time for instance to boot up. During that time plugin check Cloud-Init signatures. |
Expand All @@ -38,6 +39,8 @@ OpenStack setup
1. You should create a special user (recommended) and project (optional),
then export clouds.yaml with credentials for that cloud.

1. Optional: You can also use OS\_\* environment variables to authenticate.

2. You may create a tenant network for workers, in that case don't forget to add a router.
In that case manager VM should have two ports: external and that tenant network,
so it will be able to connect to the worker instances.
Expand Down
74 changes: 56 additions & 18 deletions provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package fpoc
import (
"bytes"
"context"
"crypto/tls"
"errors"
"fmt"
"os"
"path"
"sync/atomic"
"time"
Expand All @@ -29,6 +31,7 @@ var _ provider.InstanceGroup = (*InstanceGroup)(nil)
type InstanceGroup struct {
Cloud string `json:"cloud"` // cloud to use
CloudsConfig string `json:"clouds_config"` // optional: path to clouds.yaml
AuthFromEnv bool `json:"auth_from_env"` // optional: Use environment variables for authentication
Name string `json:"name"` // name of the cluster
NovaMicroversion string `json:"nova_microversion"` // Microversion for the Nova client
ServerSpec ExtCreateOpts `json:"server_spec"` // instance creation spec
Expand All @@ -45,25 +48,15 @@ type InstanceGroup struct {
}

func (g *InstanceGroup) Init(ctx context.Context, log hclog.Logger, settings provider.Settings) (provider.ProviderInfo, error) {
pOpts := []clouds.ParseOption{clouds.WithCloudName(g.Cloud)}
if g.CloudsConfig != "" {
pOpts = append(pOpts, clouds.WithLocations(g.CloudsConfig))
}

ao, eo, tlsCfg, err := clouds.Parse(pOpts...)
if err != nil {
return provider.ProviderInfo{}, fmt.Errorf("Failed to parse clouds.yaml: %w", err)
}

// plugin is a long running process. force allow reauth
ao.AllowReauth = true
g.log = log.With("name", g.Name, "cloud", g.Cloud)
g.log.Debug("Initializing fleeting-plugin-openstack")

pc, err := config.NewProviderClient(ctx, ao, config.WithTLSConfig(tlsCfg))
providerClient, endpointOps, err := g.getProviderClient(ctx)
if err != nil {
return provider.ProviderInfo{}, fmt.Errorf("Failed to connect to OpenStack Keystone: %w", err)
return provider.ProviderInfo{}, err
}

cli, err := openstack.NewComputeV2(pc, eo)
cli, err := openstack.NewComputeV2(providerClient, endpointOps)
if err != nil {
return provider.ProviderInfo{}, fmt.Errorf("Failed to connect to OpenStack Nova: %w", err)
}
Expand All @@ -85,7 +78,7 @@ func (g *InstanceGroup) Init(ctx context.Context, log hclog.Logger, settings pro
}

if g.ServerSpec.ImageRef != "" {
imgCli, err := openstack.NewImageV2(pc, eo)
imgCli, err := openstack.NewImageV2(providerClient, endpointOps)
if err != nil {
return provider.ProviderInfo{}, fmt.Errorf("Failed to get OpenStack Glance: %w", err)
}
Expand Down Expand Up @@ -121,8 +114,6 @@ func (g *InstanceGroup) Init(ctx context.Context, log hclog.Logger, settings pro
}

g.settings = settings
g.log = log.With("name", g.Name, "cloud", g.Cloud)

if _, err := g.getInstances(ctx); err != nil {
return provider.ProviderInfo{}, err
}
Expand All @@ -135,6 +126,53 @@ func (g *InstanceGroup) Init(ctx context.Context, log hclog.Logger, settings pro
}, nil
}

func (g *InstanceGroup) getProviderClient(ctx context.Context) (*gophercloud.ProviderClient, gophercloud.EndpointOpts, error) {
var endpointOps gophercloud.EndpointOpts
var authOptions gophercloud.AuthOptions
var providerClient *gophercloud.ProviderClient

if g.AuthFromEnv {
g.log.Debug("Using env vars for auth")

var err error
endpointOps = gophercloud.EndpointOpts{Region: os.Getenv("OS_REGION_NAME")}
authOptions, err = openstack.AuthOptionsFromEnv()
if err != nil {
return nil, gophercloud.EndpointOpts{}, fmt.Errorf("Failed to get auth options from environment: %w", err)
}
authOptions.AllowReauth = true

providerClient, err = openstack.AuthenticatedClient(ctx, authOptions)
if err != nil {
return nil, gophercloud.EndpointOpts{}, fmt.Errorf("Failed to connect to OpenStack Keystone: %w", err)
}
} else {
g.log.Debug("Using clouds.yaml for auth")

var err error
var tlsCfg *tls.Config
cloudOpts := []clouds.ParseOption{clouds.WithCloudName(g.Cloud)}
if g.CloudsConfig != "" {
cloudOpts = append(cloudOpts, clouds.WithLocations(g.CloudsConfig))
}

authOptions, endpointOps, tlsCfg, err = clouds.Parse(cloudOpts...)
if err != nil {
return nil, gophercloud.EndpointOpts{}, fmt.Errorf("Failed to parse clouds.yaml: %w", err)
}

// plugin is a long running process. force allow reauth
authOptions.AllowReauth = true

providerClient, err = config.NewProviderClient(ctx, authOptions, config.WithTLSConfig(tlsCfg))
if err != nil {
return nil, gophercloud.EndpointOpts{}, fmt.Errorf("Failed to connect to OpenStack Keystone: %w", err)
}
}

return providerClient, endpointOps, nil
}

func (g *InstanceGroup) Update(ctx context.Context, update func(instance string, state provider.State)) error {

instances, err := g.getInstances(ctx)
Expand Down

0 comments on commit 295d815

Please sign in to comment.