whisk/wskprops.go (271 lines of code) (raw):

/* * 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 whisk import ( "bufio" "errors" "fmt" "github.com/apache/openwhisk-client-go/wski18n" "io/ioutil" "net/url" "os" "strings" ) const ( OPENWHISK_HOME = "OPENWHISK_HOME" HOMEPATH = "HOME" DEFAULT_LOCAL_CONFIG = ".wskprops" OPENWHISK_PROPERTIES = "whisk.properties" TEST_AUTH_FILE = "testing.auth" OPENWHISK_PRO = "whisk.api.host.proto" OPENWHISK_PORT = "whisk.api.host.port" OPENWHISK_HOST = "whisk.api.host.name" DEFAULT_VERSION = "v1" DEFAULT_NAMESPACE = "_" APIGW_ACCESS_TOKEN = "APIGW_ACCESS_TOKEN" APIGW_TENANT_ID = "APIGW_TENANT_ID" APIHOST = "APIHOST" APIVERSION = "APIVERSION" AUTH = "AUTH" CERT = "CERT" KEY = "KEY" NAMESPACE = "NAMESPACE" DEFAULT_SOURCE = "wsk props" WSKPROP = "wsk props" WHISK_PROPERTY = "whisk.properties" ) type Wskprops struct { APIGWSpaceSuid string APIGWTenantId string APIHost string Apiversion string AuthAPIGWKey string AuthKey string Cert string Key string Namespace string Source string } func GetUrlBase(host string) (*url.URL, error) { urlBase := fmt.Sprintf("%s/api", host) url, err := url.Parse(urlBase) if err != nil || len(url.Scheme) == 0 || len(url.Host) == 0 { urlBase = fmt.Sprintf("https://%s/api", host) url, err = url.Parse(urlBase) } return url, err } func convertWskpropsToConfig(dep *Wskprops) *Config { var config Config config.Host = dep.APIHost if len(config.Host) != 0 { v, err := GetUrlBase(config.Host) if err == nil { config.BaseURL = v } } config.Namespace = dep.Namespace config.Cert = dep.Cert config.Key = dep.Key config.AuthToken = dep.AuthKey config.Version = dep.Apiversion config.Verbose = false config.Debug = false config.Insecure = true return &config } func GetDefaultConfigFromProperties(pi Properties) (*Config, error) { var config *Config dep, e := GetDefaultWskProp(pi) config = convertWskpropsToConfig(dep) return config, e } func GetConfigFromWhiskProperties(pi Properties) (*Config, error) { var config *Config dep, e := GetWskPropFromWhiskProperty(pi) config = convertWskpropsToConfig(dep) return config, e } func GetConfigFromWskprops(pi Properties, path string) (*Config, error) { var config *Config dep, e := GetWskPropFromWskprops(pi, path) config = convertWskpropsToConfig(dep) return config, e } var GetDefaultWskProp = func(pi Properties) (*Wskprops, error) { var dep *Wskprops dep = pi.GetPropsFromWskprops("") error := ValidateWskprops(dep) if error != nil { dep_whisk := pi.GetPropsFromWhiskProperties() error_whisk := ValidateWskprops(dep_whisk) if error_whisk != nil { return dep, error } else { return dep_whisk, error_whisk } } return dep, error } var GetWskPropFromWskprops = func(pi Properties, path string) (*Wskprops, error) { var dep *Wskprops dep = pi.GetPropsFromWskprops(path) error := ValidateWskprops(dep) return dep, error } var GetWskPropFromWhiskProperty = func(pi Properties) (*Wskprops, error) { var dep *Wskprops dep = pi.GetPropsFromWhiskProperties() error := ValidateWskprops(dep) return dep, error } type Properties interface { GetPropsFromWskprops(string) *Wskprops GetPropsFromWhiskProperties() *Wskprops } type PropertiesImp struct { OsPackage OSPackage } func (pi PropertiesImp) GetPropsFromWskprops(path string) *Wskprops { dep := GetDefaultWskprops(WSKPROP) var wskpropsPath string if path != "" { wskpropsPath = path } else { wskpropsPath = pi.OsPackage.Getenv(HOMEPATH, "") + "/" + DEFAULT_LOCAL_CONFIG } results, err := ReadProps(wskpropsPath) if err == nil { dep.APIHost = GetValue(results, APIHOST, dep.APIHost) dep.AuthKey = GetValue(results, AUTH, dep.AuthKey) dep.Namespace = GetValue(results, NAMESPACE, dep.Namespace) dep.AuthAPIGWKey = GetValue(results, APIGW_ACCESS_TOKEN, dep.AuthAPIGWKey) dep.APIGWTenantId = GetValue(results, APIGW_TENANT_ID, dep.APIGWTenantId) if len(dep.AuthKey) > 0 { dep.APIGWSpaceSuid = strings.Split(dep.AuthKey, ":")[0] } dep.Apiversion = GetValue(results, APIVERSION, dep.Apiversion) dep.Key = GetValue(results, KEY, dep.Key) dep.Cert = GetValue(results, CERT, dep.Cert) } return dep } func (pi PropertiesImp) GetPropsFromWhiskProperties() *Wskprops { dep := GetDefaultWskprops(WHISK_PROPERTY) path := pi.OsPackage.Getenv(OPENWHISK_HOME, "") + "/" + OPENWHISK_PROPERTIES results, err := ReadProps(path) if err == nil { // TODO Determine why we have a hardcoed "test.auth" file here, is this only for unit tests? documented? authPath := GetValue(results, TEST_AUTH_FILE, "") b, err := ioutil.ReadFile(authPath) if err == nil { dep.AuthKey = strings.TrimSpace(string(b)) } dep.APIHost = GetValue(results, OPENWHISK_HOST, "") dep.Namespace = DEFAULT_NAMESPACE if len(dep.AuthKey) > 0 { dep.APIGWSpaceSuid = strings.Split(dep.AuthKey, ":")[0] } } return dep } var ValidateWskprops = func(wskprops *Wskprops) error { // There are at least two fields: WHISKAPIURL and AuthKey, mandatory for a valid Wskprops. errStr := "" if len(wskprops.APIHost) == 0 { if wskprops.Source == WHISK_PROPERTY { errStr = wski18n.T("OpenWhisk API host is missing (Please configure WHISK_APIHOST in .wskprops under the system HOME directory.)") } else { errStr = wski18n.T("OpenWhisk API host is missing (Please configure whisk.api.host.proto, whisk.api.host.name and whisk.api.host.port in whisk.properties under the OPENWHISK_HOME directory.)") } return MakeWskError(errors.New(errStr), EXIT_CODE_ERR_GENERAL, DISPLAY_MSG, DISPLAY_USAGE) } else { if len(wskprops.AuthKey) == 0 { if wskprops.Source == WHISK_PROPERTY { errStr = wski18n.T("Authentication key is missing (Please configure AUTH in .wskprops under the system HOME directory.)") } else { errStr = wski18n.T("Authentication key is missing (Please configure testing.auth as the path of the authentication key file in whisk.properties under the OPENWHISK_HOME directory.)") } return MakeWskError(errors.New(errStr), EXIT_CODE_ERR_GENERAL, DISPLAY_MSG, DISPLAY_USAGE) } else { return nil } } } type OSPackage interface { Getenv(key string, defaultValue string) string } type OSPackageImp struct{} func (osPackage OSPackageImp) Getenv(key string, defaultValue string) string { value := os.Getenv(key) if len(value) == 0 { return defaultValue } return value } func GetDefaultConfig() (*Config, error) { pi := PropertiesImp{ OsPackage: OSPackageImp{}, } return GetDefaultConfigFromProperties(pi) } func GetWhiskPropertiesConfig() (*Config, error) { pi := PropertiesImp{ OsPackage: OSPackageImp{}, } return GetConfigFromWhiskProperties(pi) } func GetProperties() Properties { return PropertiesImp{ OsPackage: OSPackageImp{}, } } func GetWskpropsConfig(path string) (*Config, error) { pi := GetProperties() return GetConfigFromWskprops(pi, path) } func GetDefaultWskprops(source string) *Wskprops { if len(source) == 0 { source = DEFAULT_SOURCE } dep := Wskprops{ APIHost: "", AuthKey: "", Namespace: DEFAULT_NAMESPACE, AuthAPIGWKey: "", APIGWTenantId: "", APIGWSpaceSuid: "", Apiversion: DEFAULT_VERSION, Key: "", Cert: "", Source: source, } return &dep } func GetValue(StoredValues map[string]string, key string, defaultvalue string) string { if val, ok := StoredValues[key]; ok { return val } else { return defaultvalue } } func ReadProps(path string) (map[string]string, error) { props := map[string]string{} file, err := os.Open(path) if err != nil { return props, err } defer file.Close() lines := []string{} scanner := bufio.NewScanner(file) for scanner.Scan() { lines = append(lines, scanner.Text()) } props = map[string]string{} for _, line := range lines { kv := strings.Split(line, "=") if len(kv) != 2 { continue } key := strings.TrimSpace(kv[0]) value := strings.TrimSpace(kv[1]) props[key] = value } return props, nil }