Skip to content

Commit

Permalink
Merge pull request #66 from equinix/config-file
Browse files Browse the repository at this point in the history
load values from ~/.config/equinix/metal.yaml
  • Loading branch information
displague authored Sep 14, 2021
2 parents d2da49e + ae9742e commit a00bb7e
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 26 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go: [ '1.14' ]
go: [ '1.16' ]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.14
go-version: 1.16
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
Expand Down
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,37 @@ docker-machine create --driver metal

You can find the supported arguments by running `docker-machine create -d metal --help` (Equinix Metal specific arguments are shown below):

| Argument | Default | Description | Environment Variable |
| Argument | Default | Description | Environment | Config |
| --------------------------- | -------------- | ---------------------------------------------------------------------------- | ------------------------ |
| `--metal-api-key` | | Equinix Metal API Key | `METAL_AUTH_TOKEN` |
| `--metal-api-key` | | Equinix Metal API Key | `METAL_AUTH_TOKEN` | `token` or `auth-token`
| `--metal-billing-cycle` | `hourly` | Equinix Metal billing cycle, hourly or monthly | `METAL_BILLING_CYCLE` |
| `--metal-facility-code` | | Equinix Metal facility code | `METAL_FACILITY_CODE` |
| `--metal-facility-code` | | Equinix Metal facility code | `METAL_FACILITY_CODE` |`facility`
| `--metal-hw-reservation-id` | | Equinix Metal Reserved hardware ID | `METAL_HW_ID` |
| `--metal-metro-code` | | Equinix Metal metro code ("dc" is used if empty and facility is not set) | `METAL_METRO_CODE` |
| `--metal-os` | `ubuntu_20_04` | Equinix Metal OS | `METAL_OS` |
| `--metal-plan` | `c3.small.x86` | Equinix Metal Server Plan | `METAL_PLAN` |
| `--metal-project-id` | | Equinix Metal Project Id | `METAL_PROJECT_ID` |
| `--metal-metro-code` | | Equinix Metal metro code ("dc" is used if empty and facility is not set) | `METAL_METRO_CODE` |`metro`
| `--metal-os` | `ubuntu_20_04` | Equinix Metal OS | `METAL_OS` |`operating-system`
| `--metal-plan` | `c3.small.x86` | Equinix Metal Server Plan | `METAL_PLAN` |`plan`
| `--metal-project-id` | | Equinix Metal Project Id | `METAL_PROJECT_ID` |`project`
| `--metal-spot-instance` | | Request a Equinix Metal Spot Instance | `METAL_SPOT_INSTANCE` |
| `--metal-spot-price-max` | | The maximum Equinix Metal Spot Price | `METAL_SPOT_PRICE_MAX` |
| `--metal-termination-time` | | The Equinix Metal Instance Termination Time | `METAL_TERMINATION_TIME` |
| `--metal-ua-prefix` | | Prefix the User-Agent in Equinix Metal API calls with some 'product/version' | `METAL_UA_PREFIX` |
| `--metal-userdata` | | Path to file with cloud-init user-data | `METAL_USERDATA` |

Where denoted, values may be loaded from the environment or from the `~/.config/equinix/metal.yaml` file which can be created with the [Equinix Metal CLI](https://github.com/equinix/metal-cli#metal-cli).

### Example usage

This creates the following:

- c3.small.x86 machine
- in the NY metro
- with Ubuntu 16.04
- with Ubuntu 20.04
- in project $PROJECT
- Using $API_KEY - [get yours from the Portal](https://console.equinix.com/users/me/api-keys)

```sh
$ docker-machine create sloth \
--driver metal --metal-api-key=$API_KEY --metal-os=ubuntu_16_04 --metal-project-id=$PROJECT --metal-metro-code "ny" --metal-plan "c3.small.x86"
--driver metal --metal-api-key=$API_KEY --metal-os=ubuntu_20_04 --metal-project-id=$PROJECT --metal-metro-code "ny" --metal-plan "c3.small.x86"

Creating CA: /home/alex/.docker/machine/certs/ca.pem
Creating client certificate: /home/alex/.docker/machine/certs/cert.pem
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
module github.com/equinix/docker-machine-driver-metal

go 1.14
go 1.16

require (
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
github.com/carmo-evan/strtotime v0.0.0-20200108203155-3136cf889e3b
github.com/docker/docker v0.0.0-20180805161158-f57f260b49b6 // indirect
github.com/docker/machine v0.16.2
github.com/google/go-cmp v0.3.0 // indirect
github.com/packethost/packngo v0.13.0
github.com/packethost/packngo v0.17.0
github.com/pkg/errors v0.8.1 // indirect
github.com/sirupsen/logrus v1.6.0 // indirect
github.com/stretchr/testify v1.5.1
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 // indirect
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 // indirect
gotest.tools v2.2.0+incompatible // indirect
sigs.k8s.io/yaml v1.2.0
)
9 changes: 6 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/packethost/packngo v0.13.0 h1:VIeDY/Uju53v8LAKxiqTrfR9jkpX5PhWdnQC0h3aUU8=
github.com/packethost/packngo v0.13.0/go.mod h1:YrtUNN9IRjjqN6zK+cy2IYoi3EjHfoWTWxJkI1I1Vk0=
github.com/packethost/packngo v0.17.0 h1:fGPlj9NDt6ejOrAMfUgx955oCaR1QBKA9pec14m0L38=
github.com/packethost/packngo v0.17.0/go.mod h1:YrtUNN9IRjjqN6zK+cy2IYoi3EjHfoWTWxJkI1I1Vk0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand All @@ -40,7 +40,10 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
39 changes: 39 additions & 0 deletions pkg/drivers/metal/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: BSD-3-Clause

package metal

import (
"os"
"path"
"runtime"
)

type metalSnakeConfig struct {
Token string `json:"token,omitempty"`
AuthToken string `json:"auth-token,omitempty"`
Facility string `json:"facility,omitempty"`
Metro string `json:"metro,omitempty"`
OS string `json:"operating-system,omitempty"`
Plan string `json:"plan,omitempty"`
ProjectID string `json:"project-id,omitempty"`
}

func getConfigFile() string {
configFile := os.Getenv("METAL_CONFIG")
if configFile != "" {
return configFile
}

return path.Join(userHomeDir(), "/.config/equinix/metal.yaml")
}

func userHomeDir() string {
if runtime.GOOS == "windows" {
home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
if home == "" {
home = os.Getenv("USERPROFILE")
}
return home
}
return os.Getenv("HOME")
}
57 changes: 47 additions & 10 deletions pkg/drivers/metal/metal.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
package metal

import (
"errors"
"fmt"
"io/fs"
"io/ioutil"
"net/http"
"os"
Expand All @@ -18,6 +20,7 @@ import (
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"
"github.com/packethost/packngo"
"sigs.k8s.io/yaml"
)

const (
Expand Down Expand Up @@ -149,26 +152,60 @@ func (d *Driver) DriverName() string {
return "metal"
}

func (d *Driver) setConfigFromFile() error {
configFile := getConfigFile()

config := metalSnakeConfig{}

if raw, err := ioutil.ReadFile(configFile); err != nil {
if errors.Is(err, fs.ErrNotExist) {
return nil
}
return err
} else if jsonErr := yaml.Unmarshal(raw, &config); jsonErr != nil {
return jsonErr
}
d.Plan = config.Plan
d.ApiKey = config.AuthToken
if config.Token != "" {
d.ApiKey = config.Token
}
d.Facility = config.Facility
d.Metro = config.Metro
d.OperatingSystem = config.OS
d.ProjectID = config.ProjectID
return nil
}

func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
if strings.Contains(flags.String("metal-os"), "coreos") {
if err := d.setConfigFromFile(); err != nil {
return err
}
// override config file values with command-line values
for k, p := range map[string]*string{
"metal-os": &d.OperatingSystem,
"metal-api-key": &d.ApiKey,
"metal-project-id": &d.ProjectID,
"metal-metro-code": &d.Metro,
"metal-facility-code": &d.Facility,
"metal-plan": &d.Plan,
} {
if v := flags.String(k); v != "" {
*p = v
}
}

if strings.Contains(d.OperatingSystem, "coreos") {
d.SSHUser = "core"
}
if strings.Contains(flags.String("metal-os"), "rancher") {
if strings.Contains(d.OperatingSystem, "rancher") {
d.SSHUser = "rancher"
}

d.ApiKey = flags.String("metal-api-key")
d.ProjectID = flags.String("metal-project-id")
d.OperatingSystem = flags.String("metal-os")
d.Facility = flags.String("metal-facility-code")
d.Metro = flags.String("metal-metro-code")
d.BillingCycle = flags.String("metal-billing-cycle")
d.UserAgentPrefix = flags.String("metal-ua-prefix")
d.UserDataFile = flags.String("metal-userdata")

d.Plan = flags.String("metal-plan")
d.HardwareReserverationID = flags.String("metal-hw-reservation-id")

d.SpotInstance = flags.Bool("metal-spot-instance")

if d.SpotInstance {
Expand Down

0 comments on commit a00bb7e

Please sign in to comment.