mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
license cli commands
cli changes, formatting
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package api
|
||||
|
||||
import "strconv"
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Operator can be used to perform low-level operator tasks for Nomad.
|
||||
type Operator struct {
|
||||
@@ -176,3 +179,85 @@ func (op *Operator) SchedulerCASConfiguration(conf *SchedulerConfiguration, q *W
|
||||
|
||||
return &out, wm, nil
|
||||
}
|
||||
|
||||
type License struct {
|
||||
// The unique identifier of the license
|
||||
LicenseID string `json:"license_id"`
|
||||
|
||||
// The customer ID associated with the license
|
||||
CustomerID string `json:"customer_id"`
|
||||
|
||||
// If set, an identifier that should be used to lock the license to a
|
||||
// particular site, cluster, etc.
|
||||
InstallationID string `json:"installation_id"`
|
||||
|
||||
// The time at which the license was issued
|
||||
IssueTime time.Time `json:"issue_time"`
|
||||
|
||||
// The time at which the license starts being valid
|
||||
StartTime time.Time `json:"start_time"`
|
||||
|
||||
// The time after which the license expires
|
||||
ExpirationTime time.Time `json:"expiration_time"`
|
||||
|
||||
// The time at which the license ceases to function and can
|
||||
// no longer be used in any capacity
|
||||
TerminationTime time.Time `json:"termination_time"`
|
||||
|
||||
// The product the license is valid for
|
||||
Product string `json:"product"`
|
||||
|
||||
// License Specific Flags
|
||||
Flags map[string]interface{} `json:"flags"`
|
||||
|
||||
// Modules is a list of the licensed enterprise modules
|
||||
Modules []string `json:"modules"`
|
||||
|
||||
// List of features enabled by the license
|
||||
Features []string `json:"features"`
|
||||
}
|
||||
|
||||
type LicenseReply struct {
|
||||
Valid bool
|
||||
License *License
|
||||
Warnings []string
|
||||
QueryMeta
|
||||
}
|
||||
|
||||
func (op *Operator) LicensePut(license string, q *WriteOptions) (*LicenseReply, *WriteMeta, error) {
|
||||
var resp LicenseReply
|
||||
wm, err := op.c.write("/v1/operator/license", license, &resp, q)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &resp, wm, nil
|
||||
}
|
||||
|
||||
func (op *Operator) LicenseGet(q *QueryOptions) (*LicenseReply, *QueryMeta, error) {
|
||||
var reply LicenseReply
|
||||
qm, err := op.c.query("/v1/operator/license", &reply, q)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &reply, qm, nil
|
||||
}
|
||||
|
||||
func (op *Operator) LicenseGetSigned(q *QueryOptions) (string, *QueryMeta, error) {
|
||||
var reply string
|
||||
qm, err := op.c.query("/v1/operator/license?signed=true", &reply, q)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return reply, qm, nil
|
||||
}
|
||||
|
||||
// LicenseReset will reset the license to the builtin one if it is still valid.
|
||||
// If the builtin license is invalid, the current license stays active
|
||||
func (op *Operator) LicenseReset(q *WriteOptions) (*LicenseReply, *WriteMeta, error) {
|
||||
var reply LicenseReply
|
||||
wm, err := op.c.delete("/v1/operator/license", &reply, q)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &reply, wm, nil
|
||||
}
|
||||
|
||||
@@ -361,6 +361,21 @@ func Commands(metaPtr *Meta, agentUi cli.Ui) map[string]cli.CommandFactory {
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
"license": func() (cli.Command, error) {
|
||||
return &LicenseCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
"license get": func() (cli.Command, error) {
|
||||
return &LicenseGetCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
"license put": func() (cli.Command, error) {
|
||||
return &LicensePutCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
"logs": func() (cli.Command, error) {
|
||||
return &AllocLogsCommand{
|
||||
Meta: meta,
|
||||
|
||||
99
command/license.go
Normal file
99
command/license.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/nomad/api"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
type LicenseCommand struct {
|
||||
Meta
|
||||
}
|
||||
|
||||
func (l *LicenseCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: nomad license <subcommand> [options] [args]
|
||||
|
||||
This command has subcommands for managing the Nomad Enterprise license.
|
||||
For more detailed examples see:
|
||||
https://www.nomadproject.io/docs/commands/license/
|
||||
|
||||
Install a new license from a file:
|
||||
$ nomad license put @nomad.license
|
||||
|
||||
Install a new license from stdin:
|
||||
$ nomad license put -
|
||||
|
||||
Install a new license from a string:
|
||||
$ nomad license put "<license blob>"
|
||||
|
||||
Retrieve the current license:
|
||||
|
||||
$ nomad license get
|
||||
|
||||
Reset the current license:
|
||||
$ nomad license reset
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (l *LicenseCommand) Synopsis() string {
|
||||
return "Interact with Nomad Enterprise License"
|
||||
}
|
||||
|
||||
func (l *LicenseCommand) Name() string { return "license" }
|
||||
|
||||
func (l *LicenseCommand) Run(args []string) int {
|
||||
return cli.RunResultHelp
|
||||
}
|
||||
|
||||
func OutputLicenseReply(ui cli.Ui, resp *api.LicenseReply) int {
|
||||
if resp.Valid {
|
||||
ui.Output("License is valid")
|
||||
outputLicenseInfo(ui, resp.License, false)
|
||||
return 0
|
||||
} else if resp.License != nil {
|
||||
now := time.Now()
|
||||
if resp.License.ExpirationTime.Before(now) {
|
||||
ui.Output("License has expired!")
|
||||
outputLicenseInfo(ui, resp.License, true)
|
||||
} else {
|
||||
ui.Output("License is invalid!")
|
||||
for _, warn := range resp.Warnings {
|
||||
ui.Output(fmt.Sprintf(" %s", warn))
|
||||
}
|
||||
outputLicenseInfo(ui, resp.License, false)
|
||||
}
|
||||
return 1
|
||||
} else {
|
||||
// TODO - remove the expired message here in the future
|
||||
// once the go-licensing library is updated post 1.1
|
||||
ui.Output("Nomad is unlicensed or the license has expired")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func outputLicenseInfo(ui cli.Ui, lic *api.License, expired bool) {
|
||||
ui.Output(fmt.Sprintf("License ID: %s", lic.LicenseID))
|
||||
ui.Output(fmt.Sprintf("Customer ID: %s", lic.CustomerID))
|
||||
if expired {
|
||||
ui.Output(fmt.Sprintf("Expired At: %s", lic.ExpirationTime.String()))
|
||||
} else {
|
||||
ui.Output(fmt.Sprintf("Expires At: %s", lic.ExpirationTime.String()))
|
||||
}
|
||||
ui.Output(fmt.Sprintf("Terminates At: %s", lic.TerminationTime.String()))
|
||||
ui.Output(fmt.Sprintf("Datacenter: %s", lic.InstallationID))
|
||||
if len(lic.Modules) > 0 {
|
||||
ui.Output("Modules:")
|
||||
for _, mod := range lic.Modules {
|
||||
ui.Output(fmt.Sprintf("\t%v", mod))
|
||||
}
|
||||
}
|
||||
ui.Output("Licensed Features:")
|
||||
for _, f := range lic.Features {
|
||||
ui.Output(fmt.Sprintf("\t%s", f))
|
||||
}
|
||||
}
|
||||
63
command/license_get.go
Normal file
63
command/license_get.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type LicenseGetCommand struct {
|
||||
Meta
|
||||
}
|
||||
|
||||
func (c *LicenseGetCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: nomad license put [options]
|
||||
|
||||
Gets a new license in Servers and Clients
|
||||
General Options:
|
||||
|
||||
` + generalOptionsUsage() + `
|
||||
|
||||
Get Options:
|
||||
|
||||
-signed
|
||||
Determines if the returned license should be a signed blob instead of a
|
||||
parsed license.
|
||||
|
||||
`
|
||||
return helpText
|
||||
}
|
||||
|
||||
func (c *LicenseGetCommand) Synopsis() string {
|
||||
return "Install a new Nomad Enterprise License"
|
||||
}
|
||||
|
||||
func (c *LicenseGetCommand) Name() string { return "license get" }
|
||||
|
||||
func (c *LicenseGetCommand) Run(args []string) int {
|
||||
var signed bool
|
||||
|
||||
flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
|
||||
flags.Usage = func() { c.Ui.Output(c.Help()) }
|
||||
flags.BoolVar(&signed, "signed", false, "Gets the signed license blob instead of a parsed license")
|
||||
|
||||
client, err := c.Meta.Client()
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
|
||||
}
|
||||
|
||||
if signed {
|
||||
resp, _, err := client.Operator().LicenseGetSigned(nil)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error getting signed license: %v", err))
|
||||
}
|
||||
c.Ui.Output(resp)
|
||||
return 0
|
||||
}
|
||||
|
||||
resp, _, err := client.Operator().LicenseGet(nil)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error putting license: %v", err))
|
||||
}
|
||||
|
||||
return OutputLicenseReply(c.Ui, resp)
|
||||
}
|
||||
122
command/license_put.go
Normal file
122
command/license_put.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type LicensePutCommand struct {
|
||||
Meta
|
||||
|
||||
testStdin io.Reader
|
||||
}
|
||||
|
||||
func (c *LicensePutCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: nomad license put [options]
|
||||
|
||||
Puts a new license in Servers and Clients
|
||||
General Options:
|
||||
` + generalOptionsUsage() + `
|
||||
Install a new license from a file:
|
||||
$ nomad license put @nomad.license
|
||||
Install a new license from stdin:
|
||||
$ nomad license put -
|
||||
Install a new license from a string:
|
||||
$ nomad license put "<license blob>"
|
||||
`
|
||||
return helpText
|
||||
}
|
||||
|
||||
func (c *LicensePutCommand) Synopsis() string {
|
||||
return "Install a new Nomad Enterprise License"
|
||||
}
|
||||
|
||||
func (c *LicensePutCommand) Name() string { return "license put" }
|
||||
|
||||
func (c *LicensePutCommand) Run(args []string) int {
|
||||
flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
|
||||
flags.Usage = func() { c.Ui.Output(c.Help()) }
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error parsing flags: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
args = flags.Args()
|
||||
data, err := c.dataFromArgs(args)
|
||||
if err != nil {
|
||||
c.Ui.Error(errors.Wrap(err, "Error parsing arguments").Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
client, err := c.Meta.Client()
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
resp, _, err := client.Operator().LicensePut(data, nil)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error putting license: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
return OutputLicenseReply(c.Ui, resp)
|
||||
}
|
||||
|
||||
func (c *LicensePutCommand) dataFromArgs(args []string) (string, error) {
|
||||
switch len(args) {
|
||||
case 0:
|
||||
return "", fmt.Errorf("Missing LICENSE argument")
|
||||
case 1:
|
||||
return LoadDataSource(args[0], c.testStdin)
|
||||
default:
|
||||
return "", fmt.Errorf("Too many arguments, exptected 1, got %d", len(args))
|
||||
}
|
||||
}
|
||||
|
||||
func loadFromFile(path string) (string, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Failed to read file: %v", err)
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
func loadFromStdin(testStdin io.Reader) (string, error) {
|
||||
var stdin io.Reader = os.Stdin
|
||||
if testStdin != nil {
|
||||
stdin = testStdin
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
if _, err := io.Copy(&b, stdin); err != nil {
|
||||
return "", fmt.Errorf("Failed to read stdin: %v", err)
|
||||
}
|
||||
return b.String(), nil
|
||||
}
|
||||
|
||||
func LoadDataSource(data string, testStdin io.Reader) (string, error) {
|
||||
// Handle empty quoted shell parameters
|
||||
if len(data) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
switch data[0] {
|
||||
case '@':
|
||||
return loadFromFile(data[1:])
|
||||
case '-':
|
||||
if len(data) > 1 {
|
||||
return data, nil
|
||||
}
|
||||
return loadFromStdin(testStdin)
|
||||
default:
|
||||
return data, nil
|
||||
}
|
||||
}
|
||||
13
command/license_put_test.go
Normal file
13
command/license_put_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
var _ cli.Command = &LicensePutCommand{}
|
||||
|
||||
func TestCommand_LicensePut(t *testing.T) {
|
||||
// TODO create test once http endpoints are configured
|
||||
}
|
||||
Reference in New Issue
Block a user