This is an automated email from the ASF dual-hosted git repository. mrutkowski pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk-wskdeploy.git
The following commit(s) were added to refs/heads/master by this push: new 32a02ed Multiple Project Management, adding sync command, and undeploy just using Project Name (#816) 32a02ed is described below commit 32a02ed0318dcefe33e866186e81f66e347124a1 Author: Priti Desai <pde...@us.ibm.com> AuthorDate: Tue Mar 27 13:34:33 2018 -0700 Multiple Project Management, adding sync command, and undeploy just using Project Name (#816) * Adding first set of changes to add deps annotations * fixing unit test * adding integration test * updating go client version * adding check ond dependencies under whisk.system * fixing integration test * introducing sync command * creating subroutine for common piece of code * adding preview support for sync * Adding more integration test * adding support for undeploy with projectname (wip) * adding preview on undeploy with project name (wip) * adding preview on triggers * disabling one integration test case * preview actions and packages with undeploy * Sync undeploy with preview * undeploy dependencies * undeploy dependencies if not used by any other project * adding preview undeploy deps * adding sync description in wski18 * fixing preview for rules * adding more comments in project reader * updating alternate command, renaming ma, replacing hardcoded strings --- Godeps/Godeps.json | 4 +- cmd/root.go | 29 +- cmd/sync.go | 42 +++ deployers/manifestreader.go | 16 +- deployers/projectreader.go | 360 +++++++++++++++++++++ deployers/servicedeployer.go | 147 +++++++-- parsers/manifest_parser.go | 20 +- parsers/manifest_parser_test.go | 2 +- tests/src/integration/common/wskdeploy.go | 8 +- .../06-manifest-with-dependency.yaml | 40 +++ .../07-manifest-with-single-dependency.yaml | 29 ++ ...manifest-with-dependencies-on-whisk-system.yaml | 29 ++ .../managed-deployment/managed-deployment_test.go | 48 ++- utils/flags.go | 1 + utils/managedannotations.go | 48 ++- wski18n/i18n_ids.go | 6 + wski18n/i18n_resources.go | 38 +-- wski18n/resources/en_US.all.json | 8 + 18 files changed, 782 insertions(+), 93 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index a7ba4c5..80631ab 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -105,11 +105,11 @@ }, { "ImportPath": "github.com/apache/incubator-openwhisk-client-go/whisk", - "Rev": "717bc3a1638460e069e411e9a8bf0ea5c97f1efa" + "Rev": "1759868a61729708a8ab1a6de1b409d6e2aea00a" }, { "ImportPath": "github.com/apache/incubator-openwhisk-client-go/wski18n", - "Rev": "717bc3a1638460e069e411e9a8bf0ea5c97f1efa" + "Rev": "1759868a61729708a8ab1a6de1b409d6e2aea00a" }, { "ImportPath": "github.com/pelletier/go-buffruneio", diff --git a/cmd/root.go b/cmd/root.go index 0f93674..77b2e03 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -239,6 +239,34 @@ func Undeploy() error { whisk.SetVerbose(utils.Flags.Verbose) whisk.SetDebug(utils.Flags.Trace) + if len(utils.Flags.ProjectName) != 0 { + var deployer = deployers.NewServiceDeployer() + deployer.Preview = utils.Flags.Preview + + clientConfig, error := deployers.NewWhiskConfig(utils.Flags.CfgFile, "", "") + if error != nil { + return error + } + + whiskClient, error := deployers.CreateNewClient(clientConfig) + if error != nil { + return error + } + + deployer.Client = whiskClient + deployer.ClientConfig = clientConfig + + // The auth, apihost and namespace have been chosen, so that we can check the supported runtimes here. + setSupportedRuntimes(clientConfig.Host) + + err := deployer.UnDeployProject() + if err != nil { + return err + } + + return nil + } + project_Path := strings.TrimSpace(utils.Flags.ProjectPath) if len(project_Path) == 0 { project_Path = utils.DEFAULT_PROJECT_PATH @@ -294,7 +322,6 @@ func Undeploy() error { } else { return nil } - } else { errString := wski18n.T(wski18n.ID_ERR_MANIFEST_FILE_NOT_FOUND_X_path_X, map[string]interface{}{wski18n.KEY_PATH: utils.Flags.ManifestPath}) diff --git a/cmd/sync.go b/cmd/sync.go new file mode 100644 index 0000000..4e1279c --- /dev/null +++ b/cmd/sync.go @@ -0,0 +1,42 @@ +/* + * 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 cmd + +import ( + "github.com/apache/incubator-openwhisk-wskdeploy/utils" + "github.com/apache/incubator-openwhisk-wskdeploy/wski18n" + "github.com/spf13/cobra" +) + +// sync represents the mechanism to sync OpenWhisk projects between client and server +var syncCmd = &cobra.Command{ + Use: "sync", + SuggestFor: []string{"update"}, + Short: wski18n.T(wski18n.ID_CMD_DESC_SHORT_SYNC), + Long: wski18n.T(wski18n.ID_CMD_DESC_LONG_SYNC), + RunE: SyncCmdImp, +} + +func SyncCmdImp(cmd *cobra.Command, args []string) error { + utils.Flags.Sync = true + return Deploy() +} + +func init() { + RootCmd.AddCommand(syncCmd) +} diff --git a/deployers/manifestreader.go b/deployers/manifestreader.go index fa54116..c9f0268 100644 --- a/deployers/manifestreader.go +++ b/deployers/manifestreader.go @@ -52,8 +52,8 @@ func (deployer *ManifestReader) ParseManifest() (*parsers.YAML, *parsers.YAMLPar return manifest, manifestParser, nil } -func (reader *ManifestReader) InitPackages(manifestParser *parsers.YAMLParser, manifest *parsers.YAML, ma whisk.KeyValue) error { - packages, err := manifestParser.ComposeAllPackages(manifest, reader.serviceDeployer.ManifestPath, ma) +func (reader *ManifestReader) InitPackages(manifestParser *parsers.YAMLParser, manifest *parsers.YAML, managedAnnotations whisk.KeyValue) error { + packages, err := manifestParser.ComposeAllPackages(manifest, reader.serviceDeployer.ManifestPath, managedAnnotations) if err != nil { return err } @@ -63,32 +63,32 @@ func (reader *ManifestReader) InitPackages(manifestParser *parsers.YAMLParser, m } // Wrapper parser to handle yaml dir -func (deployer *ManifestReader) HandleYaml(sdeployer *ServiceDeployer, manifestParser *parsers.YAMLParser, manifest *parsers.YAML, ma whisk.KeyValue) error { +func (deployer *ManifestReader) HandleYaml(sdeployer *ServiceDeployer, manifestParser *parsers.YAMLParser, manifest *parsers.YAML, managedAnnotations whisk.KeyValue) error { var err error var manifestName = manifest.Filepath - deps, err := manifestParser.ComposeDependenciesFromAllPackages(manifest, deployer.serviceDeployer.ProjectPath, deployer.serviceDeployer.ManifestPath) + deps, err := manifestParser.ComposeDependenciesFromAllPackages(manifest, deployer.serviceDeployer.ProjectPath, deployer.serviceDeployer.ManifestPath, managedAnnotations) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } - actions, err := manifestParser.ComposeActionsFromAllPackages(manifest, deployer.serviceDeployer.ManifestPath, ma) + actions, err := manifestParser.ComposeActionsFromAllPackages(manifest, deployer.serviceDeployer.ManifestPath, managedAnnotations) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } - sequences, err := manifestParser.ComposeSequencesFromAllPackages(deployer.serviceDeployer.ClientConfig.Namespace, manifest, ma) + sequences, err := manifestParser.ComposeSequencesFromAllPackages(deployer.serviceDeployer.ClientConfig.Namespace, manifest, managedAnnotations) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } - triggers, err := manifestParser.ComposeTriggersFromAllPackages(manifest, deployer.serviceDeployer.ManifestPath, ma) + triggers, err := manifestParser.ComposeTriggersFromAllPackages(manifest, deployer.serviceDeployer.ManifestPath, managedAnnotations) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } - rules, err := manifestParser.ComposeRulesFromAllPackages(manifest, ma) + rules, err := manifestParser.ComposeRulesFromAllPackages(manifest, managedAnnotations) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } diff --git a/deployers/projectreader.go b/deployers/projectreader.go new file mode 100644 index 0000000..84ee979 --- /dev/null +++ b/deployers/projectreader.go @@ -0,0 +1,360 @@ +/* + * 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 deployers + +import ( + "net/http" + "strings" + + "github.com/apache/incubator-openwhisk-client-go/whisk" + "github.com/apache/incubator-openwhisk-wskdeploy/parsers" + "github.com/apache/incubator-openwhisk-wskdeploy/utils" + "github.com/apache/incubator-openwhisk-wskdeploy/wski18n" +) + +func (deployer *ServiceDeployer) UnDeployProjectAssets() error { + + // calculate all the project entities such as packages, actions, sequences, + // triggers, and rules based on the project name in "whisk-managed" annotation + deployer.SetProjectAssets(utils.Flags.ProjectName) + // calculate all the dependencies based on the project name + projectDeps, err := deployer.SetProjectDependencies(utils.Flags.ProjectName) + if err != nil { + return err + } + + // show preview of which all OpenWhisk entities will be deployed + if utils.Flags.Preview { + deployer.printDeploymentAssets(deployer.Deployment) + for _, deps := range projectDeps { + deployer.printDeploymentAssets(deps) + } + return nil + } + + // now, undeploy all those project dependencies if not used by + // any other project or packages + for _, deps := range projectDeps { + if err := deployer.unDeployAssets(deps); err != nil { + return err + } + } + + // undeploy all the project entities + return deployer.unDeployAssets(deployer.Deployment) + + return nil +} + +// based on the project name set in "whisk-managed" annotation +// calculate and determine list of packages, actions, sequences, rules and triggers +func (deployer *ServiceDeployer) SetProjectAssets(projectName string) error { + + if err := deployer.SetProjectPackages(projectName); err != nil { + return err + } + + if err := deployer.SetPackageActionsAndSequences(projectName); err != nil { + return err + } + + if err := deployer.SetProjectTriggers(projectName); err != nil { + return err + } + + if err := deployer.SetProjectRules(projectName); err != nil { + return err + } + + if err := deployer.SetProjectApis(projectName); err != nil { + return err + } + + return nil +} + +// check if project name matches with the one in "whisk-managed" annotation +func (deployer *ServiceDeployer) isManagedEntity(a interface{}, projectName string) bool { + if a != nil { + ta := a.(map[string]interface{}) + if ta[utils.OW_PROJECT_NAME] == projectName { + return true + } + } + return false +} + +// get an instance of *whisk.Package for the specified package name +func (deployer *ServiceDeployer) getPackage(packageName string) (*DeploymentPackage, error) { + var err error + var p *whisk.Package + var response *http.Response + err = retry(DEFAULT_ATTEMPTS, DEFAULT_INTERVAL, func() error { + p, response, err = deployer.Client.Packages.Get(packageName) + return err + }) + if err != nil { + return nil, createWhiskClientError(err.(*whisk.WskError), response, parsers.YAML_KEY_PACKAGE, false) + } + newPack := NewDeploymentPackage() + newPack.Package = p + return newPack, nil + +} + +// capture all the packages with "whisk-managed" annotations and matching project name +func (deployer *ServiceDeployer) SetProjectPackages(projectName string) error { + // retrieve a list of all the packages available under the namespace + listOfPackages, _, err := deployer.Client.Packages.List(&whisk.PackageListOptions{}) + if err != nil { + return nil + } + for _, pkg := range listOfPackages { + if deployer.isManagedEntity(pkg.Annotations.GetValue(utils.MANAGED), projectName) { + p, err := deployer.getPackage(pkg.Name) + if err != nil { + return err + } + deployer.Deployment.Packages[pkg.Name] = p + } + } + + return nil +} + +// get a list of actions/sequences of a given package name +func (deployer *ServiceDeployer) getPackageActionsAndSequences(packageName string, projectName string) (map[string]utils.ActionRecord, map[string]utils.ActionRecord, error) { + listOfActions := make(map[string]utils.ActionRecord, 0) + listOfSequences := make(map[string]utils.ActionRecord, 0) + + actions, _, err := deployer.Client.Actions.List(packageName, &whisk.ActionListOptions{}) + if err != nil { + return listOfActions, listOfSequences, err + } + for _, action := range actions { + if deployer.isManagedEntity(action.Annotations.GetValue(utils.MANAGED), projectName) { + var a *whisk.Action + var response *http.Response + err = retry(DEFAULT_ATTEMPTS, DEFAULT_INTERVAL, func() error { + a, response, err = deployer.Client.Actions.Get(packageName+parsers.PATH_SEPARATOR+action.Name, false) + return err + }) + if err != nil { + return listOfActions, listOfSequences, createWhiskClientError(err.(*whisk.WskError), response, parsers.YAML_KEY_ACTION, false) + } + ar := utils.ActionRecord{Action: a, Packagename: packageName} + if a.Exec.Kind == parsers.YAML_KEY_SEQUENCE { + listOfSequences[action.Name] = ar + } else { + listOfActions[action.Name] = ar + } + } + } + return listOfActions, listOfSequences, err +} + +// capture all the actions/sequences with "whisk-managed" annotations and matching project name +func (deployer *ServiceDeployer) SetPackageActionsAndSequences(projectName string) error { + for _, pkg := range deployer.Deployment.Packages { + a, s, err := deployer.getPackageActionsAndSequences(pkg.Package.Name, projectName) + if err != nil { + return err + } + deployer.Deployment.Packages[pkg.Package.Name].Actions = a + deployer.Deployment.Packages[pkg.Package.Name].Sequences = s + } + return nil +} + +// get a list of triggers from a given project name +func (deployer *ServiceDeployer) getProjectTriggers(projectName string) (map[string]*whisk.Trigger, error) { + triggers := make(map[string]*whisk.Trigger, 0) + listOfTriggers, _, err := deployer.Client.Triggers.List(&whisk.TriggerListOptions{}) + if err != nil { + return triggers, nil + } + for _, trigger := range listOfTriggers { + if deployer.isManagedEntity(trigger.Annotations.GetValue(utils.MANAGED), projectName) { + var t *whisk.Trigger + var response *http.Response + err = retry(DEFAULT_ATTEMPTS, DEFAULT_INTERVAL, func() error { + t, response, err = deployer.Client.Triggers.Get(trigger.Name) + return err + }) + if err != nil { + return triggers, createWhiskClientError(err.(*whisk.WskError), response, parsers.YAML_KEY_TRIGGER, false) + } + triggers[trigger.Name] = t + } + } + return triggers, nil +} + +// capture all the triggers with "whisk-managed" annotations and matching project name +func (deployer *ServiceDeployer) SetProjectTriggers(projectName string) error { + t, err := deployer.getProjectTriggers(projectName) + if err != nil { + return err + } + deployer.Deployment.Triggers = t + return nil +} + +// get a list of rules from a given project name +func (deployer *ServiceDeployer) getProjectRules(projectName string) (map[string]*whisk.Rule, error) { + rules := make(map[string]*whisk.Rule, 0) + listOfRules, _, err := deployer.Client.Rules.List(&whisk.RuleListOptions{}) + if err != nil { + return rules, nil + } + for _, rule := range listOfRules { + if deployer.isManagedEntity(rule.Annotations.GetValue(utils.MANAGED), projectName) { + var r *whisk.Rule + var response *http.Response + err = retry(DEFAULT_ATTEMPTS, DEFAULT_INTERVAL, func() error { + r, response, err = deployer.Client.Rules.Get(rule.Name) + return err + }) + if err != nil { + return rules, createWhiskClientError(err.(*whisk.WskError), response, parsers.YAML_KEY_RULE, false) + } + rules[rule.Name] = r + } + } + return rules, nil +} + +// capture all the rules with "whisk-managed" annotations and matching project name +func (deployer *ServiceDeployer) SetProjectRules(projectName string) error { + r, err := deployer.getProjectRules(projectName) + if err != nil { + return err + } + deployer.Deployment.Rules = r + return nil +} + +// "whisk-manged" annotation stores package name with namespace such as +// /<namespace>/<package name> +// parse this kind of structure to determine package name +func (deployer *ServiceDeployer) filterPackageName(name string) string { + s := strings.SplitAfterN(name, "/", 3) + if len(s) == 3 && len(s[2]) != 0 { + return s[2] + } + return "" +} + +// determine if any other package on the server is using the dependent package +func (deployer *ServiceDeployer) isPackageUsedByOtherPackages(projectName string, depPackageName string) bool { + // retrieve a list of packages on the server + listOfPackages, _, err := deployer.Client.Packages.List(&whisk.PackageListOptions{}) + if err != nil { + return false + } + for _, pkg := range listOfPackages { + if a := pkg.Annotations.GetValue(utils.MANAGED); a != nil { + ta := a.(map[string]interface{}) + // compare project names of the given package and other packages from server + // we want to skip comparing packages from the same project + if ta[utils.OW_PROJECT_NAME] != projectName { + d := a.(map[string]interface{})[utils.OW_PROJECT_DEPS] + listOfDeps := d.([]interface{}) + // iterate over a list of dependencies of a package + // to determine whether it has listed the dependent package as its dependency as well + // in such case, we dont want to undeploy dependent package if its used by any other package + for _, dep := range listOfDeps { + name := deployer.filterPackageName(dep.(map[string]interface{})[wski18n.KEY_KEY].(string)) + if name == depPackageName { + return true + } + + } + + } + + } + } + return false +} + +// derive a map of dependent packages using "whisk-managed" annotation +// "whisk-managed" annotation has a list of dependent packages in "projectDeps" +// projectDeps is a list of key value pairs with its own "whisk-managed" annotation +// for a given package, get the list of dependent packages +// for each dependent package, determine whether any other package is using it or not +// if not, collect a list of actions, sequences, triggers, and rules of the dependent package +// and delete them in order following by deleting the package itself +func (deployer *ServiceDeployer) SetProjectDependencies(projectName string) ([]*DeploymentProject, error) { + projectDependencies := make([]*DeploymentProject, 0) + // iterate over each package in a given project + for _, pkg := range deployer.Deployment.Packages { + // get the "whisk-managed" annotation + if a := pkg.Package.Annotations.GetValue(utils.MANAGED); a != nil { + // read the list of dependencies from "projectDeps" + d := a.(map[string]interface{})[utils.OW_PROJECT_DEPS] + listOfDeps := d.([]interface{}) + // iterate over a list of dependencies + for _, dep := range listOfDeps { + // dependent package name is in form of "/<namespace>/<package-name> + // filter it to derive the package name + name := deployer.filterPackageName(dep.(map[string]interface{})[wski18n.KEY_KEY].(string)) + // undeploy dependent package if its not used by any other package + if !deployer.isPackageUsedByOtherPackages(projectName, name) { + // get the *whisk.Package object for the given dependent package + p, err := deployer.getPackage(name) + if err != nil { + return projectDependencies, err + } + // construct a new DeploymentProject for each dependency + depProject := NewDeploymentProject() + depProject.Packages[p.Package.Name] = p + // Now, get the project name of dependent package so that + // we can get other entities from that project + pa := p.Package.Annotations.GetValue(utils.MANAGED) + depProjectName := (pa.(map[string]interface{})[utils.OW_PROJECT_NAME]).(string) + // get a list of actions and sequences of a dependent package + actions, sequences, err := deployer.getPackageActionsAndSequences(p.Package.Name, depProjectName) + if err != nil { + return projectDependencies, err + } + depProject.Packages[p.Package.Name].Actions = actions + depProject.Packages[p.Package.Name].Sequences = sequences + // get a list of triggers of a dependent project + t, err := deployer.getProjectTriggers(depProjectName) + if err != nil { + return projectDependencies, err + } + depProject.Triggers = t + // get a list of rules of a dependent project + r, err := deployer.getProjectRules(depProjectName) + if err != nil { + return projectDependencies, err + } + depProject.Rules = r + projectDependencies = append(projectDependencies, depProject) + } + } + } + } + return projectDependencies, nil +} + +func (deployer *ServiceDeployer) SetProjectApis(projectName string) error { + return nil +} diff --git a/deployers/servicedeployer.go b/deployers/servicedeployer.go index 023e18e..2d417b0 100644 --- a/deployers/servicedeployer.go +++ b/deployers/servicedeployer.go @@ -139,7 +139,7 @@ func (deployer *ServiceDeployer) ConstructDeploymentPlan() error { // Generate Managed Annotations if its marked as a Managed Deployment // Managed deployments are the ones when OpenWhisk entities are deployed with command line flag --managed. // Which results in a hidden annotation in every OpenWhisk entity in manifest file. - if utils.Flags.Managed { + if utils.Flags.Managed || utils.Flags.Sync { // OpenWhisk entities are annotated with Project Name and therefore // Project Name in manifest/deployment file is mandatory for managed deployments if deployer.ProjectName == "" { @@ -309,7 +309,7 @@ func (deployer *ServiceDeployer) deployAssets() error { // refresh previously deployed project entities, delete the assets which is no longer part of the project // i.e. in a subsequent managed deployment of the same project minus few OpenWhisk entities // from the manifest file must result in undeployment of those deleted entities - if utils.Flags.Managed { + if utils.Flags.Managed || utils.Flags.Sync { if err := deployer.RefreshManagedEntities(deployer.ManagedAnnotation); err != nil { errString := wski18n.T(wski18n.ID_MSG_MANAGED_UNDEPLOYMENT_FAILED) whisk.Debug(whisk.DbgError, errString) @@ -436,6 +436,9 @@ func (deployer *ServiceDeployer) RefreshManagedEntities(maValue whisk.KeyValue) return err } + if err := deployer.RefreshManagedPackagesWithDependencies(ma); err != nil { + return err + } return nil } @@ -612,6 +615,74 @@ func (deployer *ServiceDeployer) RefreshManagedPackages(ma map[string]interface{ } } } + + return nil +} + +func (deployer *ServiceDeployer) appendDepAnnotation(list whisk.KeyValueArr, pkg *whisk.Package) whisk.KeyValueArr { + depExists := false + if a := pkg.Annotations.GetValue(utils.MANAGED); a != nil { + //append annotations from this package to deps + pkgName := parsers.PATH_SEPARATOR + pkg.Namespace + parsers.PATH_SEPARATOR + pkg.Name + for _, dep := range list { + if dep.Key == pkgName { + depExists = true + } + } + if !depExists { + list = append(list, whisk.KeyValue{Key: pkgName, Value: a.(map[string]interface{})}) + } + } + return list +} + +func (deployer *ServiceDeployer) RefreshManagedPackagesWithDependencies(ma map[string]interface{}) error { + // iterate over each package from the given project + for _, p := range deployer.Deployment.Packages { + dependencyAnnotations := make(whisk.KeyValueArr, 0) + // iterate over the list of dependencies of the package + // dependencies could be labeled same as dependent package name + // for example, "helloworld" where the package it depends on is also called "helloworld" + // dependencies could be labeled different from the dependent package name + // for example, "custom-helloworld" where the package it depends on it called "helloworld" + for n := range p.Dependencies { + // find the package using dependency label + pkg, _, err := deployer.Client.Packages.Get(n) + if err != nil { + return err + } + // if dependency label (custom-helloworld) is different from the dependent package name, + // it must have binding set to the original package ("helloworld") + if len(pkg.Binding.Name) != 0 { + // having dependency on packages under /whisk.system is treated in a different way + // in which dependent package under /whisk.system are not modified to add managed annotation + // and parent package does not show this dependency in its managed annotation + // because whisk.system packages comes pre-packaged and deployed with OpenWhisk server and not + // deployed along with application deployments. + // (TODO) here, we are only finding a package with its name as Get method + // (TODO) does not support looking under different/seperate namespace + // (TODO) we could add support to sync dependencies from different namespaces in future + if pkg.Binding.Namespace != utils.WHISK_SYSTEM { + // get the original package to retrieve its managed annotations + pkg, _, err := deployer.Client.Packages.Get(pkg.Binding.Name) + if err != nil { + return err + } + dependencyAnnotations = deployer.appendDepAnnotation(dependencyAnnotations, pkg) + } + } else { + dependencyAnnotations = deployer.appendDepAnnotation(dependencyAnnotations, pkg) + } + } + updatedAnnotation, err := utils.AddDependentAnnotation(ma, dependencyAnnotations) + if err != nil { + return err + } + p.Package.Annotations.AddOrReplace(&updatedAnnotation) + } + if err := deployer.DeployPackages(); err != nil { + return err + } return nil } @@ -935,6 +1006,13 @@ func (deployer *ServiceDeployer) UnDeploy(verifiedPlan *DeploymentProject) error return nil } +func (deployer *ServiceDeployer) UnDeployProject() error { + if err := deployer.UnDeployProjectAssets(); err != nil { + return err + } + return nil +} + func (deployer *ServiceDeployer) unDeployAssets(verifiedPlan *DeploymentProject) error { if err := deployer.UnDeployApis(verifiedPlan); err != nil { return err @@ -1355,10 +1433,10 @@ func (deployer *ServiceDeployer) printDeploymentAssets(assets *DeploymentProject wskprint.PrintlnOpenWhiskOutput(" ____ ___ _ _ _ _ _\n /\\ \\ / _ \\ _ __ ___ _ __ | | | | |__ (_)___| | __\n /\\ /__\\ \\ | | | | '_ \\ / _ \\ '_ \\| | | | '_ \\| / __| |/ /\n / \\____ \\ / | |_| | |_) | __/ | | | |/\\| | | | | \\__ \\ <\n \\ \\ / \\/ \\___/| .__/ \\___|_| |_|__/\\__|_| |_|_|___/_|\\_\\ \n \\___\\/ |_|\n") // TODO() review format - wskprint.PrintlnOpenWhiskOutput("Packages:") + wskprint.PrintlnOpenWhiskOutput(strings.Title(parsers.YAML_KEY_PACKAGES) + ":") for _, pack := range assets.Packages { - wskprint.PrintlnOpenWhiskOutput("Name: " + pack.Package.Name) - wskprint.PrintlnOpenWhiskOutput(" bindings: ") + wskprint.PrintlnOpenWhiskOutput(strings.Title(wski18n.KEY_NAME) + ": " + pack.Package.Name) + wskprint.PrintlnOpenWhiskOutput(" " + wski18n.KEY_BINDINGS + ": ") for _, p := range pack.Package.Parameters { jsonValue, err := utils.PrettyJSON(p.Value) if err != nil { @@ -1368,19 +1446,25 @@ func (deployer *ServiceDeployer) printDeploymentAssets(assets *DeploymentProject } } + wskprint.PrintlnOpenWhiskOutput(" " + parsers.YAML_KEY_ANNOTATION + ": ") + for _, p := range pack.Package.Annotations { + fmt.Printf(" - %s : %v\n", p.Key, p.Value) + + } + for key, dep := range pack.Dependencies { - wskprint.PrintlnOpenWhiskOutput(" * dependency: " + key) - wskprint.PrintlnOpenWhiskOutput(" location: " + dep.Location) + wskprint.PrintlnOpenWhiskOutput(" * " + wski18n.KEY_DEPENDENCY + ": " + key) + wskprint.PrintlnOpenWhiskOutput(" " + wski18n.KEY_LOCATION + ": " + dep.Location) if !dep.IsBinding { - wskprint.PrintlnOpenWhiskOutput(" local path: " + dep.ProjectPath) + wskprint.PrintlnOpenWhiskOutput(" " + wski18n.KEY_PATH + ": " + dep.ProjectPath) } } wskprint.PrintlnOpenWhiskOutput("") for _, action := range pack.Actions { - wskprint.PrintlnOpenWhiskOutput(" * action: " + action.Action.Name) - wskprint.PrintlnOpenWhiskOutput(" bindings: ") + wskprint.PrintlnOpenWhiskOutput(" * " + parsers.YAML_KEY_ACTION + ": " + action.Action.Name) + wskprint.PrintlnOpenWhiskOutput(" " + wski18n.KEY_BINDINGS + ": ") for _, p := range action.Action.Parameters { if reflect.TypeOf(p.Value).Kind() == reflect.Map { @@ -1405,7 +1489,7 @@ func (deployer *ServiceDeployer) printDeploymentAssets(assets *DeploymentProject } } - wskprint.PrintlnOpenWhiskOutput(" annotations: ") + wskprint.PrintlnOpenWhiskOutput(" " + parsers.YAML_KEY_ANNOTATION + ": ") for _, p := range action.Action.Annotations { fmt.Printf(" - %s : %v\n", p.Key, p.Value) @@ -1414,16 +1498,21 @@ func (deployer *ServiceDeployer) printDeploymentAssets(assets *DeploymentProject wskprint.PrintlnOpenWhiskOutput("") for _, action := range pack.Sequences { - wskprint.PrintlnOpenWhiskOutput(" * sequence: " + action.Action.Name) + wskprint.PrintlnOpenWhiskOutput(" * " + parsers.YAML_KEY_SEQUENCE + ": " + action.Action.Name) + wskprint.PrintlnOpenWhiskOutput(" " + parsers.YAML_KEY_ANNOTATION + ": ") + for _, p := range action.Action.Annotations { + fmt.Printf(" - %s : %v\n", p.Key, p.Value) + + } } wskprint.PrintlnOpenWhiskOutput("") } - wskprint.PrintlnOpenWhiskOutput("Triggers:") + wskprint.PrintlnOpenWhiskOutput(wski18n.TRIGGERS + ":") for _, trigger := range assets.Triggers { - wskprint.PrintlnOpenWhiskOutput("* trigger: " + trigger.Name) - wskprint.PrintlnOpenWhiskOutput(" bindings: ") + wskprint.PrintlnOpenWhiskOutput("* " + parsers.YAML_KEY_TRIGGER + ": " + trigger.Name) + wskprint.PrintlnOpenWhiskOutput(" " + wski18n.KEY_BINDINGS + ": ") for _, p := range trigger.Parameters { jsonValue, err := utils.PrettyJSON(p.Value) @@ -1434,21 +1523,31 @@ func (deployer *ServiceDeployer) printDeploymentAssets(assets *DeploymentProject } } - wskprint.PrintlnOpenWhiskOutput(" annotations: ") + wskprint.PrintlnOpenWhiskOutput(" " + parsers.YAML_KEY_ANNOTATION + ": ") for _, p := range trigger.Annotations { + fmt.Printf(" - %s : %v\n", p.Key, p.Value) - value := "?" - if str, ok := p.Value.(string); ok { - value = str - } - wskprint.PrintlnOpenWhiskOutput(" - name: " + p.Key + " value: " + value) } } - wskprint.PrintlnOpenWhiskOutput("\n Rules") + wskprint.PrintlnOpenWhiskOutput("\n" + wski18n.RULES) for _, rule := range assets.Rules { - wskprint.PrintlnOpenWhiskOutput("* rule: " + rule.Name) - wskprint.PrintlnOpenWhiskOutput(" - trigger: " + rule.Trigger.(string) + "\n - action: " + rule.Action.(string)) + wskprint.PrintlnOpenWhiskOutput("* " + parsers.YAML_KEY_RULE + ": " + rule.Name) + wskprint.PrintlnOpenWhiskOutput(" " + parsers.YAML_KEY_ANNOTATION + ": ") + for _, p := range rule.Annotations { + fmt.Printf(" - %s : %v\n", p.Key, p.Value) + + } + if reflect.TypeOf(rule.Trigger).Kind() == reflect.String { + wskprint.PrintlnOpenWhiskOutput(" - " + parsers.YAML_KEY_TRIGGER + ": " + rule.Trigger.(string) + "\n - " + parsers.YAML_KEY_ACTION + ": " + rule.Action.(string)) + } else if reflect.TypeOf(rule.Trigger).Kind() == reflect.Map { + trigger := rule.Trigger.(map[string]interface{}) + triggerName := trigger["path"].(string) + parsers.PATH_SEPARATOR + trigger["name"].(string) + action := rule.Action.(map[string]interface{}) + actionName := action["path"].(string) + parsers.PATH_SEPARATOR + action["name"].(string) + wskprint.PrintlnOpenWhiskOutput(" - " + parsers.YAML_KEY_TRIGGER + ": " + triggerName + "\n - " + parsers.YAML_KEY_ACTION + ": " + actionName) + } + } wskprint.PrintlnOpenWhiskOutput("") diff --git a/parsers/manifest_parser.go b/parsers/manifest_parser.go index 763dcbc..88f8d9f 100644 --- a/parsers/manifest_parser.go +++ b/parsers/manifest_parser.go @@ -141,7 +141,7 @@ func (dm *YAMLParser) composeAnnotations(annotations map[string]interface{}) whi return listOfAnnotations } -func (dm *YAMLParser) ComposeDependenciesFromAllPackages(manifest *YAML, projectPath string, filePath string) (map[string]utils.DependencyRecord, error) { +func (dm *YAMLParser) ComposeDependenciesFromAllPackages(manifest *YAML, projectPath string, filePath string, ma whisk.KeyValue) (map[string]utils.DependencyRecord, error) { dependencies := make(map[string]utils.DependencyRecord) packages := make(map[string]Package) @@ -152,7 +152,7 @@ func (dm *YAMLParser) ComposeDependenciesFromAllPackages(manifest *YAML, project } for n, p := range packages { - d, err := dm.ComposeDependencies(p, projectPath, filePath, n) + d, err := dm.ComposeDependencies(p, projectPath, filePath, n, ma) if err == nil { for k, v := range d { dependencies[k] = v @@ -164,7 +164,7 @@ func (dm *YAMLParser) ComposeDependenciesFromAllPackages(manifest *YAML, project return dependencies, nil } -func (dm *YAMLParser) ComposeDependencies(pkg Package, projectPath string, filePath string, packageName string) (map[string]utils.DependencyRecord, error) { +func (dm *YAMLParser) ComposeDependencies(pkg Package, projectPath string, filePath string, packageName string, ma whisk.KeyValue) (map[string]utils.DependencyRecord, error) { depMap := make(map[string]utils.DependencyRecord) for key, dependency := range pkg.Dependencies { @@ -201,6 +201,10 @@ func (dm *YAMLParser) ComposeDependencies(pkg Package, projectPath string, fileP annotations := dm.composeAnnotations(dependency.Annotations) + if utils.Flags.Managed || utils.Flags.Sync { + annotations = append(annotations, ma) + } + packDir := path.Join(projectPath, strings.Title(YAML_KEY_PACKAGES)) depName := packageName + ":" + key depMap[depName] = utils.NewDependencyRecord(packDir, packageName, location, version, inputs, annotations, isBinding) @@ -308,7 +312,7 @@ func (dm *YAMLParser) ComposePackage(pkg Package, packageName string, filePath s } // add Managed Annotations if this is Managed Deployment - if utils.Flags.Managed { + if utils.Flags.Managed || utils.Flags.Sync { pag.Annotations = append(pag.Annotations, ma) } @@ -383,7 +387,7 @@ func (dm *YAMLParser) ComposeSequences(namespace string, sequences map[string]Se } // appending managed annotations if its a managed deployment - if utils.Flags.Managed { + if utils.Flags.Managed || utils.Flags.Sync { wskaction.Annotations = append(wskaction.Annotations, ma) } @@ -756,7 +760,7 @@ func (dm *YAMLParser) ComposeActions(manifestFilePath string, actions map[string } // add managed annotations if its marked as managed deployment - if utils.Flags.Managed { + if utils.Flags.Managed || utils.Flags.Sync { wskaction.Annotations = append(wskaction.Annotations, ma) } @@ -864,7 +868,7 @@ func (dm *YAMLParser) ComposeTriggers(filePath string, pkg Package, ma whisk.Key } // add managed annotations if its a managed deployment - if utils.Flags.Managed { + if utils.Flags.Managed || utils.Flags.Sync { wsktrigger.Annotations = append(wsktrigger.Annotations, ma) } @@ -917,7 +921,7 @@ func (dm *YAMLParser) ComposeRules(pkg Package, packageName string, ma whisk.Key } // add managed annotations if its a managed deployment - if utils.Flags.Managed { + if utils.Flags.Managed || utils.Flags.Sync { wskrule.Annotations = append(wskrule.Annotations, ma) } diff --git a/parsers/manifest_parser_test.go b/parsers/manifest_parser_test.go index bc6948e..f96ebc1 100644 --- a/parsers/manifest_parser_test.go +++ b/parsers/manifest_parser_test.go @@ -1332,7 +1332,7 @@ func TestComposeDependencies(t *testing.T) { file := "../tests/dat/manifest_data_compose_dependencies.yaml" p, m, _ := testLoadParseManifest(t, file) - depdList, err := p.ComposeDependenciesFromAllPackages(m, "/project_folder", m.Filepath) + depdList, err := p.ComposeDependenciesFromAllPackages(m, "/project_folder", m.Filepath, whisk.KeyValue{}) assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_COMPOSE_DEPENDENCY_FAILURE, file)) assert.Equal(t, 3, len(depdList), "Failed to get rules") diff --git a/tests/src/integration/common/wskdeploy.go b/tests/src/integration/common/wskdeploy.go index 2eb18e5..17755a9 100644 --- a/tests/src/integration/common/wskdeploy.go +++ b/tests/src/integration/common/wskdeploy.go @@ -167,15 +167,11 @@ func (wskdeploy *Wskdeploy) UndeployManifestPathOnly(manifestpath string) (strin } func (Wskdeploy *Wskdeploy) ManagedDeployment(manifestPath string, deploymentPath string) (string, error) { - return Wskdeploy.RunCommand("-m", manifestPath, "-d", deploymentPath, "--managed") + return Wskdeploy.RunCommand("sync", "-m", manifestPath, "-d", deploymentPath) } func (Wskdeploy *Wskdeploy) HeadlessManagedDeployment(manifestPath string, deploymentPath string, name string) (string, error) { - return Wskdeploy.RunCommand("-m", manifestPath, "-d", deploymentPath, "--managed", "--projectname", name) -} - -func (Wskdeploy *Wskdeploy) ManagedUndeployment(manifestPath string, deploymentPath string) (string, error) { - return Wskdeploy.RunCommand("undeploy", "-m", manifestPath, "-d", deploymentPath, "--managed") + return Wskdeploy.RunCommand("sync", "-m", manifestPath, "-d", deploymentPath, "--projectname", name) } // This method is only for testing diff --git a/tests/src/integration/managed-deployment/06-manifest-with-dependency.yaml b/tests/src/integration/managed-deployment/06-manifest-with-dependency.yaml new file mode 100644 index 0000000..0cbe848 --- /dev/null +++ b/tests/src/integration/managed-deployment/06-manifest-with-dependency.yaml @@ -0,0 +1,40 @@ +# +# 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. +# + +project: + name: MyManagedProjectWithDependency + packages: + Extension1: + dependencies: + helloworlds: + location: github.com/pritidesai/incubator-openwhisk-test/packages/helloworlds + custom-hellowhisk: + location: github.com/pritidesai/incubator-openwhisk-test/packages/hellowhisk + custom-helloworlds: + location: github.com/pritidesai/incubator-openwhisk-test/packages/helloworlds + sequences: + helloworld-sequence: + actions: custom-helloworlds/hello-js, custom-hellowhisk/greeting, helloworlds/hello-js + triggers: + trigger1: + trigger2: + rules: + rule1: + trigger: trigger1 + action: helloworld-sequence + rule2: + trigger: trigger2 + action: custom-helloworlds/helloworld-js diff --git a/tests/src/integration/managed-deployment/07-manifest-with-single-dependency.yaml b/tests/src/integration/managed-deployment/07-manifest-with-single-dependency.yaml new file mode 100644 index 0000000..903fd0e --- /dev/null +++ b/tests/src/integration/managed-deployment/07-manifest-with-single-dependency.yaml @@ -0,0 +1,29 @@ +# +# 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. +# + +project: + name: MyManagedProjectWithSingleDependency + packages: + Extension2: + dependencies: + helloworlds: + location: github.com/pritidesai/incubator-openwhisk-test/packages/helloworlds + triggers: + triggerInExtension2: + rules: + ruleInExtension2: + trigger: triggerInExtension2 + action: helloworlds/helloworld-js diff --git a/tests/src/integration/managed-deployment/08-manifest-with-dependencies-on-whisk-system.yaml b/tests/src/integration/managed-deployment/08-manifest-with-dependencies-on-whisk-system.yaml new file mode 100644 index 0000000..612feeb --- /dev/null +++ b/tests/src/integration/managed-deployment/08-manifest-with-dependencies-on-whisk-system.yaml @@ -0,0 +1,29 @@ +# +# 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. +# + +project: + name: MyManagedProjectWithWhiskSystemDependency + packages: + Extension3: + dependencies: + whiskUtility: + location: /whisk.system/utils + triggers: + triggerInExtension3: + rules: + ruleInExtension3: + trigger: triggerInExtension3 + action: whiskUtility/sort diff --git a/tests/src/integration/managed-deployment/managed-deployment_test.go b/tests/src/integration/managed-deployment/managed-deployment_test.go index 119296d..475ab71 100644 --- a/tests/src/integration/managed-deployment/managed-deployment_test.go +++ b/tests/src/integration/managed-deployment/managed-deployment_test.go @@ -27,41 +27,61 @@ import ( "github.com/stretchr/testify/assert" ) +const PATH = "/src/github.com/apache/incubator-openwhisk-wskdeploy/tests/src/integration/managed-deployment/" + func TestManagedDeployment(t *testing.T) { - path := "/src/github.com/apache/incubator-openwhisk-wskdeploy/tests/src/integration/managed-deployment/" - manifestPath := os.Getenv("GOPATH") + path + "manifest.yaml" + manifestPath := os.Getenv("GOPATH") + PATH + "manifest.yaml" deploymentPath := "" wskdeploy := common.NewWskdeploy() _, err := wskdeploy.ManagedDeployment(manifestPath, deploymentPath) assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.") - manifestPath = os.Getenv("GOPATH") + path + "00-manifest-minus-second-package.yaml" - wskdeploy = common.NewWskdeploy() + manifestPath = os.Getenv("GOPATH") + PATH + "00-manifest-minus-second-package.yaml" _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath) assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.") - manifestPath = os.Getenv("GOPATH") + path + "01-manifest-minus-sequence-2.yaml" - wskdeploy = common.NewWskdeploy() + manifestPath = os.Getenv("GOPATH") + PATH + "01-manifest-minus-sequence-2.yaml" _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath) assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.") - manifestPath = os.Getenv("GOPATH") + path + "02-manifest-minus-action-3.yaml" - wskdeploy = common.NewWskdeploy() + manifestPath = os.Getenv("GOPATH") + PATH + "02-manifest-minus-action-3.yaml" _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath) assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.") - manifestPath = os.Getenv("GOPATH") + path + "03-manifest-minus-trigger.yaml" - wskdeploy = common.NewWskdeploy() + manifestPath = os.Getenv("GOPATH") + PATH + "03-manifest-minus-trigger.yaml" _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath) assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.") - manifestPath = os.Getenv("GOPATH") + path + "04-manifest-minus-package.yaml" - wskdeploy = common.NewWskdeploy() + manifestPath = os.Getenv("GOPATH") + PATH + "04-manifest-minus-package.yaml" _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath) assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.") - manifestPath = os.Getenv("GOPATH") + path + "05-manifest-headless.yaml" - wskdeploy = common.NewWskdeploy() + manifestPath = os.Getenv("GOPATH") + PATH + "05-manifest-headless.yaml" _, err = wskdeploy.HeadlessManagedDeployment(manifestPath, deploymentPath, "Headless Managed") assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.") + _, err = wskdeploy.Undeploy(manifestPath, deploymentPath) + assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.") + +} + +func TestManagedDeploymentWithDependency(t *testing.T) { + manifestPath := os.Getenv("GOPATH") + PATH + "06-manifest-with-dependency.yaml" + deploymentPath := "" + wskdeploy := common.NewWskdeploy() + _, err := wskdeploy.ManagedDeployment(manifestPath, deploymentPath) + assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.") + _, err = wskdeploy.Undeploy(manifestPath, deploymentPath) + assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.") + + manifestPath = os.Getenv("GOPATH") + PATH + "07-manifest-with-single-dependency.yaml" + _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath) + assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.") + _, err = wskdeploy.Undeploy(manifestPath, deploymentPath) + assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.") + + //manifestPath = os.Getenv("GOPATH") + PATH + "08-manifest-with-dependencies-on-whisk-system.yaml" + //_, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath) + //assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.") + //_, err = wskdeploy.Undeploy(manifestPath, deploymentPath) + //assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.") } diff --git a/utils/flags.go b/utils/flags.go index 278527e..7d42cde 100644 --- a/utils/flags.go +++ b/utils/flags.go @@ -42,6 +42,7 @@ type WskDeployFlags struct { ApigwAccessToken string Verbose bool Trace bool + Sync bool } func (flags *WskDeployFlags) Format() string { diff --git a/utils/managedannotations.go b/utils/managedannotations.go index fa0781e..858b2b5 100644 --- a/utils/managedannotations.go +++ b/utils/managedannotations.go @@ -35,17 +35,20 @@ import ( */ const ( - MANAGED = "managed" + MANAGED = "whisk-managed" OPENWHISK = "OpenWhisk" NULL = "golang\000" - OW_PROJECT_NAME = "__OW_PROJECT_NAME" - OW_PROJECT_HASH = "__OW_PROJECT_HASH" + OW_PROJECT_NAME = "projectName" + OW_PROJECT_HASH = "projectHash" + OW_PROJECT_DEPS = "projectDeps" + OW_File = "file" ) type ManagedAnnotation struct { - ProjectName string `json:"__OW_PROJECT_NAME"` - ProjectHash string `json:"__OW_PROJECT_HASH"` - File string `json:"__OW_FILE"` + ProjectName string `json:"projectName"` + ProjectHash string `json:"projectHash"` + File string `json:"file"` + Deps whisk.KeyValueArr `json:"projectDeps"` } // Project Hash is generated based on the following formula: @@ -100,13 +103,38 @@ func GenerateManagedAnnotation(projectName string, filePath string) (whisk.KeyVa ProjectName: projectName, ProjectHash: projectHash, File: filePath, + Deps: make(whisk.KeyValueArr, 0), } - ma, err := json.Marshal(m) + ma, err := structToJson(m) if err != nil { return managedAnnotation, err } - var a interface{} - err = json.Unmarshal(ma, &a) - managedAnnotation = whisk.KeyValue{Key: MANAGED, Value: a.(map[string]interface{})} + managedAnnotation = whisk.KeyValue{Key: MANAGED, Value: ma} return managedAnnotation, nil } + +func AddDependentAnnotation(existingAnnotation map[string]interface{}, dependencyAnnotations whisk.KeyValueArr) (whisk.KeyValue, error) { + managedAnnotation := whisk.KeyValue{} + m := ManagedAnnotation{ + ProjectName: existingAnnotation[OW_PROJECT_NAME].(string), + ProjectHash: existingAnnotation[OW_PROJECT_HASH].(string), + File: existingAnnotation[OW_File].(string), + Deps: dependencyAnnotations, + } + ma, err := structToJson(m) + if err != nil { + return managedAnnotation, err + } + managedAnnotation = whisk.KeyValue{Key: MANAGED, Value: ma} + return managedAnnotation, nil +} + +func structToJson(m ManagedAnnotation) (map[string]interface{}, error) { + ma, err := json.Marshal(m) + if err != nil { + return nil, err + } + var a interface{} + json.Unmarshal(ma, &a) + return a.(map[string]interface{}), nil +} diff --git a/wski18n/i18n_ids.go b/wski18n/i18n_ids.go index 12807b5..25ceb06 100644 --- a/wski18n/i18n_ids.go +++ b/wski18n/i18n_ids.go @@ -40,6 +40,7 @@ const ( CMD_DEPLOY = "deploy" CMD_UNDEPLOY = "undeploy" CMD_SYNC = "sync" + TRIGGERS = "Triggers" ) // DO NOT TRANSLATE @@ -72,6 +73,9 @@ const ( KEY_API = "api" KEY_URL = "url" KEY_PACKAGE = "package" + KEY_BINDINGS = "bindings" + KEY_DEPENDENCY = "dependency" + KEY_LOCATION = "location" ) // DO NOT TRANSLATE @@ -86,9 +90,11 @@ const ( // Cobra command descriptions ID_CMD_DESC_LONG_REPORT = "msg_cmd_desc_long_report" ID_CMD_DESC_LONG_ROOT = "msg_cmd_desc_long_root" + ID_CMD_DESC_LONG_SYNC = "msg_cmd_desc_long_sync" ID_CMD_DESC_SHORT_REPORT = "msg_cmd_desc_short_report" ID_CMD_DESC_SHORT_ROOT = "msg_cmd_desc_short_root" ID_CMD_DESC_SHORT_VERSION = "msg_cmd_desc_short_version" + ID_CMD_DESC_SHORT_SYNC = "msg_cmd_desc_short_sync" // Cobra Flag messages ID_CMD_FLAG_API_HOST = "msg_cmd_flag_api_host" diff --git a/wski18n/i18n_resources.go b/wski18n/i18n_resources.go index b22c917..a28d6b9 100644 --- a/wski18n/i18n_resources.go +++ b/wski18n/i18n_resources.go @@ -97,7 +97,7 @@ func wski18nResourcesDe_deAllJson() (*asset, error) { return a, nil } -var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x5b\x5f\x8f\xdb\x36\x12\x7f\xcf\xa7\x18\x04\x07\xa4\x05\x1c\x25\xed\xe1\x80\x43\x80\x7d\xc8\x35\x69\xbb\xd7\x26\x1b\xec\x26\x17\x14\xb9\x85\x42\x8b\x63\x9b\xb5\x44\x0a\x24\x65\xc7\x35\xfc\xdd\x0f\xc3\x3f\x92\xec\x5d\x4a\x5a\xa7\xc5\xe5\xa5\x6e\x38\x9c\xf9\xcd\x90\xfc\x71\x66\xa8\x7c\x7a\x04\xb0\x7f\x04\x00\xf0\x58\xf0\xc7\x2f\xe0\x71\x65\x96\x79\xad\x71\x21\xbe\xe4\xa8\xb5\xd2\x8f\x67\x7e\xd4\x6a\x26 [...] +var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x5b\x6d\x8f\xdb\x36\xf2\x7f\x9f\x4f\x31\x08\xfe\x40\x5a\xc0\x51\xd2\xfe\x71\xc0\x21\x40\x5e\xe4\x9a\xb4\xdd\x6b\x93\x0d\x76\xb3\x17\x14\xb9\x85\x42\x4b\x63\x9b\xb5\x44\x0a\x24\x65\xc7\x35\xfc\xdd\x0f\x33\xa4\x1e\xec\x5d\x4a\x5a\xa7\xbd\xeb\x9b\xf3\x2d\x87\x33\xbf\x79\xe0\x70\x66\xa8\x7c\x7a\x04\xb0\x7f\x04\x00\xf0\x58\xe6\x8f\x5f\xc0\xe3\xd2\x2e\xd3\xca\xe0\x42\x7e\x49\xd1\x18\x6d\x1e\xcf\xfc\xaa\x33 [...] func wski18nResourcesEn_usAllJsonBytes() ([]byte, error) { return bindataRead( @@ -112,7 +112,7 @@ func wski18nResourcesEn_usAllJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 13551, mode: os.FileMode(420), modTime: time.Unix(1521501471, 0)} + info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 13874, mode: os.FileMode(420), modTime: time.Unix(1522158494, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -329,14 +329,14 @@ func AssetNames() []string { // _bindata is a table, holding each asset generator, mapped to its name. var _bindata = map[string]func() (*asset, error){ - "wski18n/resources/de_DE.all.json": wski18nResourcesDe_deAllJson, - "wski18n/resources/en_US.all.json": wski18nResourcesEn_usAllJson, - "wski18n/resources/es_ES.all.json": wski18nResourcesEs_esAllJson, - "wski18n/resources/fr_FR.all.json": wski18nResourcesFr_frAllJson, - "wski18n/resources/it_IT.all.json": wski18nResourcesIt_itAllJson, - "wski18n/resources/ja_JA.all.json": wski18nResourcesJa_jaAllJson, - "wski18n/resources/ko_KR.all.json": wski18nResourcesKo_krAllJson, - "wski18n/resources/pt_BR.all.json": wski18nResourcesPt_brAllJson, + "wski18n/resources/de_DE.all.json": wski18nResourcesDe_deAllJson, + "wski18n/resources/en_US.all.json": wski18nResourcesEn_usAllJson, + "wski18n/resources/es_ES.all.json": wski18nResourcesEs_esAllJson, + "wski18n/resources/fr_FR.all.json": wski18nResourcesFr_frAllJson, + "wski18n/resources/it_IT.all.json": wski18nResourcesIt_itAllJson, + "wski18n/resources/ja_JA.all.json": wski18nResourcesJa_jaAllJson, + "wski18n/resources/ko_KR.all.json": wski18nResourcesKo_krAllJson, + "wski18n/resources/pt_BR.all.json": wski18nResourcesPt_brAllJson, "wski18n/resources/zh_Hans.all.json": wski18nResourcesZh_hansAllJson, "wski18n/resources/zh_Hant.all.json": wski18nResourcesZh_hantAllJson, } @@ -380,18 +380,17 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } - var _bintree = &bintree{nil, map[string]*bintree{ "wski18n": &bintree{nil, map[string]*bintree{ "resources": &bintree{nil, map[string]*bintree{ - "de_DE.all.json": &bintree{wski18nResourcesDe_deAllJson, map[string]*bintree{}}, - "en_US.all.json": &bintree{wski18nResourcesEn_usAllJson, map[string]*bintree{}}, - "es_ES.all.json": &bintree{wski18nResourcesEs_esAllJson, map[string]*bintree{}}, - "fr_FR.all.json": &bintree{wski18nResourcesFr_frAllJson, map[string]*bintree{}}, - "it_IT.all.json": &bintree{wski18nResourcesIt_itAllJson, map[string]*bintree{}}, - "ja_JA.all.json": &bintree{wski18nResourcesJa_jaAllJson, map[string]*bintree{}}, - "ko_KR.all.json": &bintree{wski18nResourcesKo_krAllJson, map[string]*bintree{}}, - "pt_BR.all.json": &bintree{wski18nResourcesPt_brAllJson, map[string]*bintree{}}, + "de_DE.all.json": &bintree{wski18nResourcesDe_deAllJson, map[string]*bintree{}}, + "en_US.all.json": &bintree{wski18nResourcesEn_usAllJson, map[string]*bintree{}}, + "es_ES.all.json": &bintree{wski18nResourcesEs_esAllJson, map[string]*bintree{}}, + "fr_FR.all.json": &bintree{wski18nResourcesFr_frAllJson, map[string]*bintree{}}, + "it_IT.all.json": &bintree{wski18nResourcesIt_itAllJson, map[string]*bintree{}}, + "ja_JA.all.json": &bintree{wski18nResourcesJa_jaAllJson, map[string]*bintree{}}, + "ko_KR.all.json": &bintree{wski18nResourcesKo_krAllJson, map[string]*bintree{}}, + "pt_BR.all.json": &bintree{wski18nResourcesPt_brAllJson, map[string]*bintree{}}, "zh_Hans.all.json": &bintree{wski18nResourcesZh_hansAllJson, map[string]*bintree{}}, "zh_Hant.all.json": &bintree{wski18nResourcesZh_hantAllJson, map[string]*bintree{}}, }}, @@ -444,3 +443,4 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } + diff --git a/wski18n/resources/en_US.all.json b/wski18n/resources/en_US.all.json index 512d758..9824ddb 100644 --- a/wski18n/resources/en_US.all.json +++ b/wski18n/resources/en_US.all.json @@ -36,6 +36,14 @@ "translation": "Print the version number of wskdeploy" }, { + "id": "msg_cmd_desc_short_sync", + "translation": "A tool to sync your OpenWhisk packages between client and server." + }, + { + "id": "msg_cmd_desc_long_sync", + "translation": "A tool to sync deployment and undeployment of openwhisk packages using a manifest and optional deployment files using YAML." + }, + { "id": "msg_cmd_flag_api_host", "translation": "whisk API `HOST`" }, -- To stop receiving notification emails like this one, please contact mrutkow...@apache.org.