| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 commands |
| |
| import ( |
| "bufio" |
| "bytes" |
| "errors" |
| "fmt" |
| "reflect" |
| "strconv" |
| "strings" |
| |
| "github.com/apache/incubator-openwhisk-cli/wski18n" |
| "github.com/apache/incubator-openwhisk-client-go/whisk" |
| |
| "encoding/json" |
| "github.com/fatih/color" |
| "github.com/ghodss/yaml" |
| "github.com/spf13/cobra" |
| "regexp" |
| ) |
| |
| const ( |
| yamlFileExtension = "yaml" |
| ymlFileExtension = "yml" |
| |
| formatOptionYaml = "yaml" |
| formatOptionJson = "json" |
| |
| pathParamRegex = `\/\{([^\/]+)\}\/|\/\{([^\/]+)\}$|\{([^\/]+)}\/` |
| pathSegmentParamRegex = `^\/\{([^\/]+)\}\/$` |
| ) |
| |
| var apiCmd = &cobra.Command{ |
| Use: "api", |
| Short: wski18n.T("work with APIs"), |
| } |
| |
| var fmtString = "%-30s %7s %20s %s\n" |
| |
| // When set, this overrides the default authkey based api context id |
| var ContextId string |
| |
| // When set, this overrides the default access token used to authenticate with the api gw |
| var ApiGwAccessToken string |
| |
| func IsValidApiVerb(verb string) (error, bool) { |
| // Is the API verb valid? |
| if _, ok := whisk.ApiVerbs[strings.ToUpper(verb)]; !ok { |
| whisk.Debug(whisk.DbgError, "Invalid API verb: '%s'\n", verb) |
| errMsg := wski18n.T("'{{.verb}}' is not a valid API verb. Valid values are: {{.verbs}}", |
| map[string]interface{}{ |
| "verb": verb, |
| "verbs": reflect.ValueOf(whisk.ApiVerbs).MapKeys()}) |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return whiskErr, false |
| } |
| return nil, true |
| } |
| |
| func hasPathPrefix(path string) (error, bool) { |
| if !strings.HasPrefix(path, "/") { |
| whisk.Debug(whisk.DbgError, "path does not begin with '/': '%s'\n", path) |
| errMsg := wski18n.T("'{{.path}}' must begin with '/'.", |
| map[string]interface{}{ |
| "path": path, |
| }) |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return whiskErr, false |
| } |
| return nil, true |
| } |
| |
| func isValidBasepath(basepath string) (error, bool) { |
| if whiskerr, ok := hasPathPrefix(basepath); !ok { |
| return whiskerr, false |
| } |
| return nil, true |
| } |
| |
| func isValidRelpath(relpath string) (error, bool) { |
| if whiskerr, ok := hasPathPrefix(relpath); !ok { |
| return whiskerr, false |
| } |
| return nil, true |
| } |
| |
| func getPathParameterNames(path string) ([]string, error) { |
| var pathParameters []string |
| |
| regexObj, err := regexp.Compile(pathSegmentParamRegex) |
| if err != nil { |
| whisk.Debug(whisk.DbgError, "Failed to match path '%s' to regular expressions `%s`\n", path, pathSegmentParamRegex) |
| } else { |
| segments := strings.Split(path, "/") |
| for _, segment := range segments { |
| segment = fmt.Sprintf("/%s/", segment) |
| matchedItems := regexObj.FindAllStringSubmatch(segment, -1) |
| for _, matchedParam := range matchedItems { |
| for idx, paramName := range matchedParam { |
| whisk.Debug(whisk.DbgInfo, "Path parameter submatch '%v'; idx %v\n", paramName, idx) |
| if idx > 0 && len(paramName) > 0 { |
| pathParameters = append(pathParameters, paramName) |
| } |
| } |
| } |
| } |
| } |
| |
| return pathParameters, err |
| } |
| |
| func hasPathParameters(path string) (bool, error) { |
| pathParams, err := getPathParameterNames(path) |
| return len(pathParams) > 0, err |
| } |
| |
| func isBasepathParameterized(basepath string) (error, bool) { |
| hasParams, err := hasPathParameters(basepath) |
| if hasParams || err != nil { |
| errMsg := wski18n.T("The base path '{{.path}}' cannot have parameters. Only the relative path supports path parameters.", |
| map[string]interface{}{"path": basepath}) |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return whiskErr, false |
| } |
| return nil, true |
| } |
| |
| /* |
| * Pull the managedUrl (external API URL) from the API configuration |
| */ |
| func getManagedUrl(api *whisk.RetApi, relpath string, operation string) (url string) { |
| baseUrl := strings.TrimSuffix(api.BaseUrl, "/") |
| whisk.Debug(whisk.DbgInfo, "getManagedUrl: baseUrl = '%s', relpath = '%s', operation = '%s'\n", baseUrl, relpath, operation) |
| for path := range api.Swagger.Paths { |
| whisk.Debug(whisk.DbgInfo, "getManagedUrl: comparing api relpath: '%s'\n", path) |
| if path == relpath { |
| whisk.Debug(whisk.DbgInfo, "getManagedUrl: relpath matches '%s'\n", relpath) |
| for op := range api.Swagger.Paths[path].MakeOperationMap() { |
| whisk.Debug(whisk.DbgInfo, "getManagedUrl: comparing operation: '%s'\n", op) |
| if strings.ToLower(op) == strings.ToLower(operation) { |
| whisk.Debug(whisk.DbgInfo, "getManagedUrl: operation matches: '%s'\n", operation) |
| url = baseUrl + path |
| } |
| } |
| } |
| } |
| return url |
| } |
| |
| ////////////// |
| // Commands // |
| ////////////// |
| var apiCreateCmd = &cobra.Command{ |
| Use: "create ([BASE_PATH] API_PATH API_VERB ACTION] | --config-file CFG_FILE) ", |
| Short: wski18n.T("create a new API"), |
| SilenceUsage: true, |
| SilenceErrors: true, |
| PreRunE: SetupClientConfig, |
| RunE: func(cmd *cobra.Command, args []string) error { |
| var api *whisk.Api |
| var err error |
| var qname = new(QualifiedName) |
| var action *whisk.Action |
| var webactionSecret interface{} |
| |
| if len(args) == 0 && Flags.api.configfile == "" { |
| whisk.Debug(whisk.DbgError, "No swagger file and no arguments\n") |
| errMsg := wski18n.T("Invalid argument(s). Specify a swagger file or specify an API base path with an API path, an API verb, and an action name.") |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return whiskErr |
| } else if len(args) == 0 && Flags.api.configfile != "" { |
| api, err = parseSwaggerApi(Flags.api.configfile, Client.Config.Namespace) |
| if err != nil { |
| whisk.Debug(whisk.DbgError, "parseSwaggerApi() error: %s\n", err) |
| errMsg := wski18n.T("Unable to parse swagger file: {{.err}}", map[string]interface{}{"err": err}) |
| whiskErr := whisk.MakeWskErrorFromWskError(errors.New(errMsg), err, whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return whiskErr |
| } |
| } else { |
| if whiskErr := CheckArgs(args, 3, 4, "Api create", |
| wski18n.T("Specify a swagger file or specify an API base path with an API path, an API verb, and an action name.")); whiskErr != nil { |
| return whiskErr |
| } |
| api, qname, err = parseApi(cmd, args) |
| if err != nil { |
| whisk.Debug(whisk.DbgError, "parseApi(%s, %s) error: %s\n", cmd, args, err) |
| errMsg := wski18n.T("Unable to parse api command arguments: {{.err}}", |
| map[string]interface{}{"err": err}) |
| whiskErr := whisk.MakeWskErrorFromWskError(errors.New(errMsg), err, whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return whiskErr |
| } |
| |
| // Confirm that the specified action is a web-action |
| action, err = isWebAction(Client, *qname) |
| if err != nil { |
| whisk.Debug(whisk.DbgError, "isWebAction(%v) is false: %s\n", qname, err) |
| whiskErr := whisk.MakeWskError(err, whisk.EXIT_CODE_ERR_GENERAL, whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return whiskErr |
| } |
| |
| if webactionSecret = action.Annotations.GetValue(WEB_SECURE_ANNOT); webactionSecret != nil { |
| whisk.Debug(whisk.DbgInfo, "web action is secured\n") |
| } |
| } |
| |
| apiCreateReq := new(whisk.ApiCreateRequest) |
| apiCreateReq.ApiDoc = api |
| |
| apiCreateReqOptions := new(whisk.ApiCreateRequestOptions) |
| if apiCreateReqOptions.SpaceGuid, err = getUserContextId(); err != nil { |
| return err |
| } |
| if apiCreateReqOptions.AccessToken, err = getAccessToken(); err != nil { |
| return err |
| } |
| apiCreateReqOptions.ResponseType = Flags.api.resptype |
| |
| if webactionSecret != nil { |
| apiCreateReq.ApiDoc.Action.SecureKey = webactionSecret |
| } |
| |
| whisk.Debug(whisk.DbgInfo, "AccessToken: %s\nSpaceGuid: %s\nResponseType: %s", |
| apiCreateReqOptions.AccessToken, apiCreateReqOptions.SpaceGuid, apiCreateReqOptions.ResponseType) |
| |
| retApi, _, err := Client.Apis.Insert(apiCreateReq, apiCreateReqOptions, whisk.DoNotOverwrite) |
| if err != nil { |
| whisk.Debug(whisk.DbgError, "Client.Apis.Insert(%#v, false) error: %s\n", api, err) |
| errMsg := wski18n.T("Unable to create API: {{.err}}", map[string]interface{}{"err": err}) |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE) |
| return whiskErr |
| } |
| |
| if api.Swagger == "" { |
| baseUrl := retApi.BaseUrl |
| fmt.Fprintf(color.Output, |
| wski18n.T("{{.ok}} created API {{.path}} {{.verb}} for action {{.name}}\n{{.fullpath}}\n", |
| map[string]interface{}{ |
| "ok": color.GreenString("ok:"), |
| "path": strings.TrimSuffix(api.GatewayBasePath, "/") + api.GatewayRelPath, |
| "verb": api.GatewayMethod, |
| "name": boldString("/" + api.Action.Namespace + "/" + api.Action.Name), |
| "fullpath": strings.TrimSuffix(baseUrl, "/") + api.GatewayRelPath, |
| })) |
| } else { |
| whisk.Debug(whisk.DbgInfo, "Processing swagger based create API response\n") |
| baseUrl := retApi.BaseUrl |
| for path := range retApi.Swagger.Paths { |
| managedUrl := strings.TrimSuffix(baseUrl, "/") + path |
| whisk.Debug(whisk.DbgInfo, "Managed path: '%s'\n", managedUrl) |
| for op, opv := range retApi.Swagger.Paths[path].MakeOperationMap() { |
| whisk.Debug(whisk.DbgInfo, "Path operation: '%s'\n", op) |
| var fqActionName string |
| if opv.XOpenWhisk == nil { |
| fqActionName = "" |
| } else if len(opv.XOpenWhisk.Package) > 0 { |
| fqActionName = "/" + opv.XOpenWhisk.Namespace + "/" + opv.XOpenWhisk.Package + "/" + opv.XOpenWhisk.ActionName |
| } else { |
| fqActionName = "/" + opv.XOpenWhisk.Namespace + "/" + opv.XOpenWhisk.ActionName |
| } |
| |
| whisk.Debug(whisk.DbgInfo, "baseUrl '%s' Path '%s' Path obj %+v\n", baseUrl, path, opv) |
| if len(fqActionName) > 0 { |
| fmt.Fprintf(color.Output, |
| wski18n.T("{{.ok}} created API {{.path}} {{.verb}} for action {{.name}}\n{{.fullpath}}\n", |
| map[string]interface{}{ |
| "ok": color.GreenString("ok:"), |
| "path": strings.TrimSuffix(retApi.Swagger.BasePath, "/") + path, |
| "verb": op, |
| "name": boldString(fqActionName), |
| "fullpath": managedUrl, |
| })) |
| } else { |
| fmt.Fprintf(color.Output, |
| wski18n.T("{{.ok}} created API {{.path}} {{.verb}}\n{{.fullpath}}\n", |
| map[string]interface{}{ |
| "ok": color.GreenString("ok:"), |
| "path": strings.TrimSuffix(retApi.Swagger.BasePath, "/") + path, |
| "verb": op, |
| "fullpath": managedUrl, |
| })) |
| } |
| } |
| } |
| } |
| |
| return nil |
| }, |
| } |
| |
| var apiGetCmd = &cobra.Command{ |
| Use: "get BASE_PATH | API_NAME", |
| Short: wski18n.T("get API details"), |
| SilenceUsage: true, |
| SilenceErrors: true, |
| PreRunE: SetupClientConfig, |
| RunE: func(cmd *cobra.Command, args []string) error { |
| var err error |
| var isBasePathArg bool = true |
| |
| if whiskErr := CheckArgs(args, 1, 1, "Api get", |
| wski18n.T("An API base path or API name is required.")); whiskErr != nil { |
| return whiskErr |
| } |
| |
| if cmd.LocalFlags().Changed("format") && |
| strings.ToLower(Flags.common.format) != formatOptionYaml && |
| strings.ToLower(Flags.common.format) != formatOptionJson { |
| errMsg := wski18n.T("Invalid format type: {{.type}}", map[string]interface{}{"type": Flags.common.format}) |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE) |
| return whiskErr |
| } |
| |
| apiGetReq := new(whisk.ApiGetRequest) |
| apiGetReqOptions := new(whisk.ApiGetRequestOptions) |
| apiGetReqOptions.ApiBasePath = args[0] |
| if apiGetReqOptions.SpaceGuid, err = getUserContextId(); err != nil { |
| return err |
| } |
| if apiGetReqOptions.AccessToken, err = getAccessToken(); err != nil { |
| return err |
| } |
| |
| retApi, _, err := Client.Apis.Get(apiGetReq, apiGetReqOptions) |
| if err != nil { |
| whisk.Debug(whisk.DbgError, "Client.Apis.Get(%#v, %#v) error: %s\n", apiGetReq, apiGetReqOptions, err) |
| errMsg := wski18n.T("Unable to get API '{{.name}}': {{.err}}", map[string]interface{}{"name": args[0], "err": err}) |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE) |
| return whiskErr |
| } |
| whisk.Debug(whisk.DbgInfo, "Client.Apis.Get returned: %#v\n", retApi) |
| |
| var displayResult interface{} = nil |
| if Flags.common.detail { |
| if retApi.Apis != nil && len(retApi.Apis) > 0 && |
| retApi.Apis[0].ApiValue != nil { |
| displayResult = retApi.Apis[0].ApiValue |
| } else { |
| whisk.Debug(whisk.DbgError, "No result object returned\n") |
| } |
| } else { |
| if retApi.Apis != nil && len(retApi.Apis) > 0 && |
| retApi.Apis[0].ApiValue != nil && |
| retApi.Apis[0].ApiValue.Swagger != nil { |
| displayResult = retApi.Apis[0].ApiValue.Swagger |
| } else { |
| whisk.Debug(whisk.DbgError, "No swagger returned\n") |
| } |
| } |
| if displayResult == nil { |
| var errMsg string |
| if isBasePathArg { |
| errMsg = wski18n.T("API does not exist for basepath {{.basepath}}", |
| map[string]interface{}{"basepath": args[0]}) |
| } else { |
| errMsg = wski18n.T("API does not exist for API name {{.apiname}}", |
| map[string]interface{}{"apiname": args[0]}) |
| } |
| |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE) |
| return whiskErr |
| } |
| |
| if cmd.LocalFlags().Changed("format") && strings.ToLower(Flags.common.format) == formatOptionYaml { |
| var jsonOutputBuffer bytes.Buffer |
| var jsonOutputWriter = bufio.NewWriter(&jsonOutputBuffer) |
| printJSON(displayResult, jsonOutputWriter) |
| jsonOutputWriter.Flush() |
| yamlbytes, err := yaml.JSONToYAML(jsonOutputBuffer.Bytes()) |
| if err != nil { |
| whisk.Debug(whisk.DbgError, "yaml.JSONToYAML() error: %s\n", err) |
| errMsg := wski18n.T("Unable to convert API into YAML: {{.err}}", map[string]interface{}{"err": err}) |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE) |
| return whiskErr |
| } |
| fmt.Println(string(yamlbytes)) |
| } else { |
| printJSON(displayResult) |
| } |
| |
| return nil |
| }, |
| } |
| |
| var apiDeleteCmd = &cobra.Command{ |
| Use: "delete BASE_PATH | API_NAME [API_PATH [API_VERB]]", |
| Short: wski18n.T("delete an API"), |
| SilenceUsage: true, |
| SilenceErrors: true, |
| PreRunE: SetupClientConfig, |
| RunE: func(cmd *cobra.Command, args []string) error { |
| var err error |
| |
| if whiskErr := CheckArgs(args, 1, 3, "Api delete", |
| wski18n.T("An API base path or API name is required. An optional API relative path and operation may also be provided.")); whiskErr != nil { |
| return whiskErr |
| } |
| |
| apiDeleteReq := new(whisk.ApiDeleteRequest) |
| apiDeleteReqOptions := new(whisk.ApiDeleteRequestOptions) |
| if apiDeleteReqOptions.SpaceGuid, err = getUserContextId(); err != nil { |
| return err |
| } |
| if apiDeleteReqOptions.AccessToken, err = getAccessToken(); err != nil { |
| return err |
| } |
| |
| // Is the argument a basepath (must start with /) or an API name |
| if _, ok := isValidBasepath(args[0]); !ok { |
| whisk.Debug(whisk.DbgInfo, "Treating '%s' as an API name; as it does not begin with '/'\n", args[0]) |
| apiDeleteReqOptions.ApiBasePath = args[0] |
| } else { |
| apiDeleteReqOptions.ApiBasePath = args[0] |
| } |
| |
| if len(args) > 1 { |
| // Is the API path valid? |
| if whiskErr, ok := isValidRelpath(args[1]); !ok { |
| return whiskErr |
| } |
| apiDeleteReqOptions.ApiRelPath = args[1] |
| } |
| if len(args) > 2 { |
| // Is the API verb valid? |
| if whiskErr, ok := IsValidApiVerb(args[2]); !ok { |
| return whiskErr |
| } |
| apiDeleteReqOptions.ApiVerb = strings.ToUpper(args[2]) |
| } |
| |
| _, err = Client.Apis.Delete(apiDeleteReq, apiDeleteReqOptions) |
| if err != nil { |
| whisk.Debug(whisk.DbgError, "Client.Apis.Delete(%#v, %#v) error: %s\n", apiDeleteReq, apiDeleteReqOptions, err) |
| errMsg := wski18n.T("Unable to delete API: {{.err}}", map[string]interface{}{"err": err}) |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE) |
| return whiskErr |
| } |
| |
| if len(args) == 1 { |
| fmt.Fprintf(color.Output, |
| wski18n.T("{{.ok}} deleted API {{.basepath}}\n", |
| map[string]interface{}{ |
| "ok": color.GreenString("ok:"), |
| "basepath": apiDeleteReqOptions.ApiBasePath, |
| })) |
| } else if len(args) == 2 { |
| fmt.Fprintf(color.Output, |
| wski18n.T("{{.ok}} deleted {{.path}} from {{.basepath}}\n", |
| map[string]interface{}{ |
| "ok": color.GreenString("ok:"), |
| "path": apiDeleteReqOptions.ApiRelPath, |
| "basepath": apiDeleteReqOptions.ApiBasePath, |
| })) |
| } else { |
| fmt.Fprintf(color.Output, |
| wski18n.T("{{.ok}} deleted {{.path}} {{.verb}} from {{.basepath}}\n", |
| map[string]interface{}{ |
| "ok": color.GreenString("ok:"), |
| "path": apiDeleteReqOptions.ApiRelPath, |
| "verb": apiDeleteReqOptions.ApiVerb, |
| "basepath": apiDeleteReqOptions.ApiBasePath, |
| })) |
| } |
| |
| return nil |
| }, |
| } |
| |
| var apiListCmd = &cobra.Command{ |
| Use: "list [[BASE_PATH | API_NAME] [API_PATH [API_VERB]]", |
| Short: wski18n.T("list APIs"), |
| SilenceUsage: true, |
| SilenceErrors: true, |
| PreRunE: SetupClientConfig, |
| RunE: func(cmd *cobra.Command, args []string) error { |
| var err error |
| var retApiList *whisk.ApiListResponse |
| var retApi *whisk.ApiGetResponse |
| var retApiArray *whisk.RetApiArray |
| var apiPath string |
| var apiVerb string |
| var orderFilteredList []whisk.ApiFilteredList |
| var orderFilteredRow []whisk.ApiFilteredRow |
| |
| if whiskErr := CheckArgs(args, 0, 3, "Api list", |
| wski18n.T("Optional parameters are: API base path (or API name), API relative path and operation.")); whiskErr != nil { |
| return whiskErr |
| } |
| |
| if len(args) == 0 { |
| // List API request query parameters |
| apiListReqOptions := new(whisk.ApiListRequestOptions) |
| apiListReqOptions.Limit = Flags.common.limit |
| apiListReqOptions.Skip = Flags.common.skip |
| if apiListReqOptions.SpaceGuid, err = getUserContextId(); err != nil { |
| return err |
| } |
| if apiListReqOptions.AccessToken, err = getAccessToken(); err != nil { |
| return err |
| } |
| |
| retApiList, _, err = Client.Apis.List(apiListReqOptions) |
| if err != nil { |
| whisk.Debug(whisk.DbgError, "Client.Apis.List(%#v) error: %s\n", apiListReqOptions, err) |
| errMsg := wski18n.T("Unable to obtain the API list: {{.err}}", map[string]interface{}{"err": err}) |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE) |
| return whiskErr |
| } |
| whisk.Debug(whisk.DbgInfo, "Client.Apis.List returned: %#v (%+v)\n", retApiList, retApiList) |
| // Cast to a common type to allow for code to print out apilist response or apiget response |
| retApiArray = (*whisk.RetApiArray)(retApiList) |
| } else { |
| // Get API request body |
| apiGetReq := new(whisk.ApiGetRequest) |
| apiGetReq.Namespace = Client.Config.Namespace |
| // Get API request options |
| apiGetReqOptions := new(whisk.ApiGetRequestOptions) |
| if apiGetReqOptions.SpaceGuid, err = getUserContextId(); err != nil { |
| return err |
| } |
| if apiGetReqOptions.AccessToken, err = getAccessToken(); err != nil { |
| return err |
| } |
| |
| // The first argument is either a basepath (must start with /) or an API name |
| apiGetReqOptions.ApiBasePath = args[0] |
| if len(args) > 1 { |
| // Is the API path valid? |
| if whiskErr, ok := isValidRelpath(args[1]); !ok { |
| return whiskErr |
| } |
| apiPath = args[1] |
| apiGetReqOptions.ApiRelPath = apiPath |
| } |
| if len(args) > 2 { |
| // Is the API verb valid? |
| if whiskErr, ok := IsValidApiVerb(args[2]); !ok { |
| return whiskErr |
| } |
| apiVerb = strings.ToUpper(args[2]) |
| apiGetReqOptions.ApiVerb = apiVerb |
| } |
| |
| retApi, _, err = Client.Apis.Get(apiGetReq, apiGetReqOptions) |
| if err != nil { |
| whisk.Debug(whisk.DbgError, "Client.Apis.Get(%#v, %#v) error: %s\n", apiGetReq, apiGetReqOptions, err) |
| errMsg := wski18n.T("Unable to obtain the API list: {{.err}}", map[string]interface{}{"err": err}) |
| whiskErr := whisk.MakeWskErrorFromWskError(errors.New(errMsg), err, whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE) |
| return whiskErr |
| } |
| whisk.Debug(whisk.DbgInfo, "Client.Apis.Get returned: %#v\n", retApi) |
| // Cast to a common type to allow for code to print out apilist response or apiget response |
| retApiArray = (*whisk.RetApiArray)(retApi) |
| } |
| //Checks for any order flags being passed |
| sortByName := Flags.common.nameSort |
| // Display the APIs - applying any specified filtering |
| if Flags.common.full { |
| fmt.Fprintf(color.Output, |
| wski18n.T("{{.ok}} APIs\n", |
| map[string]interface{}{ |
| "ok": color.GreenString("ok:"), |
| })) |
| for i := 0; i < len(retApiArray.Apis); i++ { |
| orderFilteredList = append(orderFilteredList, genFilteredList(retApiArray.Apis[i].ApiValue, apiPath, apiVerb)...) |
| } |
| printList(orderFilteredList, sortByName) // Sends an array of structs that contains specified variables that are not truncated |
| } else { |
| if len(retApiArray.Apis) > 0 { |
| // Dynamically create the output format string based on the maximum size of the |
| // fully qualified action name and the API Name. |
| maxActionNameSize := min(40, max(len("Action"), getLargestActionNameSize(retApiArray, apiPath, apiVerb))) |
| maxApiNameSize := min(30, max(len("API Name"), getLargestApiNameSize(retApiArray, apiPath, apiVerb))) |
| fmtString = "%-" + strconv.Itoa(maxActionNameSize) + "s %7s %" + strconv.Itoa(maxApiNameSize+1) + "s %s\n" |
| fmt.Fprintf(color.Output, |
| wski18n.T("{{.ok}} APIs\n", |
| map[string]interface{}{ |
| "ok": color.GreenString("ok:"), |
| })) |
| for i := 0; i < len(retApiArray.Apis); i++ { |
| orderFilteredRow = append(orderFilteredRow, genFilteredRow(retApiArray.Apis[i].ApiValue, apiPath, apiVerb, maxActionNameSize, maxApiNameSize)...) |
| } |
| printList(orderFilteredRow, sortByName) // Sends an array of structs that contains specified variables that are truncated |
| } else { |
| fmt.Fprintf(color.Output, |
| wski18n.T("{{.ok}} APIs\n", |
| map[string]interface{}{ |
| "ok": color.GreenString("ok:"), |
| })) |
| printList(orderFilteredRow, sortByName) // Sends empty orderFilteredRow so that defaultHeader can be printed |
| } |
| } |
| |
| return nil |
| }, |
| } |
| |
| // genFilteredList(resultApi, api) generates an array of |
| // ApiFilteredLists for the purpose of ordering and printing in a list form. |
| // NOTE: genFilteredRow() generates entries with one line per configuration |
| // property (action name, verb, api name, api gw url) |
| func genFilteredList(resultApi *whisk.RetApi, apiPath string, apiVerb string) []whisk.ApiFilteredList { |
| var orderInfo whisk.ApiFilteredList |
| var orderInfoArr []whisk.ApiFilteredList |
| baseUrl := strings.TrimSuffix(resultApi.BaseUrl, "/") |
| apiName := resultApi.Swagger.Info.Title |
| basePath := resultApi.Swagger.BasePath |
| if resultApi.Swagger != nil && resultApi.Swagger.Paths != nil { |
| for path := range resultApi.Swagger.Paths { |
| whisk.Debug(whisk.DbgInfo, "genFilteredApi: comparing api relpath: '%s'\n", path) |
| if len(apiPath) == 0 || path == apiPath { |
| whisk.Debug(whisk.DbgInfo, "genFilteredList: relpath matches\n") |
| for op, opv := range resultApi.Swagger.Paths[path].MakeOperationMap() { |
| whisk.Debug(whisk.DbgInfo, "genFilteredList: comparing operation: '%s'\n", op) |
| if len(apiVerb) == 0 || strings.ToLower(op) == strings.ToLower(apiVerb) { |
| whisk.Debug(whisk.DbgInfo, "genFilteredList: operation matches: %#v\n", opv) |
| var actionName string |
| if opv.XOpenWhisk == nil { |
| actionName = "" |
| } else if len(opv.XOpenWhisk.Package) > 0 { |
| actionName = "/" + opv.XOpenWhisk.Namespace + "/" + opv.XOpenWhisk.Package + "/" + opv.XOpenWhisk.ActionName |
| } else { |
| actionName = "/" + opv.XOpenWhisk.Namespace + "/" + opv.XOpenWhisk.ActionName |
| } |
| orderInfo = AssignListInfo(actionName, op, apiName, basePath, path, baseUrl+path) |
| whisk.Debug(whisk.DbgInfo, "Appening to orderInfoArr: %s %s\n", orderInfo.RelPath) |
| orderInfoArr = append(orderInfoArr, orderInfo) |
| } |
| } |
| } |
| } |
| } |
| return orderInfoArr |
| } |
| |
| // genFilteredRow(resultApi, api, maxApiNameSize, maxApiNameSize) generates an array of |
| // ApiFilteredRows for the purpose of ordering and printing in a list form by parsing and |
| // initializing vaules for each individual ApiFilteredRow struct. |
| // NOTE: Large action and api name values will be truncated by their associated max size parameters. |
| func genFilteredRow(resultApi *whisk.RetApi, apiPath string, apiVerb string, maxActionNameSize int, maxApiNameSize int) []whisk.ApiFilteredRow { |
| var orderInfo whisk.ApiFilteredRow |
| var orderInfoArr []whisk.ApiFilteredRow |
| baseUrl := strings.TrimSuffix(resultApi.BaseUrl, "/") |
| apiName := resultApi.Swagger.Info.Title |
| basePath := resultApi.Swagger.BasePath |
| if resultApi.Swagger != nil && resultApi.Swagger.Paths != nil { |
| for path := range resultApi.Swagger.Paths { |
| whisk.Debug(whisk.DbgInfo, "genFilteredRow: comparing api relpath: '%s'\n", path) |
| if len(apiPath) == 0 || path == apiPath { |
| whisk.Debug(whisk.DbgInfo, "genFilteredRow: relpath matches\n") |
| for op, opv := range resultApi.Swagger.Paths[path].MakeOperationMap() { |
| whisk.Debug(whisk.DbgInfo, "genFilteredRow: comparing operation: '%s'\n", op) |
| if len(apiVerb) == 0 || strings.ToLower(op) == strings.ToLower(apiVerb) { |
| whisk.Debug(whisk.DbgInfo, "genFilteredRow: operation matches: %#v\n", opv) |
| var actionName string |
| if opv.XOpenWhisk == nil { |
| actionName = "" |
| } else if len(opv.XOpenWhisk.Package) > 0 { |
| actionName = "/" + opv.XOpenWhisk.Namespace + "/" + opv.XOpenWhisk.Package + "/" + opv.XOpenWhisk.ActionName |
| } else { |
| actionName = "/" + opv.XOpenWhisk.Namespace + "/" + opv.XOpenWhisk.ActionName |
| } |
| orderInfo = AssignRowInfo(actionName[0:min(len(actionName), maxActionNameSize)], op, apiName[0:min(len(apiName), maxApiNameSize)], basePath, path, baseUrl+path) |
| orderInfo.FmtString = fmtString |
| whisk.Debug(whisk.DbgInfo, "Appening to orderInfoArr: %s %s\n", orderInfo.RelPath) |
| orderInfoArr = append(orderInfoArr, orderInfo) |
| } |
| } |
| } |
| } |
| } |
| return orderInfoArr |
| } |
| |
| // AssignRowInfo(actionName, verb, apiName, basePath, relPath, url) assigns |
| // the given vaules to and initializes an ApiFilteredRow struct, then returns it. |
| func AssignRowInfo(actionName string, verb string, apiName string, basePath string, relPath string, url string) whisk.ApiFilteredRow { |
| var orderInfo whisk.ApiFilteredRow |
| |
| orderInfo.ActionName = actionName |
| orderInfo.Verb = verb |
| orderInfo.ApiName = apiName |
| orderInfo.BasePath = basePath |
| orderInfo.RelPath = relPath |
| orderInfo.Url = url |
| |
| return orderInfo |
| } |
| |
| // AssignListInfo(actionName, verb, apiName, basePath, relPath, url) assigns |
| // the given vaules to and initializes an ApiFilteredList struct, then returns it. |
| func AssignListInfo(actionName string, verb string, apiName string, basePath string, relPath string, url string) whisk.ApiFilteredList { |
| var orderInfo whisk.ApiFilteredList |
| |
| orderInfo.ActionName = actionName |
| orderInfo.Verb = verb |
| orderInfo.ApiName = apiName |
| orderInfo.BasePath = basePath |
| orderInfo.RelPath = relPath |
| orderInfo.Url = url |
| |
| return orderInfo |
| } |
| |
| func getLargestActionNameSize(retApiArray *whisk.RetApiArray, apiPath string, apiVerb string) int { |
| var maxNameSize = 0 |
| for i := 0; i < len(retApiArray.Apis); i++ { |
| var resultApi = retApiArray.Apis[i].ApiValue |
| if resultApi.Swagger != nil && resultApi.Swagger.Paths != nil { |
| for path := range resultApi.Swagger.Paths { |
| whisk.Debug(whisk.DbgInfo, "getLargestActionNameSize: comparing api relpath: '%s'\n", path) |
| if len(apiPath) == 0 || path == apiPath { |
| whisk.Debug(whisk.DbgInfo, "getLargestActionNameSize: relpath matches\n") |
| for op, opv := range resultApi.Swagger.Paths[path].MakeOperationMap() { |
| whisk.Debug(whisk.DbgInfo, "getLargestActionNameSize: comparing operation: '%s'\n", op) |
| if len(apiVerb) == 0 || strings.ToLower(op) == strings.ToLower(apiVerb) { |
| whisk.Debug(whisk.DbgInfo, "getLargestActionNameSize: operation matches: %#v\n", opv) |
| var fullActionName string |
| if opv.XOpenWhisk == nil { |
| fullActionName = "" |
| } else if len(opv.XOpenWhisk.Package) > 0 { |
| fullActionName = "/" + opv.XOpenWhisk.Namespace + "/" + opv.XOpenWhisk.Package + "/" + opv.XOpenWhisk.ActionName |
| } else { |
| fullActionName = "/" + opv.XOpenWhisk.Namespace + "/" + opv.XOpenWhisk.ActionName |
| } |
| if len(fullActionName) > maxNameSize { |
| maxNameSize = len(fullActionName) |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| return maxNameSize |
| } |
| |
| func getLargestApiNameSize(retApiArray *whisk.RetApiArray, apiPath string, apiVerb string) int { |
| var maxNameSize = 0 |
| for i := 0; i < len(retApiArray.Apis); i++ { |
| var resultApi = retApiArray.Apis[i].ApiValue |
| apiName := resultApi.Swagger.Info.Title |
| if resultApi.Swagger != nil && resultApi.Swagger.Paths != nil { |
| for path := range resultApi.Swagger.Paths { |
| whisk.Debug(whisk.DbgInfo, "getLargestActionNameSize: comparing api relpath: '%s'\n", path) |
| if len(apiPath) == 0 || path == apiPath { |
| whisk.Debug(whisk.DbgInfo, "getLargestActionNameSize: relpath matches\n") |
| for op, opv := range resultApi.Swagger.Paths[path].MakeOperationMap() { |
| whisk.Debug(whisk.DbgInfo, "getLargestActionNameSize: comparing operation: '%s'\n", op) |
| if len(apiVerb) == 0 || strings.ToLower(op) == strings.ToLower(apiVerb) { |
| whisk.Debug(whisk.DbgInfo, "getLargestActionNameSize: operation matches: %#v\n", opv) |
| if len(apiName) > maxNameSize { |
| maxNameSize = len(apiName) |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| return maxNameSize |
| } |
| |
| func generatePathParameters(relativePath string) ([]whisk.ApiParameter, error) { |
| pathParams := []whisk.ApiParameter{} |
| |
| pathParamNames, err := getPathParameterNames(relativePath) |
| if len(pathParamNames) > 0 && err == nil { |
| // Only create unique swagger entries |
| var uniqueParamNames []string |
| for _, name := range pathParamNames { |
| if !contains(uniqueParamNames, name) { |
| uniqueParamNames = append(uniqueParamNames, name) |
| } |
| } |
| for _, uniqueName := range uniqueParamNames { |
| whisk.Debug(whisk.DbgInfo, "Creating api parameter for '%s'\n", uniqueName) |
| param := whisk.ApiParameter{Name: uniqueName, In: "path", Required: true, Type: "string", |
| Description: wski18n.T("Default description for '{{.name}}'", map[string]interface{}{"name": uniqueName})} |
| pathParams = append(pathParams, param) |
| } |
| } |
| |
| return pathParams, err |
| } |
| |
| /* |
| * if # args = 4 |
| * args[0] = API base path |
| * args[0] = API relative path |
| * args[1] = API verb |
| * args[2] = Optional. Action name (may or may not be qualified with namespace and package name) |
| * |
| * if # args = 3 |
| * args[0] = API relative path |
| * args[1] = API verb |
| * args[2] = Optional. Action name (may or may not be qualified with namespace and package name) |
| */ |
| func parseApi(cmd *cobra.Command, args []string) (*whisk.Api, *QualifiedName, error) { |
| var err error |
| var basepath string = "/" |
| var apiname string |
| var basepathArgIsApiName = false |
| |
| api := new(whisk.Api) |
| |
| if len(args) > 3 { |
| // Is the argument a basepath (must start with /) or an API name |
| if _, ok := isValidBasepath(args[0]); !ok { |
| whisk.Debug(whisk.DbgInfo, "Treating '%s' as an API name; as it does not begin with '/'\n", args[0]) |
| basepathArgIsApiName = true |
| } |
| if err, _ := isBasepathParameterized(args[0]); err != nil { |
| return nil, nil, err |
| } |
| basepath = args[0] |
| |
| // Shift the args so the remaining code works with or without the explicit base path arg |
| args = args[1:] |
| } |
| |
| // Is the API path valid? |
| if len(args) > 0 { |
| if whiskErr, ok := isValidRelpath(args[0]); !ok { |
| return nil, nil, whiskErr |
| } |
| api.GatewayRelPath = args[0] // Maintain case as URLs may be case-sensitive |
| } |
| |
| // Attempting to use path parameters, lets validate that they provided them correctly. |
| hasPathParams, err := hasPathParameters(api.GatewayRelPath) |
| if err != nil { |
| return nil, nil, err |
| } |
| // If they provided path Parameters, the response type better be http as its the only one that supports path parameters right now. |
| if hasPathParams && Flags.api.resptype != "http" { |
| errMsg := wski18n.T("A response type of 'http' is required when using path parameters.") |
| whiskErr := whisk.MakeWskErrorFromWskError(errors.New(errMsg), err, whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return nil, nil, whiskErr |
| } |
| |
| // Is the API verb valid? |
| if len(args) > 1 { |
| if whiskErr, ok := IsValidApiVerb(args[1]); !ok { |
| return nil, nil, whiskErr |
| } |
| api.GatewayMethod = strings.ToUpper(args[1]) |
| } |
| |
| // Is the specified action name valid? |
| var qName = new(QualifiedName) |
| if len(args) == 3 { |
| qName, err = NewQualifiedName(args[2]) |
| if err != nil { |
| whisk.Debug(whisk.DbgError, "NewQualifiedName(%s) failed: %s\n", args[2], err) |
| errMsg := wski18n.T("'{{.name}}' is not a valid action name: {{.err}}", |
| map[string]interface{}{"name": args[2], "err": err}) |
| whiskErr := whisk.MakeWskErrorFromWskError(errors.New(errMsg), err, whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return nil, nil, whiskErr |
| } |
| if qName.GetEntityName() == "" { |
| whisk.Debug(whisk.DbgError, "Action name '%s' is invalid\n", args[2]) |
| errMsg := wski18n.T("'{{.name}}' is not a valid action name.", map[string]interface{}{"name": args[2]}) |
| whiskErr := whisk.MakeWskErrorFromWskError(errors.New(errMsg), err, whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return nil, nil, whiskErr |
| } |
| } |
| |
| if len(Flags.api.apiname) > 0 { |
| if basepathArgIsApiName { |
| // Specifying API name as argument AND as a --apiname option value is invalid |
| whisk.Debug(whisk.DbgError, "API is specified as an argument '%s' and as a flag '%s'\n", basepath, Flags.api.apiname) |
| errMsg := wski18n.T("An API name can only be specified once.") |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return nil, nil, whiskErr |
| } |
| apiname = Flags.api.apiname |
| } |
| |
| api.Namespace = Client.Config.Namespace |
| api.Action = new(whisk.ApiAction) |
| var urlActionPackage string |
| if len(qName.GetPackageName()) > 0 { |
| urlActionPackage = qName.GetPackageName() |
| } else { |
| urlActionPackage = "default" |
| } |
| backendUrl := Client.Config.Host + "/api/v1/web/" + qName.GetNamespace() + "/" + urlActionPackage + "/" + qName.GetEntity() + ".http" |
| if !strings.HasPrefix(backendUrl, "http") { |
| backendUrl = "https://" + backendUrl |
| } |
| api.Action.BackendUrl = backendUrl |
| api.Action.BackendMethod = api.GatewayMethod |
| api.Action.Name = qName.GetEntityName() |
| api.Action.Namespace = qName.GetNamespace() |
| api.Action.Auth = Client.Config.AuthToken |
| api.ApiName = apiname |
| api.GatewayBasePath = basepath |
| if !basepathArgIsApiName { |
| api.Id = "API:" + api.Namespace + ":" + api.GatewayBasePath |
| } |
| api.PathParameters, err = generatePathParameters(api.GatewayRelPath) |
| |
| whisk.Debug(whisk.DbgInfo, "Parsed api struct: %#v\n", api) |
| return api, qName, err |
| } |
| |
| func parseSwaggerApi(configfile string, namespace string) (*whisk.Api, error) { |
| // Test is for completeness, but this situation should only arise due to an internal error |
| if len(configfile) == 0 { |
| whisk.Debug(whisk.DbgError, "No swagger file is specified\n") |
| errMsg := wski18n.T("A configuration file was not specified.") |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return nil, whiskErr |
| } |
| |
| swagger, err := ReadFile(configfile) |
| if err != nil { |
| whisk.Debug(whisk.DbgError, "readFile(%s) error: %s\n", configfile, err) |
| errMsg := wski18n.T("Error reading swagger file '{{.name}}': {{.err}}", |
| map[string]interface{}{"name": configfile, "err": err}) |
| whiskErr := whisk.MakeWskErrorFromWskError(errors.New(errMsg), err, whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return nil, whiskErr |
| } |
| |
| // Check if this swagger is in JSON or YAML format |
| isYaml := strings.HasSuffix(configfile, yamlFileExtension) || strings.HasSuffix(configfile, ymlFileExtension) |
| if isYaml { |
| whisk.Debug(whisk.DbgInfo, "Converting YAML formated API configuration into JSON\n") |
| jsonbytes, err := yaml.YAMLToJSON([]byte(swagger)) |
| if err != nil { |
| whisk.Debug(whisk.DbgError, "yaml.YAMLToJSON() error: %s\n", err) |
| errMsg := wski18n.T("Unable to parse YAML configuration file: {{.err}}", map[string]interface{}{"err": err}) |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE) |
| return nil, whiskErr |
| } |
| swagger = string(jsonbytes) |
| } |
| |
| // Parse the JSON into a swagger object |
| swaggerObj := new(whisk.ApiSwagger) |
| err = json.Unmarshal([]byte(swagger), swaggerObj) |
| if err != nil { |
| whisk.Debug(whisk.DbgError, "JSON parse of '%s' error: %s\n", configfile, err) |
| errMsg := wski18n.T("Error parsing swagger file '{{.name}}': {{.err}}", |
| map[string]interface{}{"name": configfile, "err": err}) |
| whiskErr := whisk.MakeWskErrorFromWskError(errors.New(errMsg), err, whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return nil, whiskErr |
| } |
| |
| if swaggerObj.BasePath == "" || swaggerObj.SwaggerName == "" || swaggerObj.Info == nil || swaggerObj.Paths == nil { |
| whisk.Debug(whisk.DbgError, "Swagger file is invalid.\n", configfile, err) |
| errMsg := wski18n.T("Swagger file is invalid (missing basePath, info, paths, or swagger fields)") |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return nil, whiskErr |
| } |
| |
| if _, ok := isValidBasepath(swaggerObj.BasePath); !ok { |
| whisk.Debug(whisk.DbgError, "Swagger file basePath is invalid.\n", configfile, err) |
| errMsg := wski18n.T("Swagger file basePath must start with a leading slash (/)") |
| whiskErr := whisk.MakeWskError(errors.New(errMsg), whisk.EXIT_CODE_ERR_GENERAL, |
| whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) |
| return nil, whiskErr |
| } |
| |
| api := new(whisk.Api) |
| api.Namespace = namespace |
| api.Swagger = swagger |
| |
| return api, nil |
| } |
| |
| func getAccessToken() (string, error) { |
| var token string = "DUMMY TOKEN" |
| var err error |
| |
| // If the api gw access token override has been set, use it instead of the default |
| if len(ApiGwAccessToken) > 0 { |
| token = ApiGwAccessToken |
| whisk.Debug(whisk.DbgInfo, "API GW access token override used\n") |
| } else { |
| props, errprops := ReadProps(Properties.PropsFile) |
| if errprops == nil { |
| if len(props["APIGW_ACCESS_TOKEN"]) > 0 { |
| token = props["APIGW_ACCESS_TOKEN"] |
| } |
| } else { |
| whisk.Debug(whisk.DbgError, "readProps(%s) failed: %s\n", Properties.PropsFile, err) |
| errStr := wski18n.T("Unable to obtain the API Gateway access token from the properties file: {{.err}}", map[string]interface{}{"err": err}) |
| err = whisk.MakeWskError(errors.New(errStr), whisk.EXIT_CODE_ERR_GENERAL, whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE) |
| } |
| } |
| |
| return token, err |
| } |
| |
| func getUserContextId() (string, error) { |
| var guid string |
| var err error |
| |
| // If the context id override has been set, use it instead of the default |
| if len(ContextId) > 0 { |
| guid = ContextId |
| } else { |
| props, errprops := ReadProps(Properties.PropsFile) |
| if errprops == nil { |
| if len(props["AUTH"]) > 0 { |
| guid = strings.Split(props["AUTH"], ":")[0] |
| } else { |
| whisk.Debug(whisk.DbgError, "AUTH property not set in properties file: '%s'\n", Properties.PropsFile) |
| errStr := wski18n.T("Authorization key is not configured (--auth is required)") |
| err = whisk.MakeWskError(errors.New(errStr), whisk.EXIT_CODE_ERR_GENERAL, whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE) |
| } |
| } else { |
| whisk.Debug(whisk.DbgError, "readProps(%s) failed: %s\n", Properties.PropsFile, err) |
| errStr := wski18n.T("Unable to obtain the auth key from the properties file: {{.err}}", map[string]interface{}{"err": err}) |
| err = whisk.MakeWskError(errors.New(errStr), whisk.EXIT_CODE_ERR_GENERAL, whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE) |
| } |
| } |
| |
| return guid, err |
| } |
| |
| /////////// |
| // Flags // |
| /////////// |
| |
| func init() { |
| |
| apiCreateCmd.Flags().StringVarP(&Flags.api.apiname, "apiname", "n", "", wski18n.T("Friendly name of the API; ignored when CFG_FILE is specified (default BASE_PATH)")) |
| apiCreateCmd.Flags().StringVarP(&Flags.api.configfile, "config-file", "c", "", wski18n.T("`CFG_FILE` containing API configuration in swagger JSON format")) |
| apiCreateCmd.Flags().StringVar(&Flags.api.resptype, "response-type", "json", wski18n.T("Set the web action response `TYPE`. Possible values are html, http, json, text, svg")) |
| apiGetCmd.Flags().BoolVarP(&Flags.common.detail, "full", "f", false, wski18n.T("display full API configuration details")) |
| apiGetCmd.Flags().StringVarP(&Flags.common.format, "format", "", formatOptionJson, wski18n.T("Specify the API output `TYPE`, either json or yaml")) |
| apiListCmd.Flags().IntVarP(&Flags.common.skip, "skip", "s", 0, wski18n.T("exclude the first `SKIP` number of actions from the result")) |
| apiListCmd.Flags().IntVarP(&Flags.common.limit, "limit", "l", 30, wski18n.T("only return `LIMIT` number of actions from the collection")) |
| apiListCmd.Flags().BoolVarP(&Flags.common.nameSort, "name-sort", "n", false, wski18n.T("sorts a list alphabetically by order of [BASE_PATH | API_NAME], API_PATH, then API_VERB; only applicable within the limit/skip returned entity block")) |
| apiListCmd.Flags().BoolVarP(&Flags.common.full, "full", "f", false, wski18n.T("display full description of each API")) |
| apiCmd.AddCommand( |
| apiCreateCmd, |
| apiGetCmd, |
| apiDeleteCmd, |
| apiListCmd, |
| ) |
| } |