Skip to content
Merged
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
41 changes: 28 additions & 13 deletions docs/user/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,34 @@ The installer accepts a number of environment variable that allow the interactiv

## General

| Environment Variable | Description |
|:----------------------------------|:--------------------------------------------------------------------------------------------|
| `OPENSHIFT_INSTALL_BASE_DOMAIN` | The base domain of the cluster. All DNS records will be sub-domains of this base. |
| `OPENSHIFT_INSTALL_CLUSTER_NAME` | The name of the cluster. This will be used when generating sub-domains. |
| `OPENSHIFT_INSTALL_EMAIL_ADDRESS` | The email address of the cluster administrator. This will be used to log in to the console. |
| `OPENSHIFT_INSTALL_PASSWORD` | The password of the cluster administrator. This will be used to log in to the console. |
| `OPENSHIFT_INSTALL_PLATFORM` | The platform onto which the cluster will be installed. |
| `OPENSHIFT_INSTALL_PULL_SECRET` | The container registry pull secret for this cluster. |
| `OPENSHIFT_INSTALL_SSH_PUB_KEY` | The SSH key used to access all nodes within the cluster. This is optional. |
* `OPENSHIFT_INSTALL_BASE_DOMAIN`:
The base domain of the cluster. All DNS records will be sub-domains of this base.

* `OPENSHIFT_INSTALL_CLUSTER_NAME`:
The name of the cluster.
This will be used when generating sub-domains.
* `OPENSHIFT_INSTALL_EMAIL_ADDRESS`:
The email address of the cluster administrator.
This will be used to log in to the console.
* `OPENSHIFT_INSTALL_PASSWORD`:
The password of the cluster administrator.
This will be used to log in to the console.
* `OPENSHIFT_INSTALL_PLATFORM`:
The platform onto which the cluster will be installed.
Valid values are `aws` and `libvirt`.
* `OPENSHIFT_INSTALL_PULL_SECRET`:
The container registry pull secret for this cluster (e.g. `{"auths": {...}}`).
You can generate these secrets with the `podman login` command.
* `OPENSHIFT_INSTALL_SSH_PUB_KEY`:
The SSH public key used to access all nodes within the cluster (e.g. `ssh-rsa AAAA...`).
This is optional.
* `OPENSHIFT_INSTALL_SSH_PUB_KEY_PATH`:
As an alternative to `OPENSHIFT_INSTALL_SSH_PUB_KEY`, you can configure this variable with a path containing your SSH public key (e.g. `~/.ssh/id_rsa.pub`).

## Platform-Specific

| Environment Variable | Description |
|:----------------------------------|:-----------------------------------------------------------------------------------------|
| `OPENSHIFT_INSTALL_AWS_REGION` | The AWS region to be used for installation. |
| `OPENSHIFT_INSTALL_LIBVIRT_URI` | The libvirt connection URI to be used. This must be accessible from the running cluster. |
* `OPENSHIFT_INSTALL_AWS_REGION`:
The AWS region to be used for installation.
* `OPENSHIFT_INSTALL_LIBVIRT_URI`:
The libvirt connection URI to be used.
This must be accessible from the running cluster.
112 changes: 81 additions & 31 deletions pkg/asset/installconfig/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package installconfig

import (
"fmt"
"net/url"
"sort"
"strings"

"github.com/AlecAivazis/survey"
Expand All @@ -18,6 +20,27 @@ const (

var (
validPlatforms = []string{AWSPlatformType, LibvirtPlatformType}

validAWSRegions = map[string]string{
"ap-northeast-1": "Tokyo",
"ap-northeast-2": "Seoul",
"ap-northeast-3": "Osaka-Local",
"ap-south-1": "Mumbai",
"ap-southeast-1": "Singapore",
"ap-southeast-2": "Sydney",
"ca-central-1": "Central",
"cn-north-1": "Beijing",
"cn-northwest-1": "Ningxia",
"eu-central-1": "Frankfurt",
"eu-west-1": "Ireland",
"eu-west-2": "London",
"eu-west-3": "Paris",
"sa-east-1": "São Paulo",
"us-east-1": "N. Virginia",
"us-east-2": "Ohio",
"us-west-1": "N. California",
"us-west-2": "Oregon",
}
)

// Platform is an asset that queries the user for the platform on which to install
Expand Down Expand Up @@ -62,10 +85,21 @@ func (a *Platform) Name() string {
}

func (a *Platform) queryUserForPlatform() (string, error) {
sort.Strings(validPlatforms)
prompt := asset.UserProvided{
Prompt: &survey.Select{
Message: "Platform",
Options: validPlatforms,
Question: &survey.Question{
Prompt: &survey.Select{
Message: "Platform",
Options: validPlatforms,
},
Validate: survey.ComposeValidators(survey.Required, func(ans interface{}) error {
choice := ans.(string)
i := sort.SearchStrings(validPlatforms, choice)
if i == len(validPlatforms) || validPlatforms[i] != choice {
return fmt.Errorf("invalid platform %q", choice)
}
return nil
}),
},
EnvVarName: "OPENSHIFT_INSTALL_PLATFORM",
}
Expand All @@ -79,31 +113,34 @@ func (a *Platform) queryUserForPlatform() (string, error) {
}

func (a *Platform) awsPlatform() (*asset.State, error) {
longRegions := make([]string, 0, len(validAWSRegions))
shortRegions := make([]string, 0, len(validAWSRegions))
for id, location := range validAWSRegions {
longRegions = append(longRegions, fmt.Sprintf("%s (%s)", id, location))
shortRegions = append(shortRegions, id)
}
regionTransform := survey.TransformString(func(s string) string {
return strings.SplitN(s, " ", 2)[0]
})
sort.Strings(longRegions)
sort.Strings(shortRegions)
prompt := asset.UserProvided{
Prompt: &survey.Select{
Message: "Region",
Help: "The AWS region to be used for installation.",
Default: "us-east-1 (N. Virginia)",
Options: []string{
"us-east-2 (Ohio)",
"us-east-1 (N. Virginia)",
"us-west-1 (N. California)",
"us-west-2 (Oregon)",
"ap-south-1 (Mumbai)",
"ap-northeast-2 (Seoul)",
"ap-northeast-3 (Osaka-Local)",
"ap-southeast-1 (Singapore)",
"ap-southeast-2 (Sydney)",
"ap-northeast-1 (Tokyo)",
"ca-central-1 (Central)",
"cn-north-1 (Beijing)",
"cn-northwest-1 (Ningxia)",
"eu-central-1 (Frankfurt)",
"eu-west-1 (Ireland)",
"eu-west-2 (London)",
"eu-west-3 (Paris)",
"sa-east-1 (São Paulo)",
Question: &survey.Question{
Prompt: &survey.Select{
Message: "Region",
Help: "The AWS region to be used for installation.",
Default: "us-east-1 (N. Virginia)",
Options: longRegions,
},
Validate: survey.ComposeValidators(survey.Required, func(ans interface{}) error {
choice := regionTransform(ans).(string)
i := sort.SearchStrings(shortRegions, choice)
if i == len(shortRegions) || shortRegions[i] != choice {
return fmt.Errorf("invalid region %q", choice)
}
return nil
}),
Transform: regionTransform,
},
EnvVarName: "OPENSHIFT_INSTALL_AWS_REGION",
}
Expand All @@ -114,16 +151,29 @@ func (a *Platform) awsPlatform() (*asset.State, error) {

return assetStateForStringContents(
AWSPlatformType,
strings.Split(string(region.Contents[0].Data), " ")[0],
string(region.Contents[0].Data),
), nil
}

func (a *Platform) libvirtPlatform() (*asset.State, error) {
prompt := asset.UserProvided{
Prompt: &survey.Input{
Message: "URI",
Help: "The libvirt connection URI to be used. This must be accessible from the running cluster.",
Default: "qemu+tcp://192.168.122.1/system",
Question: &survey.Question{
Prompt: &survey.Input{
Message: "URI",
Help: "The libvirt connection URI to be used. This must be accessible from the running cluster.",
Default: "qemu+tcp://192.168.122.1/system",
},
Validate: survey.ComposeValidators(survey.Required, func(ans interface{}) error {
value := ans.(string)
uri, err := url.Parse(value)
if err != nil {
return err
}
if uri.Scheme == "" {
return fmt.Errorf("invalid URI %q (no scheme)", value)
}
return nil
}),
},
EnvVarName: "OPENSHIFT_INSTALL_LIBVIRT_URI",
}
Expand Down
72 changes: 53 additions & 19 deletions pkg/asset/installconfig/ssh.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package installconfig

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
Expand All @@ -23,42 +24,68 @@ func (a *sshPublicKey) Dependencies() []asset.Asset {
return nil
}

func readSSHKey(path string) (key []byte, err error) {
key, err = ioutil.ReadFile(path)
if err != nil {
return key, err
}

err = validate.OpenSSHPublicKey(string(key))
if err != nil {
return key, err
}

return key, nil
}

// Generate generates the SSH public key asset.
func (a *sshPublicKey) Generate(map[asset.Asset]*asset.State) (state *asset.State, err error) {
if value, ok := os.LookupEnv("OPENSHIFT_INSTALL_SSH_PUB_KEY"); ok {
if value != "" {
if err := validate.OpenSSHPublicKey(value); err != nil {
return nil, err
}
}
return &asset.State{
Contents: []asset.Content{{
Data: []byte(value),
}},
}, nil
}

pubKeys := map[string][]byte{
none: {},
}
home := os.Getenv("HOME")
if home != "" {
paths, err := filepath.Glob(filepath.Join(home, ".ssh", "*.pub"))
pubKeys := map[string][]byte{}
if path, ok := os.LookupEnv("OPENSHIFT_INSTALL_SSH_PUB_KEY_PATH"); ok {
key, err := readSSHKey(path)
if err != nil {
return nil, err
}

for _, path := range paths {
pubKeyBytes, err := ioutil.ReadFile(path)
pubKeys[path] = key
} else {
pubKeys[none] = []byte{}
home := os.Getenv("HOME")
if home != "" {
paths, err := filepath.Glob(filepath.Join(home, ".ssh", "*.pub"))
if err != nil {
continue
return nil, err
}
pubKey := string(pubKeyBytes)

err = validate.OpenSSHPublicKey(pubKey)
if err != nil {
continue
for _, path := range paths {
key, err := readSSHKey(path)
if err != nil {
continue
}
pubKeys[path] = key
}

pubKeys[path] = pubKeyBytes
}
}

if len(pubKeys) == 1 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to allow the user to opt out of using a key at all.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to allow the user to opt out of using a key at all.

I think we do. Some cases:

  • You set OPENSHIFT_INSTALL_SSH_PUB_KEY and exit up here.
  • You set OPENSHIFT_INSTALL_SSH_PUB_KEY_PATH, get that single entry in your pubKeys, and exit here without a prompt.
  • You set no variables, so you get the <none> choice injected. Then...
    • Go finds no valid pubkeys in ~/.ssh/*.pub, and you exit here with the none choice selected.
    • Go finds some valid pubkeys in ~/.ssh/*.pub, and you pass by here and fall down to the interactive prompt.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that seems okay then.

return &asset.State{
Contents: []asset.Content{{
Data: []byte{},
}},
}, nil
}

var paths []string
for path := range pubKeys {
paths = append(paths, path)
Expand All @@ -68,10 +95,17 @@ func (a *sshPublicKey) Generate(map[asset.Asset]*asset.State) (state *asset.Stat
var path string
survey.AskOne(&survey.Select{
Message: "SSH Public Key",
Help: "The SSH key used to access all nodes within the cluster. This is optional.",
Help: "The SSH public key used to access all nodes within the cluster. This is optional.",
Options: paths,
Default: none,
}, &path, nil)
}, &path, func(ans interface{}) error {
choice := ans.(string)
i := sort.SearchStrings(paths, choice)
if i == len(paths) || paths[i] != choice {
return fmt.Errorf("invalid path %q", choice)
}
return nil
})

return &asset.State{
Contents: []asset.Content{{
Expand Down
Loading