blob: 22e301faec5ae9856b8c922663ceb0a51c67f1e1 [file] [log] [blame]
/*
* 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
}