blob: 07773203d1e9b3d4cb244ed0f36069ba251385ad [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 common
import (
"bytes"
"errors"
"fmt"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"github.com/apache/openwhisk-client-go/whisk"
"github.com/apache/openwhisk-wskdeploy/dependencies"
"github.com/apache/openwhisk-wskdeploy/deployers"
"github.com/apache/openwhisk-wskdeploy/runtimes"
"github.com/apache/openwhisk-wskdeploy/utils"
"github.com/apache/openwhisk-wskdeploy/wskderrors"
"github.com/fatih/color"
"github.com/mattn/go-colorable"
)
const (
cmd = "wskdeploy"
BLUEMIX_APIHOST = "BLUEMIX_APIHOST"
BLUEMIX_NAMESPACE = "BLUEMIX_NAMESPACE"
BLUEMIX_AUTH = "BLUEMIX_AUTH"
)
type Wskdeploy struct {
Path string
Dir string
}
func NewWskdeploy() *Wskdeploy {
return NewWskWithPath(os.Getenv("GOPATH") + "/src/github.com/apache/openwhisk-wskdeploy/")
}
func GetWskpropsFromEnvVars(apiHost string, namespace string, authKey string) *whisk.Wskprops {
return GetWskpropsFromValues(os.Getenv(apiHost), os.Getenv(namespace), os.Getenv(authKey), "v1")
}
func GetWskpropsFromValues(apiHost string, namespace string, authKey string, version string) *whisk.Wskprops {
dep := whisk.Wskprops{
APIHost: apiHost,
AuthKey: authKey,
Namespace: namespace,
AuthAPIGWKey: "",
APIGWSpaceSuid: "",
Apiversion: version,
Key: "",
Cert: "",
Source: "",
}
return &dep
}
func ValidateWskprops(wskprops *whisk.Wskprops) error {
if len(wskprops.APIHost) == 0 {
return errors.New("Missing APIHost for wskprops.")
}
if len(wskprops.Namespace) == 0 {
return errors.New("Missing Namespace for wskprops.")
}
if len(wskprops.AuthKey) == 0 {
return errors.New("Missing AuthKey for wskprops.")
}
return nil
}
func NewWskWithPath(path string) *Wskdeploy {
var dep Wskdeploy
dep.Path = cmd
dep.Dir = path
return &dep
}
func printCommand(cmd *exec.Cmd) {
fmt.Printf("==> Executing: %s\n", strings.Join(cmd.Args, " "))
}
func printError(err string) {
outputStream := colorable.NewColorableStderr()
if len(err) > 0 {
fmt.Fprintf(outputStream, "==> Error: %s.\n", color.RedString(err))
} else {
fmt.Fprintf(outputStream, "==> Error: %s.\n", color.RedString("No error message"))
}
}
func printOutput(outs string) {
if len(outs) > 0 {
fmt.Printf("==> Output: %s.\n", outs)
}
}
func (wskdeploy *Wskdeploy) RunCommand(s ...string) (string, error) {
command := exec.Command(wskdeploy.Path, s...)
command.Dir = wskdeploy.Dir
printCommand(command)
var outb, errb bytes.Buffer
command.Stdout = &outb
command.Stderr = &errb
err := command.Run()
var returnError error = nil
if err != nil {
// Note: (sub-command) is always at Args[0] which is guaranteed to be not empty
returnError = wskderrors.NewCommandError(command.Args[0], errb.String())
}
printOutput(outb.String())
if returnError != nil {
printError(returnError.Error())
}
return outb.String(), returnError
}
func (wskdeploy *Wskdeploy) Deploy(manifestPath string, deploymentPath string) (string, error) {
return wskdeploy.RunCommand("-m", manifestPath, "-d", deploymentPath)
}
func (wskdeploy *Wskdeploy) DeployManifestVerbose(manifestPath string) (string, error) {
return wskdeploy.RunCommand("-m", manifestPath, "-v")
}
func (wskdeploy *Wskdeploy) DeployWithCredentials(manifestPath string, deploymentPath string, wskprops *whisk.Wskprops) (string, error) {
return wskdeploy.RunCommand("-m", manifestPath, "-d", deploymentPath, "--auth", wskprops.AuthKey,
"--namespace", wskprops.Namespace, "--apihost", wskprops.APIHost, "--apiversion", wskprops.Apiversion)
}
func (wskdeploy *Wskdeploy) Undeploy(manifestPath string, deploymentPath string) (string, error) {
return wskdeploy.RunCommand("undeploy", "-m", manifestPath, "-d", deploymentPath)
}
func (wskdeploy *Wskdeploy) UndeployWithCredentials(manifestPath string, deploymentPath string, wskprops *whisk.Wskprops) (string, error) {
return wskdeploy.RunCommand("undeploy", "-m", manifestPath, "-d", deploymentPath, "--auth", wskprops.AuthKey,
"--namespace", wskprops.Namespace, "--apihost", wskprops.APIHost, "--apiversion", wskprops.Apiversion)
}
func (wskdeploy *Wskdeploy) DeployProjectPathOnly(projectPath string) (string, error) {
return wskdeploy.RunCommand("-p", projectPath)
}
func (wskdeploy *Wskdeploy) UndeployProjectPathOnly(projectPath string) (string, error) {
return wskdeploy.RunCommand("undeploy", "-p", projectPath)
}
func (wskdeploy *Wskdeploy) DeployManifestPathOnly(manifestpath string) (string, error) {
return wskdeploy.RunCommand("-m", manifestpath)
}
func (wskdeploy *Wskdeploy) UndeployManifestPathOnly(manifestpath string) (string, error) {
return wskdeploy.RunCommand("undeploy", "-m", manifestpath)
}
func (Wskdeploy *Wskdeploy) ManagedDeploymentOnlyManifest(manifestPath string) (string, error) {
return Wskdeploy.RunCommand("sync", "-m", manifestPath)
}
func (Wskdeploy *Wskdeploy) ManagedDeploymentManifestAndProject(manifestPath string, projectName string) (string, error) {
return Wskdeploy.RunCommand("sync", "-m", manifestPath, "--projectname", projectName)
}
func (Wskdeploy *Wskdeploy) ManagedDeploymentManifestAndProjectWithCredentials(manifestPath string, projectName string, wskprops *whisk.Wskprops) (string, error) {
return Wskdeploy.RunCommand("sync", "-m", manifestPath, "--projectname", projectName, "--auth", wskprops.AuthKey,
"--namespace", wskprops.Namespace, "--apihost", wskprops.APIHost, "--apiversion", wskprops.Apiversion)
}
func (Wskdeploy *Wskdeploy) ManagedDeployment(manifestPath string, deploymentPath string) (string, error) {
return Wskdeploy.RunCommand("sync", "-m", manifestPath, "-d", deploymentPath)
}
func (Wskdeploy *Wskdeploy) HeadlessManagedDeployment(manifestPath string, deploymentPath string, name string) (string, error) {
return Wskdeploy.RunCommand("sync", "-m", manifestPath, "-d", deploymentPath, "--projectname", name)
}
func (wskdeploy *Wskdeploy) ExportProject(projectName string, targetManifestPath string) (string, error) {
return wskdeploy.RunCommand("export", "-m", targetManifestPath, "--projectname", projectName)
}
func (wskdeploy *Wskdeploy) ExportProjectWithCredentials(projectName string, targetManifestPath string, wskprops *whisk.Wskprops) (string, error) {
return wskdeploy.RunCommand("export", "-m", targetManifestPath, "--projectname", projectName, "--auth", wskprops.AuthKey,
"--namespace", wskprops.Namespace, "--apihost", wskprops.APIHost, "--apiversion", wskprops.Apiversion)
}
// This method is only for testing
// This method will mock a construction of deployment plan, creating all the memory objects
// This method CANNOT be used for real deployment!
// Param manifestPath & deploymentPath MUST be the absolute path.
func (wskdeploy *Wskdeploy) GetDeploymentObjects(manifestPath string, deploymentPath string) (*deployers.DeploymentProject, error) {
//create ServiceDeployer and set default values
deployer := deployers.NewServiceDeployer()
deployer.ProjectPath = filepath.Dir(manifestPath)
deployer.ManifestPath = manifestPath
deployer.DeploymentPath = deploymentPath
deployer.DependencyMaster = make(map[string]dependencies.DependencyRecord)
//create client config with namespace, apihost, authkey and etc.
//these values might be mock values because it's only for testing
userHome := utils.GetHomeDirectory()
defaultPath := path.Join(userHome, whisk.DEFAULT_LOCAL_CONFIG)
clientConfig, err := deployers.NewWhiskConfig(defaultPath, deploymentPath, manifestPath)
if err != nil {
return nil, err
}
deployer.ClientConfig = clientConfig
//setSupportedRuntimes(apiHost string)
//only for testing, mock values
op, err := runtimes.ParseOpenWhisk(clientConfig.Host)
if err == nil {
runtimes.SupportedRunTimes = runtimes.ConvertToMap(op)
runtimes.DefaultRunTimes = runtimes.DefaultRuntimes(op)
runtimes.FileExtensionRuntimeKindMap = runtimes.FileExtensionRuntimes(op)
}
//invoke ConstructDeploymentPlan to create the in memory objects for deployment
err = deployer.ConstructDeploymentPlan()
if err != nil {
return nil, err
}
//return the deployment objects
return deployer.Deployment, nil
}