openwhisk-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mrutkow...@apache.org
Subject [incubator-openwhisk-wskdeploy] branch master updated: Multiple Project Management, adding sync command, and undeploy just using Project Name (#816)
Date Tue, 27 Mar 2018 20:34:37 GMT
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 <pdesai@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
mrutkowski@apache.org.

Mime
View raw message