From 25eaa683ec0837bd2abef7897f28a458291861af Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Wed, 21 Oct 2020 20:38:34 -0400 Subject: [PATCH 01/17] add dedicated list,details --- Makefile | 1 - cmd/dedicated.go | 40 +++++++++++++++++++ cmd/dedicatedDetails.go | 86 +++++++++++++++++++++++++++++++++++++++++ cmd/dedicatedList.go | 73 ++++++++++++++++++++++++++++++++++ types/api/subaccnt.go | 36 +++++++++++++++++ 5 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 cmd/dedicated.go create mode 100644 cmd/dedicatedDetails.go create mode 100644 cmd/dedicatedList.go create mode 100644 types/api/subaccnt.go diff --git a/Makefile b/Makefile index f167dce..a4e996c 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,6 @@ install: security scripts/build/install security: - #go get github.com/securego/gosec/cmd/gosec @gosec ./... clean: diff --git a/cmd/dedicated.go b/cmd/dedicated.go new file mode 100644 index 0000000..00f9895 --- /dev/null +++ b/cmd/dedicated.go @@ -0,0 +1,40 @@ +/* +Copyright © LiquidWeb + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" +) + +var dedicatedCmd = &cobra.Command{ + Use: "dedicated", + Short: "Traditional dedicated servers.", + Long: `Command line interface to traditional dedicated servers. + +For a full list of capabilities, please refer to the "Available Commands" section.`, + Run: func(cmd *cobra.Command, args []string) { + if err := cmd.Help(); err != nil { + lwCliInst.Die(err) + } + os.Exit(1) + }, +} + +func init() { + rootCmd.AddCommand(dedicatedCmd) +} diff --git a/cmd/dedicatedDetails.go b/cmd/dedicatedDetails.go new file mode 100644 index 0000000..87b639e --- /dev/null +++ b/cmd/dedicatedDetails.go @@ -0,0 +1,86 @@ +/* +Copyright © LiquidWeb + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" + + //"github.com/liquidweb/liquidweb-cli/instance" + "github.com/liquidweb/liquidweb-cli/types/api" + "github.com/liquidweb/liquidweb-cli/validate" +) + +var dedicatedDetailsCmd = &cobra.Command{ + Use: "details", + Short: "Get details of a dedicated server", + Long: `Get details of a dedicated server`, + Run: func(cmd *cobra.Command, args []string) { + uniqIdFlag, _ := cmd.Flags().GetString("uniq-id") + jsonFlag, _ := cmd.Flags().GetBool("json") + + validateFields := map[interface{}]interface{}{ + uniqIdFlag: "UniqId", + } + if err := validate.Validate(validateFields); err != nil { + lwCliInst.Die(err) + } + + var details apiTypes.Subaccnt + apiArgs := map[string]interface{}{ + "uniq_id": uniqIdFlag, + "alsowith": []string{"categories"}, + } + + if err := lwCliInst.CallLwApiInto("bleed/asset/details", apiArgs, &details); err != nil { + lwCliInst.Die(err) + } + + var found bool + for _, category := range details.Categories { + if category == "StrictDedicated" { + found = true + break + } + } + + if !found { + lwCliInst.Die(fmt.Errorf("UniqId [%s] is not a dedicated server", uniqIdFlag)) + } + + if jsonFlag { + pretty, err := lwCliInst.JsonEncodeAndPrettyPrint(details) + if err != nil { + panic(err) + } + fmt.Print(pretty) + } else { + fmt.Print(details) + } + }, +} + +func init() { + dedicatedCmd.AddCommand(dedicatedDetailsCmd) + + dedicatedDetailsCmd.Flags().Bool("json", false, "output in json format") + dedicatedDetailsCmd.Flags().String("uniq-id", "", "uniq-id of the dedicated server") + + if err := dedicatedDetailsCmd.MarkFlagRequired("uniq-id"); err != nil { + lwCliInst.Die(err) + } +} diff --git a/cmd/dedicatedList.go b/cmd/dedicatedList.go new file mode 100644 index 0000000..0837031 --- /dev/null +++ b/cmd/dedicatedList.go @@ -0,0 +1,73 @@ +/* +Copyright © LiquidWeb + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/liquidweb/liquidweb-cli/instance" + "github.com/liquidweb/liquidweb-cli/types/api" +) + +var dedicatedListCmd = &cobra.Command{ + Use: "list", + Short: "List Dedicated Servers on your account", + Long: `List Dedicated Servers on your account`, + Run: func(cmd *cobra.Command, args []string) { + jsonFlag, _ := cmd.Flags().GetBool("json") + + methodArgs := instance.AllPaginatedResultsArgs{ + Method: "bleed/asset/list", + ResultsPerPage: 100, + MethodArgs: map[string]interface{}{ + "category": []string{"StrictDedicated"}, + }, + } + results, err := lwCliInst.AllPaginatedResults(&methodArgs) + if err != nil { + lwCliInst.Die(err) + } + + if jsonFlag { + pretty, err := lwCliInst.JsonEncodeAndPrettyPrint(results) + if err != nil { + lwCliInst.Die(err) + } + fmt.Printf(pretty) + } else { + serverCnt := 1 + for _, item := range results.Items { + + var details apiTypes.Subaccnt + if err := instance.CastFieldTypes(item, &details); err != nil { + lwCliInst.Die(err) + } + + fmt.Printf("%d.) ", serverCnt) + fmt.Print(details) + serverCnt++ + } + } + }, +} + +func init() { + dedicatedCmd.AddCommand(dedicatedListCmd) + + dedicatedListCmd.Flags().Bool("json", false, "output in json format") +} diff --git a/types/api/subaccnt.go b/types/api/subaccnt.go new file mode 100644 index 0000000..9f88f78 --- /dev/null +++ b/types/api/subaccnt.go @@ -0,0 +1,36 @@ +package apiTypes + +import ( + "fmt" + "strings" +) + +type Subaccnt struct { + Active bool `json:"active" mapstructure:"active"` + Domain string `json:"domain" mapstructure:"domain"` + Ip string `json:"ip" mapstructure:"ip"` + ProjectId int64 `json:"project_id" mapstructure:"project_id"` + ProjectName string `json:"project_name" mapstructure:"project_name"` + RegionId int `json:"region_id" mapstructure:"region_id"` + Status string `json:"status" mapstructure:"status"` + Type string `json:"type" mapstructure:"type"` + UniqId string `json:"uniq_id" mapstructure:"uniq_id"` + Username string `json:"username" mapstructure:"username"` + Categories []string `json:"categories" mapstructure:"categories"` +} + +func (x Subaccnt) String() string { + var slice []string + + slice = append(slice, fmt.Sprintf("Domain: %s UniqId: %s\n", x.Domain, x.UniqId)) + + slice = append(slice, fmt.Sprintf("\tIp: %s\n", x.Ip)) + if x.ProjectName != "" && x.ProjectId != 0 { + slice = append(slice, fmt.Sprintf("\tProjectName: %s (id %d)\n", x.ProjectName, x.ProjectId)) + } + slice = append(slice, fmt.Sprintf("\tRegionId: %d\n", x.RegionId)) + slice = append(slice, fmt.Sprintf("\tStatus: %s\n", x.Status)) + slice = append(slice, fmt.Sprintf("\tType: %s\n", x.Type)) + + return strings.Join(slice[:], "") +} From cfcd7f3763c9fda052e67f55262cf784a88b4388 Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Wed, 21 Oct 2020 20:47:41 -0400 Subject: [PATCH 02/17] move dedicated cmds --- cmd/dedicated.go | 4 +- cmd/dedicatedServer.go | 40 +++++++++++++++++++ ...edDetails.go => dedicatedServerDetails.go} | 11 +++-- ...edicatedList.go => dedicatedServerList.go} | 6 +-- 4 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 cmd/dedicatedServer.go rename cmd/{dedicatedDetails.go => dedicatedServerDetails.go} (83%) rename cmd/{dedicatedList.go => dedicatedServerList.go} (90%) diff --git a/cmd/dedicated.go b/cmd/dedicated.go index 00f9895..de1a5ec 100644 --- a/cmd/dedicated.go +++ b/cmd/dedicated.go @@ -23,8 +23,8 @@ import ( var dedicatedCmd = &cobra.Command{ Use: "dedicated", - Short: "Traditional dedicated servers.", - Long: `Command line interface to traditional dedicated servers. + Short: "All things dedicated server.", + Long: `Command line interface for all things specific to running dedicated servers. For a full list of capabilities, please refer to the "Available Commands" section.`, Run: func(cmd *cobra.Command, args []string) { diff --git a/cmd/dedicatedServer.go b/cmd/dedicatedServer.go new file mode 100644 index 0000000..7e63164 --- /dev/null +++ b/cmd/dedicatedServer.go @@ -0,0 +1,40 @@ +/* +Copyright © LiquidWeb + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" +) + +var dedicatedServerCmd = &cobra.Command{ + Use: "server", + Short: "Traditional dedicated servers.", + Long: `Command line interface for traditional dedicated servers. + +For a full list of capabilities, please refer to the "Available Commands" section.`, + Run: func(cmd *cobra.Command, args []string) { + if err := cmd.Help(); err != nil { + lwCliInst.Die(err) + } + os.Exit(1) + }, +} + +func init() { + dedicatedCmd.AddCommand(dedicatedServerCmd) +} diff --git a/cmd/dedicatedDetails.go b/cmd/dedicatedServerDetails.go similarity index 83% rename from cmd/dedicatedDetails.go rename to cmd/dedicatedServerDetails.go index 87b639e..f5f3444 100644 --- a/cmd/dedicatedDetails.go +++ b/cmd/dedicatedServerDetails.go @@ -20,12 +20,11 @@ import ( "github.com/spf13/cobra" - //"github.com/liquidweb/liquidweb-cli/instance" "github.com/liquidweb/liquidweb-cli/types/api" "github.com/liquidweb/liquidweb-cli/validate" ) -var dedicatedDetailsCmd = &cobra.Command{ +var dedicatedServerDetailsCmd = &cobra.Command{ Use: "details", Short: "Get details of a dedicated server", Long: `Get details of a dedicated server`, @@ -75,12 +74,12 @@ var dedicatedDetailsCmd = &cobra.Command{ } func init() { - dedicatedCmd.AddCommand(dedicatedDetailsCmd) + dedicatedServerCmd.AddCommand(dedicatedServerDetailsCmd) - dedicatedDetailsCmd.Flags().Bool("json", false, "output in json format") - dedicatedDetailsCmd.Flags().String("uniq-id", "", "uniq-id of the dedicated server") + dedicatedServerDetailsCmd.Flags().Bool("json", false, "output in json format") + dedicatedServerDetailsCmd.Flags().String("uniq-id", "", "uniq-id of the dedicated server") - if err := dedicatedDetailsCmd.MarkFlagRequired("uniq-id"); err != nil { + if err := dedicatedServerDetailsCmd.MarkFlagRequired("uniq-id"); err != nil { lwCliInst.Die(err) } } diff --git a/cmd/dedicatedList.go b/cmd/dedicatedServerList.go similarity index 90% rename from cmd/dedicatedList.go rename to cmd/dedicatedServerList.go index 0837031..53ac91b 100644 --- a/cmd/dedicatedList.go +++ b/cmd/dedicatedServerList.go @@ -24,7 +24,7 @@ import ( "github.com/liquidweb/liquidweb-cli/types/api" ) -var dedicatedListCmd = &cobra.Command{ +var dedicatedServerListCmd = &cobra.Command{ Use: "list", Short: "List Dedicated Servers on your account", Long: `List Dedicated Servers on your account`, @@ -67,7 +67,7 @@ var dedicatedListCmd = &cobra.Command{ } func init() { - dedicatedCmd.AddCommand(dedicatedListCmd) + dedicatedServerCmd.AddCommand(dedicatedServerListCmd) - dedicatedListCmd.Flags().Bool("json", false, "output in json format") + dedicatedServerListCmd.Flags().Bool("json", false, "output in json format") } From 7649607be4a992e38ca0abb4a458b40c9851c448 Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Thu, 22 Oct 2020 08:13:39 -0400 Subject: [PATCH 03/17] add asset commands --- cmd/asset.go | 40 ++++++++++++++++++++ cmd/assetDetails.go | 68 +++++++++++++++++++++++++++++++++ cmd/assetList.go | 88 +++++++++++++++++++++++++++++++++++++++++++ types/api/subaccnt.go | 12 +++++- 4 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 cmd/asset.go create mode 100644 cmd/assetDetails.go create mode 100644 cmd/assetList.go diff --git a/cmd/asset.go b/cmd/asset.go new file mode 100644 index 0000000..9e090ed --- /dev/null +++ b/cmd/asset.go @@ -0,0 +1,40 @@ +/* +Copyright © LiquidWeb + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" +) + +var assetCmd = &cobra.Command{ + Use: "asset", + Short: "All things assets.", + Long: `An asset is an individual product on an account. + +For a full list of capabilities, please refer to the "Available Commands" section.`, + Run: func(cmd *cobra.Command, args []string) { + if err := cmd.Help(); err != nil { + lwCliInst.Die(err) + } + os.Exit(1) + }, +} + +func init() { + rootCmd.AddCommand(assetCmd) +} diff --git a/cmd/assetDetails.go b/cmd/assetDetails.go new file mode 100644 index 0000000..a56b259 --- /dev/null +++ b/cmd/assetDetails.go @@ -0,0 +1,68 @@ +/* +Copyright © LiquidWeb + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/liquidweb/liquidweb-cli/types/api" +) + +var assetDetailsCmd = &cobra.Command{ + Use: "details", + Short: "Get details of a specific asset", + Long: `Get details of a specific asset. + +An asset is an individual product on an account. Assets have categories. +`, + Run: func(cmd *cobra.Command, args []string) { + jsonFlag, _ := cmd.Flags().GetBool("json") + uniqIdFlag, _ := cmd.Flags().GetString("uniq-id") + + var details apiTypes.Subaccnt + apiArgs := map[string]interface{}{ + "uniq_id": uniqIdFlag, + "alsowith": []string{"categories"}, + } + + if err := lwCliInst.CallLwApiInto("bleed/asset/details", apiArgs, &details); err != nil { + lwCliInst.Die(err) + } + + if jsonFlag { + pretty, err := lwCliInst.JsonEncodeAndPrettyPrint(details) + if err != nil { + lwCliInst.Die(err) + } + fmt.Printf(pretty) + } else { + fmt.Print(details) + } + }, +} + +func init() { + assetCmd.AddCommand(assetDetailsCmd) + + assetDetailsCmd.Flags().Bool("json", false, "output in json format") + assetDetailsCmd.Flags().String("uniq-id", "", "uniq-id of the asset") + + if err := assetDetailsCmd.MarkFlagRequired("uniq-id"); err != nil { + lwCliInst.Die(err) + } +} diff --git a/cmd/assetList.go b/cmd/assetList.go new file mode 100644 index 0000000..2e5c22c --- /dev/null +++ b/cmd/assetList.go @@ -0,0 +1,88 @@ +/* +Copyright © LiquidWeb + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/liquidweb/liquidweb-cli/instance" + "github.com/liquidweb/liquidweb-cli/types/api" +) + +var assetListCmdCategoriesFlag []string + +var assetListCmd = &cobra.Command{ + Use: "list", + Short: "List assets on your account", + Long: `List assets on your account. + +An asset is an individual product on an account. Assets have categories. +`, + Run: func(cmd *cobra.Command, args []string) { + jsonFlag, _ := cmd.Flags().GetBool("json") + + apiArgs := map[string]interface{}{ + "alsowith": []string{"categories"}, + } + + if len(assetListCmdCategoriesFlag) > 0 { + apiArgs["category"] = assetListCmdCategoriesFlag + } + + methodArgs := instance.AllPaginatedResultsArgs{ + Method: "bleed/asset/list", + ResultsPerPage: 100, + MethodArgs: apiArgs, + } + results, err := lwCliInst.AllPaginatedResults(&methodArgs) + if err != nil { + lwCliInst.Die(err) + } + + if jsonFlag { + pretty, err := lwCliInst.JsonEncodeAndPrettyPrint(results) + if err != nil { + lwCliInst.Die(err) + } + fmt.Printf(pretty) + } else { + cnt := 1 + for _, item := range results.Items { + + var details apiTypes.Subaccnt + if err := instance.CastFieldTypes(item, &details); err != nil { + lwCliInst.Die(err) + } + + fmt.Printf("%d.) ", cnt) + fmt.Print(details) + cnt++ + } + } + }, +} + +func init() { + assetCmd.AddCommand(assetListCmd) + + assetListCmd.Flags().Bool("json", false, "output in json format") + + assetListCmd.Flags().StringSliceVar(&assetListCmdCategoriesFlag, "categories", + []string{}, "categories to include separated by ','") + +} diff --git a/types/api/subaccnt.go b/types/api/subaccnt.go index 9f88f78..7ef45c6 100644 --- a/types/api/subaccnt.go +++ b/types/api/subaccnt.go @@ -24,7 +24,17 @@ func (x Subaccnt) String() string { slice = append(slice, fmt.Sprintf("Domain: %s UniqId: %s\n", x.Domain, x.UniqId)) - slice = append(slice, fmt.Sprintf("\tIp: %s\n", x.Ip)) + if len(x.Categories) > 0 { + slice = append(slice, fmt.Sprintln("\tCategories")) + for _, category := range x.Categories { + slice = append(slice, fmt.Sprintf("\t\t* %s\n", category)) + } + } + + if x.Ip != "" && x.Ip != "127.0.0.1" { + slice = append(slice, fmt.Sprintf("\tIp: %s\n", x.Ip)) + } + if x.ProjectName != "" && x.ProjectId != 0 { slice = append(slice, fmt.Sprintf("\tProjectName: %s (id %d)\n", x.ProjectName, x.ProjectId)) } From 9e6ba15c1d5c35ce86b566f44d51249963d7ce46 Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Thu, 22 Oct 2020 21:00:46 -0400 Subject: [PATCH 04/17] implement `lw ssh` --- Makefile | 2 +- cmd/ssh.go | 59 +++++++++++++++++++++ instance/ssh.go | 135 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 cmd/ssh.go create mode 100644 instance/ssh.go diff --git a/Makefile b/Makefile index a4e996c..163ff38 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ install: security scripts/build/install security: - @gosec ./... + @gosec --exclude=G204 ./... clean: rm -rf _exe/ diff --git a/cmd/ssh.go b/cmd/ssh.go new file mode 100644 index 0000000..bea979d --- /dev/null +++ b/cmd/ssh.go @@ -0,0 +1,59 @@ +/* +Copyright © LiquidWeb + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package cmd + +import ( + "github.com/spf13/cobra" + + "github.com/liquidweb/liquidweb-cli/instance" +) + +var sshCmd = &cobra.Command{ + Use: "ssh", + Short: "SSH to a Server", + Long: `SSH to a Server. + +Gives you an interactive shell to your Server.`, + Run: func(cmd *cobra.Command, args []string) { + params := &instance.SshParams{} + + params.Host, _ = cmd.Flags().GetString("host") + params.PrivateKey, _ = cmd.Flags().GetString("private-ssh-key") + params.User, _ = cmd.Flags().GetString("user") + params.AgentForwarding, _ = cmd.Flags().GetBool("agent-forwarding") + params.Port, _ = cmd.Flags().GetInt("port") + params.Command, _ = cmd.Flags().GetString("command") + + if err := lwCliInst.Ssh(params); err != nil { + lwCliInst.Die(err) + } + }, +} + +func init() { + rootCmd.AddCommand(sshCmd) + + sshCmd.Flags().String("host", "", "uniq-id or hostname for the Server") + sshCmd.Flags().Int("port", 22, "ssh port to use") + sshCmd.Flags().String("private-ssh-key", "", "path to a specific/non default ssh private key to use") + sshCmd.Flags().Bool("agent-forwarding", false, "whether or not to enable ssh agent forwarding") + sshCmd.Flags().String("user", "root", "username to use for the ssh connection") + sshCmd.Flags().String("command", "", "run this command and exit rather than start an interactive shell") + + if err := sshCmd.MarkFlagRequired("host"); err != nil { + lwCliInst.Die(err) + } +} diff --git a/instance/ssh.go b/instance/ssh.go new file mode 100644 index 0000000..18fafc3 --- /dev/null +++ b/instance/ssh.go @@ -0,0 +1,135 @@ +/* +Copyright © LiquidWeb + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package instance + +import ( + "fmt" + "os" + "os/exec" + + "github.com/liquidweb/liquidweb-cli/types/api" + "github.com/liquidweb/liquidweb-cli/validate" +) + +type SshParams struct { + Host string `yaml:"host"` + Port int `yaml:"port"` + PrivateKey string `yaml:"private-key"` + User string `yaml:"user"` + AgentForwarding bool `yaml:"agent-forwarding"` + Command string `yaml:"command"` +} + +func (self *SshParams) UnmarshalYAML(unmarshal func(interface{}) error) error { + type rawType SshParams + raw := rawType{ + Port: 22, + User: "root", + } + if err := unmarshal(&raw); err != nil { + return err + } + *self = SshParams(raw) + + return nil +} + +func (self *SshParams) TranslateHost(ci *Client) (ip string, err error) { + validateFields := map[interface{}]interface{}{ + self.Host: "UniqId", + } + + if err = validate.Validate(validateFields); err == nil { + var subaccnt apiTypes.Subaccnt + apiArgs := map[string]interface{}{ + "uniq_id": self.Host, + } + if aErr := ci.CallLwApiInto("bleed/asset/details", apiArgs, &subaccnt); aErr != nil { + err = aErr + return + } + + ip = subaccnt.Ip + } else { + methodArgs := AllPaginatedResultsArgs{ + Method: "bleed/asset/list", + ResultsPerPage: 100, + } + results, aErr := ci.AllPaginatedResults(&methodArgs) + if aErr != nil { + err = aErr + return + } + for _, item := range results.Items { + var subaccnt apiTypes.Subaccnt + if err = CastFieldTypes(item, &subaccnt); err != nil { + return + } + + if subaccnt.Domain == self.Host { + ip = subaccnt.Ip + break + } + } + } + + if ip == "" { + err = fmt.Errorf("unable to determine ip for Host [%s]", self.Host) + return + } + + return +} + +func (self *Client) Ssh(params *SshParams) (err error) { + validateFields := map[interface{}]interface{}{ + params.Port: "PositiveInt", + } + if err = validate.Validate(validateFields); err != nil { + return + } + + ip, err := params.TranslateHost(self) + if err != nil { + return + } + + sshArgs := []string{} + if params.PrivateKey != "" { + sshArgs = append(sshArgs, "-i", params.PrivateKey) + } + + if params.AgentForwarding { + sshArgs = append(sshArgs, "-A") + } + + sshArgs = append(sshArgs, fmt.Sprintf("%s@%s", params.User, ip)) + sshArgs = append(sshArgs, fmt.Sprintf("-p %d", params.Port)) + + if params.Command != "" { + sshArgs = append(sshArgs, params.Command) + } + + cmd := exec.Command("ssh", sshArgs...) + + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + cmd.Stdin = os.Stdin + + err = cmd.Run() + + return +} From ded2e0af41618be1bb0b5ac8751c232284ffb7ee Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Thu, 22 Oct 2020 21:02:55 -0400 Subject: [PATCH 05/17] update wording --- cmd/asset.go | 2 +- cmd/assetDetails.go | 2 +- cmd/assetList.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/asset.go b/cmd/asset.go index 9e090ed..55d263e 100644 --- a/cmd/asset.go +++ b/cmd/asset.go @@ -24,7 +24,7 @@ import ( var assetCmd = &cobra.Command{ Use: "asset", Short: "All things assets.", - Long: `An asset is an individual product on an account. + Long: `An asset is an individual component on an account. For a full list of capabilities, please refer to the "Available Commands" section.`, Run: func(cmd *cobra.Command, args []string) { diff --git a/cmd/assetDetails.go b/cmd/assetDetails.go index a56b259..0d61646 100644 --- a/cmd/assetDetails.go +++ b/cmd/assetDetails.go @@ -28,7 +28,7 @@ var assetDetailsCmd = &cobra.Command{ Short: "Get details of a specific asset", Long: `Get details of a specific asset. -An asset is an individual product on an account. Assets have categories. +An asset is an individual component on an account. Assets have categories. `, Run: func(cmd *cobra.Command, args []string) { jsonFlag, _ := cmd.Flags().GetBool("json") diff --git a/cmd/assetList.go b/cmd/assetList.go index 2e5c22c..ec9b029 100644 --- a/cmd/assetList.go +++ b/cmd/assetList.go @@ -31,7 +31,7 @@ var assetListCmd = &cobra.Command{ Short: "List assets on your account", Long: `List assets on your account. -An asset is an individual product on an account. Assets have categories. +An asset is an individual component on an account. Assets have categories. `, Run: func(cmd *cobra.Command, args []string) { jsonFlag, _ := cmd.Flags().GetBool("json") From a285c09a632fe0f7f9f068c9144a357ec79be63f Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Thu, 22 Oct 2020 21:07:24 -0400 Subject: [PATCH 06/17] update example --- cmd/assetList.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmd/assetList.go b/cmd/assetList.go index ec9b029..d40db92 100644 --- a/cmd/assetList.go +++ b/cmd/assetList.go @@ -32,6 +32,14 @@ var assetListCmd = &cobra.Command{ Long: `List assets on your account. An asset is an individual component on an account. Assets have categories. + +Examples: + +* List all assets in the Provisioned and DNS categories: +- lw asset list --categories Provisioned,DNS + +* List all dedicated servers: +- lw asset list --categories StrictDedicated `, Run: func(cmd *cobra.Command, args []string) { jsonFlag, _ := cmd.Flags().GetBool("json") From 016643ef0c6ee3dbfe4ba9a5e1cb715ed323c361 Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Thu, 22 Oct 2020 22:38:30 -0400 Subject: [PATCH 07/17] add ssh to plan --- .../plans/cloud.server.create.yaml | 0 examples/plans/cloud.server.resize.yaml | 10 ++++++++++ examples/plans/ssh.yaml | 10 ++++++++++ instance/plan.go | 13 +++++++++++++ 4 files changed, 33 insertions(+) rename plan.yaml.example => examples/plans/cloud.server.create.yaml (100%) create mode 100644 examples/plans/cloud.server.resize.yaml create mode 100644 examples/plans/ssh.yaml diff --git a/plan.yaml.example b/examples/plans/cloud.server.create.yaml similarity index 100% rename from plan.yaml.example rename to examples/plans/cloud.server.create.yaml diff --git a/examples/plans/cloud.server.resize.yaml b/examples/plans/cloud.server.resize.yaml new file mode 100644 index 0000000..e5787ce --- /dev/null +++ b/examples/plans/cloud.server.resize.yaml @@ -0,0 +1,10 @@ +--- +cloud: + server: + resize: + - config-id: 0 + private-parent: "nvme-pp" + uniq-id: "{{- .Var.uniq_id -}}" + diskspace: 1800 + vcpu: 16 + memory: 124000 diff --git a/examples/plans/ssh.yaml b/examples/plans/ssh.yaml new file mode 100644 index 0000000..e1f93c8 --- /dev/null +++ b/examples/plans/ssh.yaml @@ -0,0 +1,10 @@ +--- +ssh: + - host: nd00.ltv1wv76kc.io + command: "free -m" + user: "root" + private-key: "/home/myself/.ssh/id_rsa" + agent-forwarding: true + port: 22 + - host: PPB4NZ + command: "hostname && free -m" diff --git a/instance/plan.go b/instance/plan.go index 225962c..08cc46a 100644 --- a/instance/plan.go +++ b/instance/plan.go @@ -21,6 +21,7 @@ import ( type Plan struct { Cloud *PlanCloud + Ssh []SshParams } type PlanCloud struct { @@ -45,6 +46,12 @@ func (ci *Client) ProcessPlan(plan *Plan) error { } } + for _, x := range plan.Ssh { + if err := ci.processPlanSsh(&x); err != nil { + return err + } + } + return nil } @@ -65,6 +72,12 @@ func (ci *Client) processPlanCloud(cloud *PlanCloud) error { return nil } +func (ci *Client) processPlanSsh(params *SshParams) (err error) { + err = ci.Ssh(params) + + return +} + func (ci *Client) processPlanCloudServer(server *PlanCloudServer) error { if server.Create != nil { From 6beffc82dbbdfa7541897146fd065cd75df869db Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Thu, 22 Oct 2020 23:00:54 -0400 Subject: [PATCH 08/17] support multiple uids --- cmd/assetDetails.go | 45 +++++++++++++++-------- cmd/cloudServerDetails.go | 46 ++++++++++++----------- cmd/dedicatedServerDetails.go | 69 +++++++++++++++++++---------------- 3 files changed, 90 insertions(+), 70 deletions(-) diff --git a/cmd/assetDetails.go b/cmd/assetDetails.go index 0d61646..1af45ff 100644 --- a/cmd/assetDetails.go +++ b/cmd/assetDetails.go @@ -21,8 +21,11 @@ import ( "github.com/spf13/cobra" "github.com/liquidweb/liquidweb-cli/types/api" + "github.com/liquidweb/liquidweb-cli/validate" ) +var assetDetailsCmdUniqIdFlag []string + var assetDetailsCmd = &cobra.Command{ Use: "details", Short: "Get details of a specific asset", @@ -32,26 +35,35 @@ An asset is an individual component on an account. Assets have categories. `, Run: func(cmd *cobra.Command, args []string) { jsonFlag, _ := cmd.Flags().GetBool("json") - uniqIdFlag, _ := cmd.Flags().GetString("uniq-id") - var details apiTypes.Subaccnt - apiArgs := map[string]interface{}{ - "uniq_id": uniqIdFlag, - "alsowith": []string{"categories"}, - } + for _, uniqId := range assetDetailsCmdUniqIdFlag { + validateFields := map[interface{}]interface{}{ + uniqId: "UniqId", + } + if err := validate.Validate(validateFields); err != nil { + fmt.Printf("%s ... skipping\n", err) + continue + } - if err := lwCliInst.CallLwApiInto("bleed/asset/details", apiArgs, &details); err != nil { - lwCliInst.Die(err) - } + var details apiTypes.Subaccnt + apiArgs := map[string]interface{}{ + "uniq_id": uniqId, + "alsowith": []string{"categories"}, + } - if jsonFlag { - pretty, err := lwCliInst.JsonEncodeAndPrettyPrint(details) - if err != nil { + if err := lwCliInst.CallLwApiInto("bleed/asset/details", apiArgs, &details); err != nil { lwCliInst.Die(err) } - fmt.Printf(pretty) - } else { - fmt.Print(details) + + if jsonFlag { + pretty, err := lwCliInst.JsonEncodeAndPrettyPrint(details) + if err != nil { + lwCliInst.Die(err) + } + fmt.Printf(pretty) + } else { + fmt.Print(details) + } } }, } @@ -60,7 +72,8 @@ func init() { assetCmd.AddCommand(assetDetailsCmd) assetDetailsCmd.Flags().Bool("json", false, "output in json format") - assetDetailsCmd.Flags().String("uniq-id", "", "uniq-id of the asset") + assetDetailsCmd.Flags().StringSliceVar(&assetDetailsCmdUniqIdFlag, "uniq-id", []string{}, + "uniq-id of the asset. For multiple, must be ',' separated") if err := assetDetailsCmd.MarkFlagRequired("uniq-id"); err != nil { lwCliInst.Die(err) diff --git a/cmd/cloudServerDetails.go b/cmd/cloudServerDetails.go index ac76576..8bc7a30 100644 --- a/cmd/cloudServerDetails.go +++ b/cmd/cloudServerDetails.go @@ -17,7 +17,6 @@ package cmd import ( "fmt" - "os" "github.com/spf13/cobra" @@ -28,6 +27,7 @@ import ( var blockStorageVolumeList apiTypes.MergedPaginatedList var fetchedBlockStorageVolumes bool +var cloudServerDetailsCmdUniqIdFlag []string var cloudServerDetailsCmd = &cobra.Command{ Use: "details", @@ -39,32 +39,33 @@ You can check this methods API documentation for what the returned fields mean: https://cart.liquidweb.com/storm/api/docs/bleed/Storm/Server.html#method_details `, Run: func(cmd *cobra.Command, args []string) { - uniqIdFlag, _ := cmd.Flags().GetString("uniq-id") jsonFlag, _ := cmd.Flags().GetBool("json") - validateFields := map[interface{}]interface{}{ - uniqIdFlag: "UniqId", - } - if err := validate.Validate(validateFields); err != nil { - lwCliInst.Die(err) - } - - var details apiTypes.CloudServerDetails - if err := lwCliInst.CallLwApiInto("bleed/storm/server/details", - map[string]interface{}{"uniq_id": uniqIdFlag}, &details); err != nil { - lwCliInst.Die(err) - } + for _, uniqId := range cloudServerDetailsCmdUniqIdFlag { + validateFields := map[interface{}]interface{}{ + uniqId: "UniqId", + } + if err := validate.Validate(validateFields); err != nil { + fmt.Printf("%s ... skipping\n", err) + continue + } - if jsonFlag { - pretty, err := lwCliInst.JsonEncodeAndPrettyPrint(details) - if err != nil { + var details apiTypes.CloudServerDetails + if err := lwCliInst.CallLwApiInto("bleed/storm/server/details", + map[string]interface{}{"uniq_id": uniqId}, &details); err != nil { lwCliInst.Die(err) } - fmt.Printf(pretty) - os.Exit(0) - } - _printExtendedCloudServerDetails(&details) + if jsonFlag { + pretty, err := lwCliInst.JsonEncodeAndPrettyPrint(details) + if err != nil { + lwCliInst.Die(err) + } + fmt.Print(pretty) + } else { + _printExtendedCloudServerDetails(&details) + } + } }, } @@ -122,7 +123,8 @@ func init() { cloudServerCmd.AddCommand(cloudServerDetailsCmd) cloudServerDetailsCmd.Flags().Bool("json", false, "output in json format") - cloudServerDetailsCmd.Flags().String("uniq-id", "", "get details of this uniq-id") + cloudServerDetailsCmd.Flags().StringSliceVar(&cloudServerDetailsCmdUniqIdFlag, "uniq-id", []string{}, + "uniq-id of the cloud server. For multiple, must be ',' separated") if err := cloudServerDetailsCmd.MarkFlagRequired("uniq-id"); err != nil { lwCliInst.Die(err) diff --git a/cmd/dedicatedServerDetails.go b/cmd/dedicatedServerDetails.go index f5f3444..ce439f7 100644 --- a/cmd/dedicatedServerDetails.go +++ b/cmd/dedicatedServerDetails.go @@ -24,51 +24,55 @@ import ( "github.com/liquidweb/liquidweb-cli/validate" ) +var dedicatedServerDetailsCmdUniqIdFlag []string + var dedicatedServerDetailsCmd = &cobra.Command{ Use: "details", Short: "Get details of a dedicated server", Long: `Get details of a dedicated server`, Run: func(cmd *cobra.Command, args []string) { - uniqIdFlag, _ := cmd.Flags().GetString("uniq-id") jsonFlag, _ := cmd.Flags().GetBool("json") - validateFields := map[interface{}]interface{}{ - uniqIdFlag: "UniqId", - } - if err := validate.Validate(validateFields); err != nil { - lwCliInst.Die(err) - } + for _, uniqId := range dedicatedServerDetailsCmdUniqIdFlag { + validateFields := map[interface{}]interface{}{ + uniqId: "UniqId", + } + if err := validate.Validate(validateFields); err != nil { + fmt.Printf("%s ... skipping\n", err) + continue + } - var details apiTypes.Subaccnt - apiArgs := map[string]interface{}{ - "uniq_id": uniqIdFlag, - "alsowith": []string{"categories"}, - } + var details apiTypes.Subaccnt + apiArgs := map[string]interface{}{ + "uniq_id": uniqId, + "alsowith": []string{"categories"}, + } - if err := lwCliInst.CallLwApiInto("bleed/asset/details", apiArgs, &details); err != nil { - lwCliInst.Die(err) - } + if err := lwCliInst.CallLwApiInto("bleed/asset/details", apiArgs, &details); err != nil { + lwCliInst.Die(err) + } - var found bool - for _, category := range details.Categories { - if category == "StrictDedicated" { - found = true - break + var found bool + for _, category := range details.Categories { + if category == "StrictDedicated" { + found = true + break + } } - } - if !found { - lwCliInst.Die(fmt.Errorf("UniqId [%s] is not a dedicated server", uniqIdFlag)) - } + if !found { + lwCliInst.Die(fmt.Errorf("UniqId [%s] is not a dedicated server", uniqId)) + } - if jsonFlag { - pretty, err := lwCliInst.JsonEncodeAndPrettyPrint(details) - if err != nil { - panic(err) + if jsonFlag { + pretty, err := lwCliInst.JsonEncodeAndPrettyPrint(details) + if err != nil { + panic(err) + } + fmt.Print(pretty) + } else { + fmt.Print(details) } - fmt.Print(pretty) - } else { - fmt.Print(details) } }, } @@ -77,7 +81,8 @@ func init() { dedicatedServerCmd.AddCommand(dedicatedServerDetailsCmd) dedicatedServerDetailsCmd.Flags().Bool("json", false, "output in json format") - dedicatedServerDetailsCmd.Flags().String("uniq-id", "", "uniq-id of the dedicated server") + dedicatedServerDetailsCmd.Flags().StringSliceVar(&dedicatedServerDetailsCmdUniqIdFlag, "uniq-id", []string{}, + "uniq-id of the dedicated server. For multiple, must be ',' separated") if err := dedicatedServerDetailsCmd.MarkFlagRequired("uniq-id"); err != nil { lwCliInst.Die(err) From 552eaf33f025d88876feff53485534c2aa84d3a8 Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Thu, 22 Oct 2020 23:16:11 -0400 Subject: [PATCH 09/17] fill out help --- cmd/ssh.go | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/cmd/ssh.go b/cmd/ssh.go index bea979d..e6be62c 100644 --- a/cmd/ssh.go +++ b/cmd/ssh.go @@ -26,7 +26,36 @@ var sshCmd = &cobra.Command{ Short: "SSH to a Server", Long: `SSH to a Server. -Gives you an interactive shell to your Server.`, +Starts an interactive SSH session to your server. If --command is passed, a non interactive +session is started running only your passed command. + +Examples: + +* SSH by hostname accepting all defaults: +- lw ssh --host dexg.ulxy5e656r.io + +* SSH by uniq-id accepting all defaults: +- lw ssh --host ABC123 + +* SSH by uniq-id making use of all flags: +- lw ssh --host ABC123 --agent-forwarding --port 2222 --private-ssh-key /home/myself/.ssh-alt/id_rsa \ + --user amanda --command "ps faux && free -m" + +Plan Examples: + +--- +ssh: + - host: nd00.ltv1wv76kc.io + command: "free -m" + user: "root" + private-key: "/home/myself/.ssh/id_rsa" + agent-forwarding: true + port: 22 + - host: PPB4NZ + command: "hostname && free -m" + +lw plan --file /tmp/above.yaml +`, Run: func(cmd *cobra.Command, args []string) { params := &instance.SshParams{} From 1d577216b8e1b96a99ee34324bc6dd87dbbaa508 Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Thu, 22 Oct 2020 23:28:21 -0400 Subject: [PATCH 10/17] update docs/help --- README.md | 2 ++ cmd/cloudServerCreate.go | 32 +++++++++++++++++++++++++++++++- cmd/cloudServerResize.go | 26 +++++++++++++++++--------- cmd/ssh.go | 2 +- 4 files changed, 51 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 789d039..2936cda 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,8 @@ cloud: bandwidth: "SS.5000" ``` +You can find more examples of plans in `examples/plans`. + ### Plan Variables Plan yaml can make use of golang's template variables. Allows variables to be passed on the diff --git a/cmd/cloudServerCreate.go b/cmd/cloudServerCreate.go index 891127c..de32890 100644 --- a/cmd/cloudServerCreate.go +++ b/cmd/cloudServerCreate.go @@ -39,7 +39,7 @@ Requires various flags. Please see the flag section of help. Examples: # Create a Cloud Server on a Private Parent named "private" -'cloud server create --private-parent private --memory 1024 --diskspace 40 --vcpu 2 --zone 40460 --template DEBIAN_10_UNMANAGED' +'cloud server create --private-parent private --memory 1024 --diskspace 40 --vcpu 2 --template DEBIAN_10_UNMANAGED' # Create a Cloud Server on config-id 1 'cloud server create --config-id 1 --template DEBIAN_10_UNMANAGED --zone 40460' @@ -55,6 +55,36 @@ These examples use default values for various flags, such as password, type, ssh For a list of Templates, Configs, and Region/Zones, see 'cloud server options --configs --templates --zones' For a list of images, see 'cloud images list' For a list of backups, see 'cloud backups list' + +Plan Example: + +--- +cloud: + server: + create: + - type: "SS.VPS.WIN" + password: "1fk4ds$jktl43u90dsa" + template: "WINDOWS_2019_UNMANAGED" + zone: 40460 + hostname: "db1.dev.addictmud.org" + ips: 1 + public-ssh-key: "" + config-id: 88 + backup-days: 5 + bandwidth: "SS.5000" + backup-id: -1 + image-id: -1 + pool-ips: + - "10.111.12.13" + - "10.12.13.14" + private-parent: "my pp" + memory: 0 + diskspace: 0 + vcpu: 0 + winav: "" + ms-sql: "" + +lw plan --file /tmp/cloud.server.create.yaml `, Run: func(cmd *cobra.Command, args []string) { params := &instance.CloudServerCreateParams{} diff --git a/cmd/cloudServerResize.go b/cmd/cloudServerResize.go index 8895264..c0dc709 100644 --- a/cmd/cloudServerResize.go +++ b/cmd/cloudServerResize.go @@ -56,15 +56,23 @@ are required: Downtime Expectations: -When resizing a Cloud Server on a private parent, you can add memory or vcpu(s) -without downtime. If you change the diskspace however, then a reboot will be -required. - -When resizing a Cloud Server that isn't on a private parent, there will be one -reboot during the resize. The only case there will be two reboots is when -going to a config with more diskspace, and --skip-fs-resize wasn't passed. - -During all resizes, the Cloud Server is online as the disk synchronizes. +Please see 'lw help cloud server resize-expection' to determine if a specific +resize would require a reboot or not. + +Plan Example: + +--- +cloud: + server: + resize: + - config-id: 0 + private-parent: "nvme-pp" + uniq-id: "{{- .Var.uniq_id -}}" + diskspace: 1800 + vcpu: 16 + memory: 124000 + +lw plan --file /tmp/cloud.server.resize.yaml --var uniq_id=ABC123 `, Run: func(cmd *cobra.Command, args []string) { params := &instance.CloudServerResizeParams{} diff --git a/cmd/ssh.go b/cmd/ssh.go index e6be62c..014cd73 100644 --- a/cmd/ssh.go +++ b/cmd/ssh.go @@ -54,7 +54,7 @@ ssh: - host: PPB4NZ command: "hostname && free -m" -lw plan --file /tmp/above.yaml +lw plan --file /tmp/ssh.yaml `, Run: func(cmd *cobra.Command, args []string) { params := &instance.SshParams{} From 769391f5c6461fbc8616ec4f8610526daf418505 Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Thu, 22 Oct 2020 23:29:09 -0400 Subject: [PATCH 11/17] update help on readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 2936cda..9b3044b 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,15 @@ Usage: lw [command] Available Commands: + asset All things assets. auth authentication actions cloud Interact with LiquidWeb's Cloud platform. + completion Generate completion script + dedicated All things dedicated server. help Help about any command network network actions plan Process YAML plan file + ssh SSH to a Server version show build information Flags: From d3789f1e293db167c42ae34ef4f628e3e54cb01a Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Thu, 22 Oct 2020 23:34:25 -0400 Subject: [PATCH 12/17] add cloud.template.restore plan --- README.md | 1 + cmd/cloudTemplateRestore.go | 14 +++++++++++++- examples/plans/cloud.template.restore.yaml | 6 ++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 examples/plans/cloud.template.restore.yaml diff --git a/README.md b/README.md index 9b3044b..5b13f40 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ Current commands supported in a `plan` file: - cloud server create - cloud server resize - cloud template restore +- ssh Example: diff --git a/cmd/cloudTemplateRestore.go b/cmd/cloudTemplateRestore.go index 7bc3b00..d3e2b1c 100644 --- a/cmd/cloudTemplateRestore.go +++ b/cmd/cloudTemplateRestore.go @@ -26,7 +26,19 @@ import ( var cloudTemplateRestoreCmd = &cobra.Command{ Use: "restore", Short: "Restore a Cloud Template on a Cloud Server", - Long: `Restore a Cloud Template on a Cloud Server.`, + Long: `Restore a Cloud Template on a Cloud Server. + +Plan Example: + +--- +cloud: + template: + restore: + - uniq-id: ABC123 + template: DEBIAN_10_UNMANAGED + +lw plan --file cloud.template.restore.yaml +`, Run: func(cmd *cobra.Command, args []string) { params := &instance.CloudTemplateRestoreParams{} diff --git a/examples/plans/cloud.template.restore.yaml b/examples/plans/cloud.template.restore.yaml new file mode 100644 index 0000000..cb250df --- /dev/null +++ b/examples/plans/cloud.template.restore.yaml @@ -0,0 +1,6 @@ +--- +cloud: + template: + restore: + - uniq-id: ABC123 + template: DEBIAN_10_UNMANAGED From 6762b1a179d3dad550486b0e5a283cb6666540a0 Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Fri, 23 Oct 2020 14:38:08 -0400 Subject: [PATCH 13/17] remove period --- README.md | 4 ++-- cmd/asset.go | 2 +- cmd/dedicated.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5b13f40..391fb2e 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,11 @@ Usage: lw [command] Available Commands: - asset All things assets. + asset All things assets auth authentication actions cloud Interact with LiquidWeb's Cloud platform. completion Generate completion script - dedicated All things dedicated server. + dedicated All things dedicated server help Help about any command network network actions plan Process YAML plan file diff --git a/cmd/asset.go b/cmd/asset.go index 55d263e..bf4f744 100644 --- a/cmd/asset.go +++ b/cmd/asset.go @@ -23,7 +23,7 @@ import ( var assetCmd = &cobra.Command{ Use: "asset", - Short: "All things assets.", + Short: "All things assets", Long: `An asset is an individual component on an account. For a full list of capabilities, please refer to the "Available Commands" section.`, diff --git a/cmd/dedicated.go b/cmd/dedicated.go index de1a5ec..32a5ffe 100644 --- a/cmd/dedicated.go +++ b/cmd/dedicated.go @@ -23,7 +23,7 @@ import ( var dedicatedCmd = &cobra.Command{ Use: "dedicated", - Short: "All things dedicated server.", + Short: "All things dedicated server", Long: `Command line interface for all things specific to running dedicated servers. For a full list of capabilities, please refer to the "Available Commands" section.`, From 4d053e3837b2777d00adc81b3b4638c2dada1d04 Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Fri, 23 Oct 2020 14:38:48 -0400 Subject: [PATCH 14/17] remove period --- README.md | 2 +- cmd/cloud.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 391fb2e..7beb881 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Usage: Available Commands: asset All things assets auth authentication actions - cloud Interact with LiquidWeb's Cloud platform. + cloud Interact with LiquidWeb's Cloud platform completion Generate completion script dedicated All things dedicated server help Help about any command diff --git a/cmd/cloud.go b/cmd/cloud.go index a0901b8..18e8ae8 100644 --- a/cmd/cloud.go +++ b/cmd/cloud.go @@ -23,7 +23,7 @@ import ( var cloudCmd = &cobra.Command{ Use: "cloud", - Short: "Interact with LiquidWeb's Cloud platform.", + Short: "Interact with LiquidWeb's Cloud platform", Long: `Command line interface to LiquidWeb's Cloud platform. For a full list of capabilities, please refer to the "Available Commands" section.`, From 254c9780ef00a45fee7809afb3f6f7e7232d16c6 Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Fri, 23 Oct 2020 14:43:27 -0400 Subject: [PATCH 15/17] useless Printf --- cmd/assetDetails.go | 2 +- cmd/assetList.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/assetDetails.go b/cmd/assetDetails.go index 1af45ff..652dc6b 100644 --- a/cmd/assetDetails.go +++ b/cmd/assetDetails.go @@ -60,7 +60,7 @@ An asset is an individual component on an account. Assets have categories. if err != nil { lwCliInst.Die(err) } - fmt.Printf(pretty) + fmt.Print(pretty) } else { fmt.Print(details) } diff --git a/cmd/assetList.go b/cmd/assetList.go index d40db92..4db9ec4 100644 --- a/cmd/assetList.go +++ b/cmd/assetList.go @@ -67,7 +67,7 @@ Examples: if err != nil { lwCliInst.Die(err) } - fmt.Printf(pretty) + fmt.Print(pretty) } else { cnt := 1 for _, item := range results.Items { From 2db7e0669e8716483008ddf6fe3ab5bb8b28f96e Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Fri, 23 Oct 2020 14:52:34 -0400 Subject: [PATCH 16/17] add missing :: --- types/api/subaccnt.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/api/subaccnt.go b/types/api/subaccnt.go index 7ef45c6..b1926b8 100644 --- a/types/api/subaccnt.go +++ b/types/api/subaccnt.go @@ -25,7 +25,7 @@ func (x Subaccnt) String() string { slice = append(slice, fmt.Sprintf("Domain: %s UniqId: %s\n", x.Domain, x.UniqId)) if len(x.Categories) > 0 { - slice = append(slice, fmt.Sprintln("\tCategories")) + slice = append(slice, fmt.Sprintln("\tCategories:")) for _, category := range x.Categories { slice = append(slice, fmt.Sprintf("\t\t* %s\n", category)) } From 8f53d1c1a60a238ab559b3cda729b7dbbba9fb54 Mon Sep 17 00:00:00 2001 From: Scott Sullivan Date: Mon, 26 Oct 2020 13:33:26 -0400 Subject: [PATCH 17/17] include file in name --- cmd/ssh.go | 8 ++++---- examples/plans/ssh.yaml | 2 +- instance/ssh.go | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmd/ssh.go b/cmd/ssh.go index 014cd73..1957e35 100644 --- a/cmd/ssh.go +++ b/cmd/ssh.go @@ -38,7 +38,7 @@ Examples: - lw ssh --host ABC123 * SSH by uniq-id making use of all flags: -- lw ssh --host ABC123 --agent-forwarding --port 2222 --private-ssh-key /home/myself/.ssh-alt/id_rsa \ +- lw ssh --host ABC123 --agent-forwarding --port 2222 --private-key-file /home/myself/.ssh-alt/id_rsa \ --user amanda --command "ps faux && free -m" Plan Examples: @@ -48,7 +48,7 @@ ssh: - host: nd00.ltv1wv76kc.io command: "free -m" user: "root" - private-key: "/home/myself/.ssh/id_rsa" + private-key-file: "/home/myself/.ssh/id_rsa" agent-forwarding: true port: 22 - host: PPB4NZ @@ -60,7 +60,7 @@ lw plan --file /tmp/ssh.yaml params := &instance.SshParams{} params.Host, _ = cmd.Flags().GetString("host") - params.PrivateKey, _ = cmd.Flags().GetString("private-ssh-key") + params.PrivateKeyFile, _ = cmd.Flags().GetString("private-key-file") params.User, _ = cmd.Flags().GetString("user") params.AgentForwarding, _ = cmd.Flags().GetBool("agent-forwarding") params.Port, _ = cmd.Flags().GetInt("port") @@ -77,7 +77,7 @@ func init() { sshCmd.Flags().String("host", "", "uniq-id or hostname for the Server") sshCmd.Flags().Int("port", 22, "ssh port to use") - sshCmd.Flags().String("private-ssh-key", "", "path to a specific/non default ssh private key to use") + sshCmd.Flags().String("private-key-file", "", "path to a specific/non default ssh private key to use") sshCmd.Flags().Bool("agent-forwarding", false, "whether or not to enable ssh agent forwarding") sshCmd.Flags().String("user", "root", "username to use for the ssh connection") sshCmd.Flags().String("command", "", "run this command and exit rather than start an interactive shell") diff --git a/examples/plans/ssh.yaml b/examples/plans/ssh.yaml index e1f93c8..66e2d51 100644 --- a/examples/plans/ssh.yaml +++ b/examples/plans/ssh.yaml @@ -3,7 +3,7 @@ ssh: - host: nd00.ltv1wv76kc.io command: "free -m" user: "root" - private-key: "/home/myself/.ssh/id_rsa" + private-key-file: "/home/myself/.ssh/id_rsa" agent-forwarding: true port: 22 - host: PPB4NZ diff --git a/instance/ssh.go b/instance/ssh.go index 18fafc3..9b86af8 100644 --- a/instance/ssh.go +++ b/instance/ssh.go @@ -27,7 +27,7 @@ import ( type SshParams struct { Host string `yaml:"host"` Port int `yaml:"port"` - PrivateKey string `yaml:"private-key"` + PrivateKeyFile string `yaml:"private-key-file"` User string `yaml:"user"` AgentForwarding bool `yaml:"agent-forwarding"` Command string `yaml:"command"` @@ -108,8 +108,8 @@ func (self *Client) Ssh(params *SshParams) (err error) { } sshArgs := []string{} - if params.PrivateKey != "" { - sshArgs = append(sshArgs, "-i", params.PrivateKey) + if params.PrivateKeyFile != "" { + sshArgs = append(sshArgs, "-i", params.PrivateKeyFile) } if params.AgentForwarding {