Skip to content

Commit

Permalink
fixed usage help and error handling for solutions and objstore (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
pnickolov authored Feb 17, 2023
1 parent ae72320 commit 7d87038
Show file tree
Hide file tree
Showing 17 changed files with 177 additions and 216 deletions.
48 changes: 19 additions & 29 deletions cmd/objstore/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ package objstore

import (
"encoding/json"
"fmt"
"io"
"os"

"github.com/apex/log"
"github.com/spf13/cobra"

"github.com/cisco-open/fsoc/output"
"github.com/cisco-open/fsoc/platform/api"
)

Expand All @@ -30,14 +32,9 @@ var objStoreInsertCmd = &cobra.Command{
Short: "Create a new object of a given type",
Long: `This command allows the creation of a new object of a given type in the Object Store.
Usage:
fsoc objstore create --type<fully-qualified-typename> --object-file=<fully-qualified-path> --layer-type=<valid-layer-type> [--layer-id=<valid-layer-id>]
Flags/Options:
--type - Flag to indicate the fully qualified type name of the object that you would like to create
--object-file - Flag to indicate the fully qualified path (from your root directory) to the file containing the definition of the object that you want to create
--layer-type - Flag to indicate the layer at which you would like to create your object
--layer-id - OPTIONAL Flag to specify a custom layer ID for the object that you would like to create. This is calculated automatically for all layers currently supported but can be overridden with this flag`,
Example:
fsoc objstore create --type<fully-qualified-typename> --object-file=<fully-qualified-path> --layer-type=<valid-layer-type> [--layer-id=<valid-layer-id>]
`,

Args: cobra.ExactArgs(0),
Run: insertObject,
Expand All @@ -50,7 +47,7 @@ func getCreateObjectCmd() *cobra.Command {
_ = objStoreInsertCmd.MarkPersistentFlagRequired("type")

objStoreInsertCmd.Flags().
String("object-file", "", "The fully qualified path to the json file containing the object definition")
String("object-file", "", "The fully qualified path to the json file containing the object data")
_ = objStoreInsertCmd.MarkPersistentFlagRequired("objectFile")

objStoreInsertCmd.Flags().
Expand All @@ -70,31 +67,27 @@ func insertObject(cmd *cobra.Command, args []string) {
objJsonFilePath, _ := cmd.Flags().GetString("object-file")
objectFile, err := os.Open(objJsonFilePath)
if err != nil {
log.Errorf("Can't find the object definition file named %s", objJsonFilePath)
return
log.Fatalf("Can't find the object definition file named %q", objJsonFilePath)
}
defer objectFile.Close()

objectBytes, _ := io.ReadAll(objectFile)
var objectStruct map[string]interface{}
err = json.Unmarshal(objectBytes, &objectStruct)
if err != nil {
log.Errorf("Can't generate a %s object from the %s file. Make sure the object definition has all the required field and is valid according to the type definition.")
return
log.Fatalf("Failed to parse object data from file %q: %v. Make sure the object definition has all the required field and is valid according to the type definition.", objJsonFilePath, err)
}

layerType, _ := cmd.Flags().GetString("layer-type")
layerID := getCorrectLayerID(layerType, objType)

if layerID == "" {
if !cmd.Flags().Changed("layer-id") {
log.Error("Unable to set layer-id flag from given context. Please specify a unique layer-id value with the --layer-id flag")
return
log.Fatal("Unable to set layer-id flag from given context. Please specify a unique layer-id value with the --layer-id flag")
}
layerID, err = cmd.Flags().GetString("layer-id")
if err != nil {
log.Errorf("error trying to get %q flag value: %w", "layer-id", err)
return
log.Fatalf("error trying to get %q flag value: %w", "layer-id", err)
}
}

Expand All @@ -107,10 +100,9 @@ func insertObject(cmd *cobra.Command, args []string) {
// objJsonStr, err := json.Marshal(objectStruct)
err = api.JSONPost(getObjStoreObjectUrl()+"/"+objType, objectStruct, &res, &api.Options{Headers: headers})
if err != nil {
log.Errorf("objstore command failed: %v", err.Error())
return
log.Fatalf("Failed to create object: %v", err)
} else {
log.Infof("Successfully created %s object", objType)
log.Infof("Successfully created a %q object", objType)
}
}

Expand All @@ -122,11 +114,10 @@ var objStoreInsertPatchedObjectCmd = &cobra.Command{
Use: "create-patch",
Short: "Create a new patched object of a given type",
Long: `This command allows the creation of a new patched object of a given type in the Object Store.
A patched object inherits values from an object that exists at a higher layer and can also override mutable fields when needed.
A patched object inherits values from an object that exists at a higher layer and can also override mutable fields when needed.
Usage:
fsoc objstore create-patch --type<fully-qualified-typename> --object-file=<fully-qualified-path> --target-layer-type=<valid-layer-type> --parent-object-id=<valid-object-id>`,
Example:
fsoc objstore create-patch --type<fully-qualified-typename> --object-file=<fully-qualified-path> --target-layer-type=<valid-layer-type> --parent-object-id=<valid-object-id>`,

Args: cobra.ExactArgs(0),
Run: insertPatchObject,
Expand Down Expand Up @@ -160,7 +151,7 @@ func insertPatchObject(cmd *cobra.Command, args []string) {
objJsonFilePath, _ := cmd.Flags().GetString("object-file")
objectFile, err := os.Open(objJsonFilePath)
if err != nil {
log.Errorf("Can't find the object definition file named %s", objJsonFilePath)
log.Fatalf("Can't find the object definition file %q", objJsonFilePath)
return
}
defer objectFile.Close()
Expand All @@ -169,8 +160,7 @@ func insertPatchObject(cmd *cobra.Command, args []string) {
var objectStruct map[string]interface{}
err = json.Unmarshal(objectBytes, &objectStruct)
if err != nil {
log.Errorf("Can't generate a %s object from the %s file. Make sure the object definition has all the required fields and is valid according to the type definition.")
return
log.Fatalf("Failed to parse object data from file %q: %v. Make sure the object definition has all the required fields and is valid according to the type definition.", objJsonFilePath, err)
}

layerType, _ := cmd.Flags().GetString("target-layer-type")
Expand All @@ -184,9 +174,9 @@ func insertPatchObject(cmd *cobra.Command, args []string) {
var res any
err = api.JSONPatch(getObjStoreObjectUrl()+"/"+objType+"/"+parentObjId, objectStruct, &res, &api.Options{Headers: headers})
if err != nil {
log.Errorf("Creating a patched object command failed: %v", err.Error())
log.Fatalf("Failed to create object: %v", err)
return
} else {
log.Infof("Successfully created patched %s object at the %s layer", objType, layerType)
output.PrintCmdOutput(cmd, fmt.Sprintf("Successfully created a patched %q object at the %s layer.\n", objType, layerType))
}
}
31 changes: 12 additions & 19 deletions cmd/objstore/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,13 @@ var objStoreDeleteCmd = &cobra.Command{
Short: "Delete an existent knowledge object",
Long: `This command allows an existent knowledge object to be deleted.
Usage:
fsoc objstore delete --type=<fully-qualified-typename>
--object-id=<object id>
--layer-type=[SOLUTION|ACCOUNT|GLOBALUSER|TENANT|LOCALUSER]
--layer-id=<respective-layer-id>
Flags/Options:
--type - Flag to indicate the fully qualified type name of the object that you would like to delete
--object-id - Flag to indicate the ID of the object which you would like to delete
--layer-type - Flag to indicate the layer at which the object you would like to delete currently exists
--layer-id - OPTIONAL Flag to specify a custom layer ID for the object that you would like to delete. This is calculated automatically for all layers currently supported but can be overridden with this flag`,
Usage:
fsoc objstore delete \
--type=<fully-qualified-typename> \
--object-id=<object id> \
--layer-type=[SOLUTION|ACCOUNT|GLOBALUSER|TENANT|LOCALUSER] \
--layer-id=<respective-layer-id>
`,

Args: cobra.ExactArgs(0),
Run: deleteObject,
Expand Down Expand Up @@ -76,13 +72,11 @@ func deleteObject(cmd *cobra.Command, args []string) {

if layerID == "" {
if !cmd.Flags().Changed("layer-id") {
log.Error("Unable to set layer-id flag from given context. Please specify a unique layer-id value with the --layer-id flag")
return
log.Fatalf("Unable to set layer-id flag from given context. Please specify a unique layer-id value with the --layer-id flag")
}
layerID, err = cmd.Flags().GetString("layer-id")
if err != nil {
log.Errorf("error trying to get %q flag value: %w", "layer-id", err)
return
log.Fatalf("error trying to get %q flag value: %w", "layer-id", err)
}
}

Expand All @@ -96,11 +90,10 @@ func deleteObject(cmd *cobra.Command, args []string) {
urlStrf := getObjStoreObjectUrl() + "/%s/%s"
objectUrl := fmt.Sprintf(urlStrf, objType, objId)

output.PrintCmdStatus(cmd, (fmt.Sprintf("Deleting object %s of type %s \n", objId, objType)))
output.PrintCmdStatus(cmd, (fmt.Sprintf("Deleting object %q of type %q\n", objId, objType)))
err = api.JSONDelete(objectUrl, &res, &api.Options{Headers: headers})
if err != nil {
log.Errorf("Solution command failed: %v", err.Error())
return
log.Fatalf("Failed to delete object: %v", err)
}
output.PrintCmdStatus(cmd, "Object was successfully deleted!\n")
output.PrintCmdStatus(cmd, "Object was successfully deleted.\n")
}
9 changes: 3 additions & 6 deletions cmd/objstore/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ func newGetObjectCmd() *cobra.Command {
//_ = getCmd.MarkPersistentFlagRequired("layer-id")
_ = getCmd.MarkPersistentFlagRequired("layer-type")

_ = getCmd.MarkPersistentFlagRequired("type")

return getCmd
}

Expand Down Expand Up @@ -130,7 +128,7 @@ func getObject(cmd *cobra.Command, args []string, ltFlag layerType) error {
layerID, _ := cmd.Flags().GetString("layer-id")
if layerID == "" {
if layerType == "SOLUTION" {
return fmt.Errorf("Error: for GET requests made to the SOLUTION layer, please manually supply the layerId flag")
return fmt.Errorf("Requests made to the SOLUTION layer require the --layer-id flag")
} else {
layerID = getCorrectLayerID(layerType, fqtn)
}
Expand All @@ -148,11 +146,10 @@ func getObject(cmd *cobra.Command, args []string, ltFlag layerType) error {
} else {
if cmd.Flags().Changed("filter") {
filterCriteria, err := cmd.Flags().GetString("filter")
query := fmt.Sprintf("filter=%s", url.QueryEscape(filterCriteria))
if err != nil {
log.Errorf("error trying to get %q flag value: %w", "filter", err)
return nil
return fmt.Errorf("error trying to get %q flag value: %w", "filter", err)
}
query := fmt.Sprintf("filter=%s", url.QueryEscape(filterCriteria))
fqtn = fqtn + "?" + query
}
objStoreUrl = getObjectListUrl(fqtn)
Expand Down
5 changes: 0 additions & 5 deletions cmd/objstore/objstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
package objstore

import (
"fmt"

"github.com/spf13/cobra"
)

Expand All @@ -43,9 +41,6 @@ See <docs url>`,
fsoc obj get --type=<typeName> --object=<objectId> --layer-id=<layerId> --layer-type=SOLUTION|ACCOUNT|GLOBALUSER|TENANT|LOCALUSER
# Get object
fsoc obj create --type=<fully-qualified-typename> --object-file=<fully-qualified-path> --layer-type=SOLUTION|ACCOUNT|GLOBALUSER|TENANT|LOCALUSER [--layer-id=<respective-layer-id>] `,
RunE: func(cmd *cobra.Command, args []string) error {
return fmt.Errorf("incomplete command")
},
TraverseChildren: true,
}

Expand Down
19 changes: 7 additions & 12 deletions cmd/objstore/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,31 +81,27 @@ func updateObject(cmd *cobra.Command, args []string) {
objJsonFilePath, _ := cmd.Flags().GetString("object-file")
objectFile, err := os.Open(objJsonFilePath)
if err != nil {
log.Errorf("Can't find the object definition file named %s", objJsonFilePath)
return
log.Fatalf("Can't find the object definition file named %s", objJsonFilePath)
}
defer objectFile.Close()

objectBytes, _ := io.ReadAll(objectFile)
var objectStruct map[string]interface{}
err = json.Unmarshal(objectBytes, &objectStruct)
if err != nil {
log.Errorf("Can't generate a %s object from the %s file. Make sure the object definition has all the required field and is valid according to the type definition.")
return
log.Fatalf("Can't parse file %q. Make sure the object definition has all the required field and is valid according to the type definition.", objJsonFilePath)
}

layerType, _ := cmd.Flags().GetString("layer-type")
layerID := getCorrectLayerID(layerType, objType)

if layerID == "" {
if !cmd.Flags().Changed("layer-id") {
log.Error("Unable to set layer-id flag from given context. Please specify a unique layer-id value with the --layer-id flag")
return
log.Fatal("Unable to set layer-id flag from given context. Please specify a unique layer-id value with the --layer-id flag")
}
layerID, err = cmd.Flags().GetString("layer-id")
if err != nil {
log.Errorf("error trying to get %q flag value: %w", "layer-id", err)
return
log.Fatalf("error trying to get %q flag value: %w", "layer-id", err)
}
}

Expand All @@ -119,11 +115,10 @@ func updateObject(cmd *cobra.Command, args []string) {
urlStrf := getObjStoreObjectUrl() + "/%s/%s"
objectUrl := fmt.Sprintf(urlStrf, objType, objId)

output.PrintCmdStatus(cmd, fmt.Sprintf("Replacing object %s with the new definition from %s \n", objId, objJsonFilePath))
output.PrintCmdStatus(cmd, fmt.Sprintf("Replacing object %q with the new data from %q \n", objId, objJsonFilePath))
err = api.JSONPut(objectUrl, objectStruct, &res, &api.Options{Headers: headers})
if err != nil {
log.Errorf("Solution command failed: %v", err.Error())
return
log.Fatalf("Object update failed: %v", err)
}
output.PrintCmdStatus(cmd, "Object replacement was done successfully!\n")
output.PrintCmdStatus(cmd, "Object updated successfully.\n")
}
18 changes: 9 additions & 9 deletions cmd/solution/author.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ func newTemplateServer(dir string) *templateServer {
}
exists, err := afero.DirExists(fileSystem, templatePath)
if err != nil || !exists {
log.Fatalf("Could not find %q directory specified in the manifest: %v", templatePath, err.Error())
log.Fatalf("Could not find %q directory specified in the manifest: %v", templatePath, err)
}

// create a termination signal channel
Expand Down Expand Up @@ -281,7 +281,7 @@ func (t *templateServer) callbackHandler(w http.ResponseWriter, r *http.Request)
fmt.Fprint(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
}
if err != nil {
log.Errorf("Error while parsing request: %v", err.Error())
log.Errorf("Error while parsing request: %v", err)
fmt.Fprint(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
}
if terminate {
Expand All @@ -294,7 +294,7 @@ func (t *templateServer) readTemplate(w http.ResponseWriter, r *http.Request, ur
file, err := afero.ReadFile(t.Fs, t.TemplatePath+URIParts[len(URIParts)-1])
log.Info("Getting file at " + t.TemplatePath + URIParts[len(URIParts)-1])
if err != nil {
log.Errorf("No such template file in this directory: %v", err.Error())
log.Errorf("No such template file in this directory: %v", err)
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return err
} else {
Expand All @@ -312,7 +312,7 @@ func (t *templateServer) readTemplate(w http.ResponseWriter, r *http.Request, ur
func (t *templateServer) returnTemplateList(w http.ResponseWriter, r *http.Request) error {
files, err := afero.ReadDir(t.Fs, t.TemplatePath)
if err != nil {
log.Errorf("Cannot read the files: %v", err.Error())
log.Errorf("Cannot read the files: %v", err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return err
}
Expand Down Expand Up @@ -341,12 +341,12 @@ func (t *templateServer) updateTemplate(w http.ResponseWriter, r *http.Request,
//var body string
b, err := io.ReadAll(r.Body)
if err != nil {
log.Errorf("Cannot read request body: %v", err.Error())
log.Errorf("Cannot read request body: %v", err)
}
URIParts := strings.Split(uri.RequestURI(), "/")
err = afero.WriteFile(t.Fs, t.TemplatePath+URIParts[len(URIParts)-1], b, 0644)
if err != nil {
log.Errorf("Error writing to this file: %v", err.Error())
log.Errorf("Error writing to this file: %v", err)
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return err
} else {
Expand All @@ -359,7 +359,7 @@ func (t *templateServer) deleteTemplateFile(w http.ResponseWriter, r *http.Reque
URIParts := strings.Split(uri.RequestURI(), "/")
err := t.Fs.Remove(t.TemplatePath + URIParts[len(URIParts)-1])
if err != nil {
log.Errorf("Error in deleting file: %v", err.Error())
log.Errorf("Error in deleting file: %v", err)
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return err
}
Expand All @@ -370,13 +370,13 @@ func (t *templateServer) deleteTemplateFile(w http.ResponseWriter, r *http.Reque
func checkURI(w http.ResponseWriter, r *http.Request) (*url.URL, error) {
_, err := url.Parse(callbackUrl)
if err != nil {
log.Errorf("Unexpected failure to obtain expected callback path (likely a bug): %v", err.Error())
log.Errorf("Unexpected failure to obtain expected callback path (likely a bug): %v", err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return nil, err
}
uri, err := url.Parse(r.RequestURI)
if err != nil {
log.Errorf("Unexpected failure to parse callback path received (malformed request?): %v", err.Error())
log.Errorf("Unexpected failure to parse callback path received (malformed request?): %v", err)
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return nil, err
}
Expand Down
Loading

0 comments on commit 7d87038

Please sign in to comment.