From 2db00419a6ed7e34eefb5b8fe2175a5b0ee9b50e Mon Sep 17 00:00:00 2001 From: Eyal Gonen Date: Sat, 27 Apr 2024 04:48:06 +0300 Subject: [PATCH 1/7] Add new "getall" command which downloads certs + deploymentAssets + license in one step --- cmd/getall.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 cmd/getall.go diff --git a/cmd/getall.go b/cmd/getall.go new file mode 100644 index 0000000..2ffe2c4 --- /dev/null +++ b/cmd/getall.go @@ -0,0 +1,44 @@ +// Copyright © 2020-2023, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package cmd + +import ( + "log" + + "github.com/sassoftware/viya4-orders-cli/lib/assetreqs" + "github.com/spf13/cobra" +) + +// getallCmd represents the getall command +var getallCmd = &cobra.Command{ + Use: "getall [order number] [cadence name] [cadence version]", + Short: "Download all downloadable objects (assets + license + certs) for the given order number at the given cadence name and version ", + Example: "viya4-orders-cli getall 993456 stable 2020.0.3\n" + + "viya4-orders-cli getall 993456 stable 2020.0.3 -p $HOME/sas -n license_993456_stable_2020.0.3", + Aliases: []string{"all"}, + Args: cobra.ExactArgs(3), + Run: func(cmd *cobra.Command, args []string) { + ar := assetreqs.New(token, "license", args[0], args[1], args[2], assetFilePath, "", outFormat, allowUnsuppd) + err := ar.GetAsset() + if err != nil { + log.Fatalln(err) + } + + ar = assetreqs.New(token, "deploymentAssets", args[0], args[1], args[2], assetFilePath, "", outFormat, allowUnsuppd) + err = ar.GetAsset() + if err != nil { + log.Fatalln(err) + } + + ar = assetreqs.New(token, "certificates", args[0], "", "", assetFilePath, "", outFormat, allowUnsuppd) + err = ar.GetAsset() + if err != nil { + log.Fatalln(err) + } + }, +} + +func init() { + rootCmd.AddCommand(getallCmd) +} From 9e529a0cb3dac81b54e2f7a753ea139bd8136081 Mon Sep 17 00:00:00 2001 From: Eyal Gonen Date: Sat, 27 Apr 2024 15:50:10 +0300 Subject: [PATCH 2/7] Run the three downloads in parallel using go routines Update README to indicate the new "getall" command --- README.md | 1 + cmd/getall.go | 52 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index db2292b..1f5322e 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Available Commands: deploymentAssets Download deployment assets for the given order number at the given cadence name and version - if version not specified, get the latest version of the given cadence name help Help about any command license Download a license for the given order number at the given cadence name and version + getall Download license + certificates + deploymentAssests for the given order number at the given cadence name and version Flags: -c, --config string config file (default is $HOME/.viya4-orders-cli) diff --git a/cmd/getall.go b/cmd/getall.go index 2ffe2c4..d83500a 100644 --- a/cmd/getall.go +++ b/cmd/getall.go @@ -5,6 +5,7 @@ package cmd import ( "log" + "sync" "github.com/sassoftware/viya4-orders-cli/lib/assetreqs" "github.com/spf13/cobra" @@ -19,23 +20,40 @@ var getallCmd = &cobra.Command{ Aliases: []string{"all"}, Args: cobra.ExactArgs(3), Run: func(cmd *cobra.Command, args []string) { - ar := assetreqs.New(token, "license", args[0], args[1], args[2], assetFilePath, "", outFormat, allowUnsuppd) - err := ar.GetAsset() - if err != nil { - log.Fatalln(err) - } - - ar = assetreqs.New(token, "deploymentAssets", args[0], args[1], args[2], assetFilePath, "", outFormat, allowUnsuppd) - err = ar.GetAsset() - if err != nil { - log.Fatalln(err) - } - - ar = assetreqs.New(token, "certificates", args[0], "", "", assetFilePath, "", outFormat, allowUnsuppd) - err = ar.GetAsset() - if err != nil { - log.Fatalln(err) - } + + var wg sync.WaitGroup + + wg.Add(3) + + go func() { + ar := assetreqs.New(token, "license", args[0], args[1], args[2], assetFilePath, "", outFormat, allowUnsuppd) + err := ar.GetAsset() + if err != nil { + log.Fatalln(err) + } + wg.Done() + }() + + go func() { + ar := assetreqs.New(token, "deploymentAssets", args[0], args[1], args[2], assetFilePath, "", outFormat, allowUnsuppd) + err := ar.GetAsset() + if err != nil { + log.Fatalln(err) + } + wg.Done() + }() + + go func() { + ar := assetreqs.New(token, "certificates", args[0], "", "", assetFilePath, "", outFormat, allowUnsuppd) + err := ar.GetAsset() + if err != nil { + log.Fatalln(err) + } + wg.Done() + }() + + wg.Wait() + }, } From ec71a296b5ba827846fa2c5f8a20752e7dd8ce2d Mon Sep 17 00:00:00 2001 From: Eyal Gonen Date: Sat, 27 Apr 2024 15:56:50 +0300 Subject: [PATCH 3/7] Update README with more clarifications about the new "getall" command --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1f5322e..9751059 100644 --- a/README.md +++ b/README.md @@ -207,6 +207,8 @@ using SAS Viya Orders CLI: --config /sasstuff/.viya4-orders-cli.yaml --file-path /sasstuff/sasfiles --file-name 923456_lts_depassets ``` + NOTE: the `--file-name` option is not applicable when using the `getall` command + Sample output: ```text From 675cf8b58740e4e52e71a54e156596f9ef3814cd Mon Sep 17 00:00:00 2001 From: Eyal Gonen Date: Sun, 28 Apr 2024 08:27:48 +0300 Subject: [PATCH 4/7] Run the three goroutines in a for loop --- cmd/getall.go | 54 +++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/cmd/getall.go b/cmd/getall.go index d83500a..a51ebd3 100644 --- a/cmd/getall.go +++ b/cmd/getall.go @@ -22,35 +22,33 @@ var getallCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { var wg sync.WaitGroup + var objectTypes []string = []string{"license", "deploymentAssets", "certificates"} - wg.Add(3) - - go func() { - ar := assetreqs.New(token, "license", args[0], args[1], args[2], assetFilePath, "", outFormat, allowUnsuppd) - err := ar.GetAsset() - if err != nil { - log.Fatalln(err) - } - wg.Done() - }() - - go func() { - ar := assetreqs.New(token, "deploymentAssets", args[0], args[1], args[2], assetFilePath, "", outFormat, allowUnsuppd) - err := ar.GetAsset() - if err != nil { - log.Fatalln(err) - } - wg.Done() - }() - - go func() { - ar := assetreqs.New(token, "certificates", args[0], "", "", assetFilePath, "", outFormat, allowUnsuppd) - err := ar.GetAsset() - if err != nil { - log.Fatalln(err) - } - wg.Done() - }() + for _, v := range objectTypes { + + wg.Add(1) + + // cannot reference "v" directly inside func see https://stackoverflow.com/questions/39207608/how-does-golang-share-variables-between-goroutines + go func(objectType string) { + + var p2, p3 string + defer wg.Done() + + switch objectType { + case "certificates": + p2, p3 = "", "" + default: + p2, p3 = args[1], args[2] + } + + ar := assetreqs.New(token, objectType, args[0], p2, p3, assetFilePath, "", outFormat, allowUnsuppd) + err := ar.GetAsset() + if err != nil { + log.Fatalln(err) + } + }(v) + + } wg.Wait() From 171866868de12c17dfd72f39643e1caf40208382 Mon Sep 17 00:00:00 2001 From: Eyal Gonen Date: Sun, 28 Apr 2024 08:54:59 +0300 Subject: [PATCH 5/7] Log a message saying that the "--file-name" option is ignored for the "getall" command --- cmd/getall.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd/getall.go b/cmd/getall.go index a51ebd3..bf0dc3d 100644 --- a/cmd/getall.go +++ b/cmd/getall.go @@ -21,6 +21,12 @@ var getallCmd = &cobra.Command{ Args: cobra.ExactArgs(3), Run: func(cmd *cobra.Command, args []string) { + // check if "file-name" flag is used and if so, log a message this parameter is ignored with the getall command + //if cmd.Flags().Lookup("file-name").Changed { + if assetFileName != "" { + log.Println("The getall command ignores the file-name option. Default file names will be used instead.") + } + var wg sync.WaitGroup var objectTypes []string = []string{"license", "deploymentAssets", "certificates"} From a58715b9604b23344a5bdd8fc906f7b28b6f419b Mon Sep 17 00:00:00 2001 From: Eyal Gonen Date: Sun, 28 Apr 2024 10:38:27 +0300 Subject: [PATCH 6/7] Tidy up code --- cmd/getall.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd/getall.go b/cmd/getall.go index bf0dc3d..15cc0c7 100644 --- a/cmd/getall.go +++ b/cmd/getall.go @@ -24,33 +24,33 @@ var getallCmd = &cobra.Command{ // check if "file-name" flag is used and if so, log a message this parameter is ignored with the getall command //if cmd.Flags().Lookup("file-name").Changed { if assetFileName != "" { - log.Println("The getall command ignores the file-name option. Default file names will be used instead.") + log.Println("The getall command ignores the --file-name option. Default file names will be used instead.") } var wg sync.WaitGroup - var objectTypes []string = []string{"license", "deploymentAssets", "certificates"} + var assetTypes []string = []string{"license", "deploymentAssets", "certificates"} - for _, v := range objectTypes { + for _, v := range assetTypes { wg.Add(1) // cannot reference "v" directly inside func see https://stackoverflow.com/questions/39207608/how-does-golang-share-variables-between-goroutines - go func(objectType string) { + go func(assetType string) { var p2, p3 string defer wg.Done() - switch objectType { + switch assetType { case "certificates": p2, p3 = "", "" default: p2, p3 = args[1], args[2] } - ar := assetreqs.New(token, objectType, args[0], p2, p3, assetFilePath, "", outFormat, allowUnsuppd) + ar := assetreqs.New(token, assetType, args[0], p2, p3, assetFilePath, "", outFormat, allowUnsuppd) err := ar.GetAsset() if err != nil { - log.Fatalln(err) + log.Fatalln("Error ocurred while getting asset type", assetType, "error is:", err) } }(v) From 74baa976ae8ded7311f047144019eeb45dd7ed9b Mon Sep 17 00:00:00 2001 From: Eyal Gonen Date: Sun, 28 Apr 2024 13:09:59 +0300 Subject: [PATCH 7/7] Switch from Fatal to Panic to capture and recover gracefully from unexpected errors --- cmd/getall.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/cmd/getall.go b/cmd/getall.go index 15cc0c7..83e91d9 100644 --- a/cmd/getall.go +++ b/cmd/getall.go @@ -35,10 +35,15 @@ var getallCmd = &cobra.Command{ wg.Add(1) // cannot reference "v" directly inside func see https://stackoverflow.com/questions/39207608/how-does-golang-share-variables-between-goroutines + // even though it was supposed to work fine in Go 1.22 https://go.dev/blog/go1.22 go func(assetType string) { + defer func() { + recover() + wg.Done() + }() + var p2, p3 string - defer wg.Done() switch assetType { case "certificates": @@ -50,13 +55,15 @@ var getallCmd = &cobra.Command{ ar := assetreqs.New(token, assetType, args[0], p2, p3, assetFilePath, "", outFormat, allowUnsuppd) err := ar.GetAsset() if err != nil { - log.Fatalln("Error ocurred while getting asset type", assetType, "error is:", err) + log.Panicln("Error ocurred while getting asset type", assetType, "error is:", err) } }(v) } + log.Println("Waiting for downloads to complete.") wg.Wait() + log.Println("Downloads are complete.") }, }