2020-08-28 01:28:26 -04:00
package hostsets
import (
"fmt"
2020-09-15 01:08:21 -04:00
"net/http"
2020-08-28 01:28:26 -04:00
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hostsets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
2020-09-09 01:24:25 -04:00
"github.com/hashicorp/boundary/sdk/strutil"
2020-08-28 01:28:26 -04:00
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var _ cli . Command = ( * Command )( nil )
var _ cli . CommandAutocomplete = ( * Command )( nil )
type Command struct {
* base . Command
Func string
2020-10-02 19:20:30 -04:00
flagHosts [] string
2020-08-28 01:28:26 -04:00
}
func ( c * Command ) Synopsis () string {
2020-08-28 13:31:20 -04:00
switch c . Func {
2020-08-31 10:06:21 -04:00
case "add-hosts" :
2020-10-09 20:26:48 -04:00
return "Add hosts to the specified host set"
2020-08-31 10:06:21 -04:00
case "remove-hosts" :
2020-10-09 20:26:48 -04:00
return "Remove hosts from the specified host set"
2020-08-31 10:06:21 -04:00
case "set-hosts" :
2020-10-09 20:26:48 -04:00
return "Set the full contents of the hosts on the specified host set"
2020-08-28 13:31:20 -04:00
default :
2020-10-09 20:26:48 -04:00
return common . SynopsisFunc ( c . Func , "host set" )
2020-08-28 01:28:26 -04:00
}
}
var flagsMap = map [ string ][] string {
2020-08-31 10:06:21 -04:00
"read" : { "id" },
"delete" : { "id" },
2020-09-08 13:27:51 -07:00
"list" : { "host-catalog-id" },
2020-08-31 10:06:21 -04:00
"add-hosts" : { "id" , "host" , "version" },
"set-hosts" : { "id" , "host" , "version" },
"remove-hosts" : { "id" , "host" , "version" },
2020-08-28 01:28:26 -04:00
}
func ( c * Command ) Help () string {
2020-10-09 20:26:48 -04:00
helpMap := common . HelpMap ( "host set" )
2020-09-08 13:27:51 -07:00
var helpStr string
2020-08-28 01:28:26 -04:00
switch c . Func {
case "" :
return base . WrapForHelpText ([] string {
"Usage: boundary host-sets [sub command] [options] [args]" ,
"" ,
2020-10-09 20:26:48 -04:00
" This command allows operations on Boundary host set resources. Example:" ,
2020-08-28 01:28:26 -04:00
"" ,
2020-10-09 20:26:48 -04:00
" Read a host set:" ,
2020-08-28 01:28:26 -04:00
"" ,
` $ boundary host-sets read -id hsst_1234567890` ,
"" ,
" Please see the host-sets subcommand help for detailed usage information." ,
})
2020-08-28 13:31:20 -04:00
case "create" :
2020-09-08 13:27:51 -07:00
helpStr = base . WrapForHelpText ([] string {
2020-08-28 13:31:20 -04:00
"Usage: boundary host-sets create [type] [sub command] [options] [args]" ,
2020-08-28 01:28:26 -04:00
"" ,
2020-10-09 20:26:48 -04:00
" This command allows create operations on Boundary host set resources. Example:" ,
2020-08-28 01:28:26 -04:00
"" ,
2020-10-09 20:26:48 -04:00
" Create a static-type host set:" ,
2020-08-28 01:28:26 -04:00
"" ,
2020-08-28 13:31:20 -04:00
` $ boundary host-sets create static -name prodops -description "For ProdOps usage"` ,
2020-08-28 01:28:26 -04:00
"" ,
2020-08-28 13:31:20 -04:00
" Please see the typed subcommand help for detailed usage information." ,
})
case "update" :
2020-09-08 13:27:51 -07:00
helpStr = base . WrapForHelpText ([] string {
2020-08-28 13:31:20 -04:00
"Usage: boundary host-sets update [type] [sub command] [options] [args]" ,
"" ,
2020-10-09 20:26:48 -04:00
" This command allows update operations on Boundary host set resources. Example:" ,
2020-08-28 13:31:20 -04:00
"" ,
2020-10-09 20:26:48 -04:00
" Update a static-type host set:" ,
2020-08-28 13:31:20 -04:00
"" ,
` $ boundary host-sets update static -id hsst_1234567890 -name devops -description "For DevOps usage"` ,
"" ,
" Please see the typed subcommand help for detailed usage information." ,
2020-08-28 01:28:26 -04:00
})
2020-08-31 10:06:21 -04:00
case "add-hosts" :
2020-09-08 13:27:51 -07:00
helpStr = base . WrapForHelpText ([] string {
2020-08-31 10:06:21 -04:00
"Usage: boundary host-sets add-hosts [sub command] [options] [args]" ,
"" ,
2020-10-09 20:26:48 -04:00
" This command allows adding hosts to host set resources, if the types match and the operation is allowed by the given host set type. Example:" ,
2020-08-31 10:06:21 -04:00
"" ,
2020-10-09 20:26:48 -04:00
" Add static-type hosts to a static-type host set:" ,
2020-08-31 10:06:21 -04:00
"" ,
` $ boundary host-sets add-hosts -id hsst_1234567890 -host hst_1234567890 -host hst_0987654321` ,
})
case "remove-hosts" :
2020-09-08 13:27:51 -07:00
helpStr = base . WrapForHelpText ([] string {
2020-08-31 10:06:21 -04:00
"Usage: boundary host-sets remove-hosts [sub command] [options] [args]" ,
"" ,
2020-10-09 20:26:48 -04:00
" This command allows removing hosts from host set resources, if the types match and the operation is allowed by the given host set type. Example:" ,
2020-08-31 10:06:21 -04:00
"" ,
2020-10-09 20:26:48 -04:00
" Remove static-type hosts from a static-type host set:" ,
2020-08-31 10:06:21 -04:00
"" ,
` $ boundary host-sets remove-hosts -id hsst_1234567890 -host hst_0987654321` ,
})
case "set-hosts" :
2020-09-08 13:27:51 -07:00
helpStr = base . WrapForHelpText ([] string {
2020-08-31 10:06:21 -04:00
"Usage: boundary host-sets set-hosts [sub command] [options] [args]" ,
"" ,
2020-10-09 20:26:48 -04:00
" This command allows setting the complete set of hosts on host set resources, if the types match and the operation is allowed by the given host set type. Example:" ,
2020-08-31 10:06:21 -04:00
"" ,
2020-10-09 20:26:48 -04:00
" Set the complete set of static-type hosts on a static-type host set:" ,
2020-08-31 10:06:21 -04:00
"" ,
` $ boundary host-sets remove-hosts -id hsst_1234567890 -host hst_1234567890` ,
})
2020-08-28 01:28:26 -04:00
default :
2020-09-08 13:27:51 -07:00
helpStr = helpMap [ c . Func ]()
2020-08-28 01:28:26 -04:00
}
2020-09-08 13:27:51 -07:00
return helpStr + c . Flags (). Help ()
2020-08-28 01:28:26 -04:00
}
func ( c * Command ) Flags () * base . FlagSets {
2020-10-09 20:26:48 -04:00
if len ( flagsMap [ c . Func ]) == 0 {
return c . FlagSet ( base . FlagSetNone )
}
2020-08-28 01:28:26 -04:00
2020-10-09 20:26:48 -04:00
set := c . FlagSet ( base . FlagSetHTTP | base . FlagSetClient | base . FlagSetOutputFormat )
2020-08-28 01:28:26 -04:00
f := set . NewFlagSet ( "Command Options" )
2020-09-12 14:06:28 -04:00
common . PopulateCommonFlags ( c . Command , f , resource . HostSet . String (), flagsMap [ c . Func ])
2020-08-28 01:28:26 -04:00
2020-08-31 10:06:21 -04:00
for _ , name := range flagsMap [ c . Func ] {
switch name {
case "host" :
f . StringSliceVar ( & base . StringSliceVar {
Name : "host" ,
Target : & c . flagHosts ,
Usage : "The hosts to add, remove, or set. May be specified multiple times." ,
})
}
}
2020-08-28 01:28:26 -04:00
return set
}
func ( c * Command ) AutocompleteArgs () complete . Predictor {
return complete . PredictAnything
}
func ( c * Command ) AutocompleteFlags () complete . Flags {
return c . Flags (). Completions ()
}
func ( c * Command ) Run ( args [] string ) int {
2020-08-28 13:31:20 -04:00
switch c . Func {
case "" , "create" , "update" :
2020-08-28 01:28:26 -04:00
return cli . RunResultHelp
}
f := c . Flags ()
if err := f . Parse ( args ); err != nil {
c . UI . Error ( err . Error ())
return 1
}
if strutil . StrListContains ( flagsMap [ c . Func ], "id" ) && c . FlagId == "" {
c . UI . Error ( "ID is required but not passed in via -id" )
return 1
}
2020-10-02 19:20:30 -04:00
if strutil . StrListContains ( flagsMap [ c . Func ], "host-catalog-id" ) && c . FlagHostCatalogId == "" {
2020-09-08 13:27:51 -07:00
c . UI . Error ( "Host Catalog ID must be passed in via -host-catalog-id" )
return 1
}
2020-08-28 01:28:26 -04:00
client , err := c . Client ()
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Error creating API client: %s" , err . Error ()))
return 2
}
var opts [] hostsets . Option
switch c . FlagName {
case "" :
case "null" :
opts = append ( opts , hostsets . DefaultName ())
default :
opts = append ( opts , hostsets . WithName ( c . FlagName ))
}
switch c . FlagDescription {
case "" :
case "null" :
opts = append ( opts , hostsets . DefaultDescription ())
default :
opts = append ( opts , hostsets . WithDescription ( c . FlagDescription ))
}
2020-08-31 10:06:21 -04:00
hosts := c . flagHosts
switch c . Func {
case "add-hosts" , "remove-hosts" :
if len ( c . flagHosts ) == 0 {
c . UI . Error ( "No hosts supplied via -host" )
return 1
}
case "set-hosts" :
switch len ( c . flagHosts ) {
case 0 :
2020-09-14 12:45:56 -04:00
c . UI . Error ( "No hosts supplied via -host" )
return 1
2020-08-31 10:06:21 -04:00
case 1 :
if c . flagHosts [ 0 ] == "null" {
2020-09-14 12:45:56 -04:00
hosts = nil
2020-08-31 10:06:21 -04:00
}
}
}
// Perform check-and-set when needed
var version uint32
switch c . Func {
case "add-hosts" , "remove-hosts" , "set-hosts" :
switch c . FlagVersion {
case 0 :
2020-09-08 13:27:51 -07:00
opts = append ( opts , hostsets . WithAutomaticVersioning ( true ))
2020-08-31 10:06:21 -04:00
default :
version = uint32 ( c . FlagVersion )
}
default :
// The only other one that needs it is update, handled by the static
// file
}
2020-08-28 01:28:26 -04:00
hostsetClient := hostsets . NewClient ( client )
2020-09-15 01:08:21 -04:00
existed := true
var result api . GenericResult
var listResult api . GenericListResult
2020-08-28 01:28:26 -04:00
switch c . Func {
case "read" :
2020-09-24 14:34:58 -07:00
result , err = hostsetClient . Read ( c . Context , c . FlagId , opts ... )
2020-08-28 01:28:26 -04:00
case "delete" :
2020-09-24 14:34:58 -07:00
_ , err = hostsetClient . Delete ( c . Context , c . FlagId , opts ... )
2020-12-07 14:25:16 -07:00
if apiErr := api . AsServerError ( err ); apiErr != nil && apiErr . ResponseStatus () == http . StatusNotFound {
2020-09-15 01:08:21 -04:00
existed = false
2020-09-24 14:34:58 -07:00
err = nil
2020-09-15 01:08:21 -04:00
}
2020-08-28 01:28:26 -04:00
case "list" :
2020-10-02 19:20:30 -04:00
listResult , err = hostsetClient . List ( c . Context , c . FlagHostCatalogId , opts ... )
2020-08-31 10:06:21 -04:00
case "add-hosts" :
2020-09-24 14:34:58 -07:00
result , err = hostsetClient . AddHosts ( c . Context , c . FlagId , version , hosts , opts ... )
2020-08-31 10:06:21 -04:00
case "remove-hosts" :
2020-09-24 14:34:58 -07:00
result , err = hostsetClient . RemoveHosts ( c . Context , c . FlagId , version , hosts , opts ... )
2020-08-31 10:06:21 -04:00
case "set-hosts" :
2020-09-24 14:34:58 -07:00
result , err = hostsetClient . SetHosts ( c . Context , c . FlagId , version , hosts , opts ... )
2020-08-28 01:28:26 -04:00
}
plural := "host set"
if c . Func == "list" {
plural = "host sets"
}
if err != nil {
2020-10-06 14:08:49 -07:00
if apiErr := api . AsServerError ( err ); apiErr != nil {
c . UI . Error ( fmt . Sprintf ( "Error from controller when performing %s on %s: %s" , c . Func , plural , base . PrintApiError ( apiErr )))
2020-09-24 14:34:58 -07:00
return 1
}
2020-08-28 01:28:26 -04:00
c . UI . Error ( fmt . Sprintf ( "Error trying to %s %s: %s" , c . Func , plural , err . Error ()))
return 2
}
switch c . Func {
case "delete" :
switch base . Format ( c . UI ) {
case "json" :
c . UI . Output ( "null" )
case "table" :
output := "The delete operation completed successfully"
switch existed {
case true :
output += "."
default :
output += ", however the resource did not exist at the time."
}
c . UI . Output ( output )
}
return 0
case "list" :
2020-09-15 01:08:21 -04:00
listedSets := listResult . GetItems ().([] * hostsets . HostSet )
2020-08-28 01:28:26 -04:00
switch base . Format ( c . UI ) {
case "json" :
if len ( listedSets ) == 0 {
c . UI . Output ( "null" )
return 0
}
b , err := base . JsonFormatter {}. Format ( listedSets )
if err != nil {
c . UI . Error ( fmt . Errorf ( "Error formatting as JSON: %w" , err ). Error ())
return 1
}
c . UI . Output ( string ( b ))
case "table" :
if len ( listedSets ) == 0 {
c . UI . Output ( "No host sets found" )
return 0
}
var output [] string
output = [] string {
"" ,
"Host Set information:" ,
}
for i , m := range listedSets {
if i > 0 {
output = append ( output , "" )
}
if true {
output = append ( output ,
fmt . Sprintf ( " ID: %s" , m . Id ),
fmt . Sprintf ( " Version: %d" , m . Version ),
fmt . Sprintf ( " Type: %s" , m . Type ),
)
}
if m . Name != "" {
output = append ( output ,
fmt . Sprintf ( " Name: %s" , m . Name ),
)
}
if m . Description != "" {
output = append ( output ,
fmt . Sprintf ( " Description: %s" , m . Description ),
)
}
}
c . UI . Output ( base . WrapForHelpText ( output ))
}
return 0
}
2020-09-15 01:08:21 -04:00
set := result . GetItem ().( * hostsets . HostSet )
2020-08-28 01:28:26 -04:00
switch base . Format ( c . UI ) {
case "table" :
c . UI . Output ( generateHostSetTableOutput ( set ))
case "json" :
b , err := base . JsonFormatter {}. Format ( set )
if err != nil {
c . UI . Error ( fmt . Errorf ( "Error formatting as JSON: %w" , err ). Error ())
return 1
}
c . UI . Output ( string ( b ))
}
return 0
}