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 de4e3d8 Refactoring ManifestReader (#863) de4e3d8 is described below commit de4e3d80046ef691d91c4bf24b462c39916f5195 Author: Priti Desai <pde...@us.ibm.com> AuthorDate: Tue Apr 10 13:28:16 2018 -0700 Refactoring ManifestReader (#863) * cleaning up manifestreader * adding error messages to wski18n * adding integration test on actions * Adding trigger tests * adding error message for trigger * adding rule test * fixing integration test * fixing integration test * integration test fix * dropping doc on errors --- cmd/root.go | 16 +- deployers/manifestreader.go | 290 ++++++++----------- deployers/manifestreader_test.go | 319 ++++++++++++++++++++- deployers/servicedeployer.go | 2 - parsers/manifest_parser.go | 6 +- tests/dat/manifest_validate_action_all.yaml | 43 +++ tests/dat/manifest_validate_dependencies.yaml | 42 +++ .../dat/manifest_validate_dependencies_bogus.yaml | 42 +++ ...st_validate_package_inputs_and_annotations.yaml | 37 +++ tests/dat/manifest_validate_rules_bogus.yaml | 41 +++ tests/dat/manifest_validate_sequences_bogus.yaml | 38 +++ tests/dat/manifest_validate_triggers_bogus.yaml | 33 +++ utils/dependencies.go | 10 + utils/gitreader.go | 1 - wski18n/i18n_ids.go | 47 +-- wski18n/i18n_resources.go | 4 +- wski18n/resources/en_US.all.json | 24 ++ 17 files changed, 777 insertions(+), 218 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 77b2e03..4d665dd 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -150,7 +150,7 @@ func loadDefaultDeploymentFileFromProjectPath(command string, projectPath string } else if _, err := os.Stat(path.Join(projectPath, utils.DeploymentFileNameYml)); err == nil { utils.Flags.DeploymentPath = path.Join(projectPath, utils.DeploymentFileNameYml) } - displayCommandUsingFilenameMessage(command, wski18n.DEPLOYMENT_FILE, utils.Flags.ManifestPath) + displayCommandUsingFilenameMessage(command, wski18n.DEPLOYMENT_FILE, utils.Flags.DeploymentPath) return nil } @@ -167,14 +167,19 @@ func Deploy() error { projectPath, _ := filepath.Abs(project_Path) // If manifest filename is not provided, attempt to load default manifests from project path + // default manifests are manifest.yaml and manifest.yml + // return failure if none of the default manifest files were found if utils.Flags.ManifestPath == "" { if err := loadDefaultManifestFileFromProjectPath(wski18n.CMD_DEPLOY, projectPath); err != nil { return err } } + // If deployment filename is not provided, attempt to load default deployment files from project path + // default deployments are deployment.yaml and deployment.yml + // continue processing manifest file, even if none of the default + // deployment files were found as deployment files are optional if utils.Flags.DeploymentPath == "" { - if err := loadDefaultDeploymentFileFromProjectPath(wski18n.CMD_DEPLOY, projectPath); err != nil { return err } @@ -182,7 +187,9 @@ func Deploy() error { if utils.MayExists(utils.Flags.ManifestPath) { + // Create an instance of ServiceDeployer var deployer = deployers.NewServiceDeployer() + // Set Project Path, Manifest Path, and Deployment Path of ServiceDeployer deployer.ProjectPath = projectPath deployer.ManifestPath = utils.Flags.ManifestPath deployer.DeploymentPath = utils.Flags.DeploymentPath @@ -191,6 +198,7 @@ func Deploy() error { // master record of any dependency that has been downloaded deployer.DependencyMaster = make(map[string]utils.DependencyRecord) + // Read credentials from Configuration file, manifest file or deployment file clientConfig, error := deployers.NewWhiskConfig( utils.Flags.CfgFile, utils.Flags.DeploymentPath, @@ -210,14 +218,14 @@ func Deploy() error { // The auth, apihost and namespace have been chosen, so that we can check the supported runtimes here. setSupportedRuntimes(clientConfig.Host) + // Construct Deployment Plan err := deployer.ConstructDeploymentPlan() - if err != nil { return err } + // Deploy all OW entities err = deployer.Deploy() - if err != nil { return err } else { diff --git a/deployers/manifestreader.go b/deployers/manifestreader.go index 1f9171d..c19fd68 100644 --- a/deployers/manifestreader.go +++ b/deployers/manifestreader.go @@ -18,13 +18,14 @@ package deployers import ( - "errors" "strings" + "fmt" "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/wskderrors" + "github.com/apache/incubator-openwhisk-wskdeploy/wski18n" ) var clientConfig *whisk.Config @@ -58,32 +59,31 @@ func (reader *ManifestReader) InitPackages(manifestParser *parsers.YAMLParser, m return err } reader.SetPackages(packages) - return nil } // Wrapper parser to handle yaml dir -func (deployer *ManifestReader) HandleYaml(sdeployer *ServiceDeployer, manifestParser *parsers.YAMLParser, manifest *parsers.YAML, managedAnnotations whisk.KeyValue) error { +func (reader *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, managedAnnotations) + deps, err := manifestParser.ComposeDependenciesFromAllPackages(manifest, reader.serviceDeployer.ProjectPath, reader.serviceDeployer.ManifestPath, managedAnnotations) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } - actions, err := manifestParser.ComposeActionsFromAllPackages(manifest, deployer.serviceDeployer.ManifestPath, managedAnnotations) + actions, err := manifestParser.ComposeActionsFromAllPackages(manifest, reader.serviceDeployer.ManifestPath, managedAnnotations) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } - sequences, err := manifestParser.ComposeSequencesFromAllPackages(deployer.serviceDeployer.ClientConfig.Namespace, manifest, deployer.serviceDeployer.ManifestPath, managedAnnotations) + sequences, err := manifestParser.ComposeSequencesFromAllPackages(reader.serviceDeployer.ClientConfig.Namespace, manifest, reader.serviceDeployer.ManifestPath, managedAnnotations) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } - triggers, err := manifestParser.ComposeTriggersFromAllPackages(manifest, deployer.serviceDeployer.ManifestPath, managedAnnotations) + triggers, err := manifestParser.ComposeTriggersFromAllPackages(manifest, reader.serviceDeployer.ManifestPath, managedAnnotations) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } @@ -93,37 +93,37 @@ func (deployer *ManifestReader) HandleYaml(sdeployer *ServiceDeployer, manifestP return wskderrors.NewYAMLFileFormatError(manifestName, err) } - apis, err := manifestParser.ComposeApiRecordsFromAllPackages(deployer.serviceDeployer.ClientConfig, manifest) + apis, err := manifestParser.ComposeApiRecordsFromAllPackages(reader.serviceDeployer.ClientConfig, manifest) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } - err = deployer.SetDependencies(deps) + err = reader.SetDependencies(deps) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } - err = deployer.SetActions(actions) + err = reader.SetActions(actions) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } - err = deployer.SetSequences(sequences) + err = reader.SetSequences(sequences) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } - err = deployer.SetTriggers(triggers) + err = reader.SetTriggers(triggers) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } - err = deployer.SetRules(rules) + err = reader.SetRules(rules) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } - err = deployer.SetApis(apis) + err = reader.SetApis(apis) if err != nil { return wskderrors.NewYAMLFileFormatError(manifestName, err) } @@ -131,36 +131,6 @@ func (deployer *ManifestReader) HandleYaml(sdeployer *ServiceDeployer, manifestP return nil } -func (reader *ManifestReader) SetDependencies(deps map[string]utils.DependencyRecord) error { - for name, dep := range deps { - n := strings.Split(name, ":") - depName := n[1] - if depName == "" { - return nil - } - if !dep.IsBinding && !reader.IsUndeploy { - if _, exists := reader.serviceDeployer.DependencyMaster[depName]; !exists { - // dependency - gitReader := utils.NewGitReader(depName, dep) - err := gitReader.CloneDependency() - if err != nil { - return wskderrors.NewYAMLFileFormatError(depName, err) - } - } else { - // TODO: we should do a check to make sure this dependency is compatible with an already installed one. - // If not, we should throw dependency mismatch error. - } - } - - // store in two places (one local to package to preserve relationship, one in master record to check for conflics - reader.serviceDeployer.Deployment.Packages[dep.Packagename].Dependencies[depName] = dep - reader.serviceDeployer.DependencyMaster[depName] = dep - - } - - return nil -} - func (reader *ManifestReader) SetPackages(packages map[string]*whisk.Package) error { dep := reader.serviceDeployer @@ -169,13 +139,6 @@ func (reader *ManifestReader) SetPackages(packages map[string]*whisk.Package) er defer dep.mt.Unlock() for _, pkg := range packages { - _, exist := dep.Deployment.Packages[pkg.Name] - if exist { - // TODO(): i18n of error message (or create a new named error) - // TODO(): Is there a better way to handle an existing dependency of same name? - err := errors.New("Package [" + pkg.Name + "] exists already.") - return wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err) - } newPack := NewDeploymentPackage() newPack.Package = pkg dep.Deployment.Packages[pkg.Name] = newPack @@ -183,126 +146,78 @@ func (reader *ManifestReader) SetPackages(packages map[string]*whisk.Package) er return nil } -func (reader *ManifestReader) SetActions(actions []utils.ActionRecord) error { +func (reader *ManifestReader) SetDependencies(deps map[string]utils.DependencyRecord) error { dep := reader.serviceDeployer dep.mt.Lock() defer dep.mt.Unlock() - for _, manifestAction := range actions { - existAction, exists := reader.serviceDeployer.Deployment.Packages[manifestAction.Packagename].Actions[manifestAction.Action.Name] - - if exists == true { - if existAction.Filepath == manifestAction.Filepath || manifestAction.Filepath == "" { - // we're adding a filesystem detected action so just updated code and filepath if needed - if manifestAction.Action.Exec.Kind != "" { - existAction.Action.Exec.Kind = manifestAction.Action.Exec.Kind - } - - if manifestAction.Action.Exec.Code != nil { - code := *manifestAction.Action.Exec.Code - if code != "" { - existAction.Action.Exec.Code = manifestAction.Action.Exec.Code - } - } - - existAction.Action.Annotations = manifestAction.Action.Annotations - existAction.Action.Limits = manifestAction.Action.Limits - existAction.Action.Parameters = manifestAction.Action.Parameters - existAction.Action.Version = manifestAction.Action.Version - - if manifestAction.Filepath != "" { - existAction.Filepath = manifestAction.Filepath - } - - err := reader.checkAction(existAction) - if err != nil { - return wskderrors.NewFileReadError(manifestAction.Filepath, err) + for name, dependency := range deps { + // name is <packagename>:<dependencylabel> + depName := strings.Split(name, ":")[1] + if len(depName) == 0 { + return nil + } + if !dependency.IsBinding && !reader.IsUndeploy { + if _, exists := dep.DependencyMaster[depName]; exists { + if !utils.CompareDependencyRecords(dep.DependencyMaster[depName], dependency) { + location := strings.Join([]string{dep.DependencyMaster[depName].Location, dependency.Location}, ",") + errmsg := wski18n.T(wski18n.ID_ERR_DEPENDENCIES_WITH_SAME_LABEL_X_dependency_X_location_X, + map[string]interface{}{wski18n.KEY_DEPENDENCY: depName, + wski18n.KEY_LOCATION: location}) + return wskderrors.NewYAMLParserErr(dep.ManifestPath, errmsg) } - - } else { - // Action exists, but references two different sources - // TODO(): i18n of error message (or create a new named error) - err := errors.New("Conflict detected for action named [" + - existAction.Action.Name + "].\nFound two locations for source file: [" + - existAction.Filepath + "] and [" + manifestAction.Filepath + "]") - return wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err) } - } else { - // not a new action so update the action in the package - err := reader.checkAction(manifestAction) + gitReader := utils.NewGitReader(depName, dependency) + err := gitReader.CloneDependency() if err != nil { - return wskderrors.NewFileReadError(manifestAction.Filepath, err) + return err } - reader.serviceDeployer.Deployment.Packages[manifestAction.Packagename].Actions[manifestAction.Action.Name] = manifestAction } + // store in two places (one local to package to preserve relationship, one in master record to check for conflics + dep.Deployment.Packages[dependency.Packagename].Dependencies[depName] = dependency + dep.DependencyMaster[depName] = dependency } return nil } -// TODO create named errors -// Check action record before deploying it -// action record is created by reading and composing action elements from manifest file -// Action.kind is mandatory which is set to -// (1) action runtime for an action and (2) set to "sequence" for a sequence -// Also, action executable code should be specified for any action -func (reader *ManifestReader) checkAction(action utils.ActionRecord) error { - if action.Action.Exec.Kind == "" { - // TODO(): i18n of error message (or create a new named error) - err := errors.New("Action [" + action.Action.Name + "] has no kind set.") - return wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err) - } +func (reader *ManifestReader) SetActions(actions []utils.ActionRecord) error { - if action.Action.Exec.Code != nil { - code := *action.Action.Exec.Code - if code == "" && action.Action.Exec.Kind != parsers.YAML_KEY_SEQUENCE { - // TODO(): i18n of error message (or create a new named error) - err := errors.New("Action [" + action.Action.Name + "] has no source code.") - return wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err) + dep := reader.serviceDeployer + + dep.mt.Lock() + defer dep.mt.Unlock() + + for _, manifestAction := range actions { + err := reader.checkAction(manifestAction) + if err != nil { + return err } + dep.Deployment.Packages[manifestAction.Packagename].Actions[manifestAction.Action.Name] = manifestAction } - return nil } -func (reader *ManifestReader) SetSequences(actions []utils.ActionRecord) error { +func (reader *ManifestReader) SetSequences(sequences []utils.ActionRecord) error { dep := reader.serviceDeployer dep.mt.Lock() defer dep.mt.Unlock() - for _, seqAction := range actions { - // check if the sequence action is exist in actions - // If the sequence action exists in actions, return error - _, exists := reader.serviceDeployer.Deployment.Packages[seqAction.Packagename].Actions[seqAction.Action.Name] - if exists == true { - // TODO(798): i18n of error message (or create a new named error) - err := errors.New("Sequence action's name [" + - seqAction.Action.Name + "] is already used by an action.") + for _, sequence := range sequences { + // If the sequence name matches with any of the actions defined, return error + if _, exists := dep.Deployment.Packages[sequence.Packagename].Actions[sequence.Action.Name]; exists { + err := wski18n.T(wski18n.ID_ERR_SEQUENCE_HAVING_SAME_NAME_AS_ACTION_X_action_X, + map[string]interface{}{wski18n.KEY_SEQUENCE: sequence.Action.Name}) return wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err) } - existAction, exists := reader.serviceDeployer.Deployment.Packages[seqAction.Packagename].Sequences[seqAction.Action.Name] - - if exists == true { - existAction.Action.Annotations = seqAction.Action.Annotations - existAction.Action.Exec.Kind = "sequence" - existAction.Action.Exec.Components = seqAction.Action.Exec.Components - existAction.Action.Publish = seqAction.Action.Publish - existAction.Action.Namespace = seqAction.Action.Namespace - existAction.Action.Limits = seqAction.Action.Limits - existAction.Action.Parameters = seqAction.Action.Parameters - existAction.Action.Version = seqAction.Action.Version - } else { - // not a new action so update the action in the package - err := reader.checkAction(seqAction) - if err != nil { - // TODO() Need a better error type here - return wskderrors.NewFileReadError(seqAction.Filepath, err) - } - reader.serviceDeployer.Deployment.Packages[seqAction.Packagename].Sequences[seqAction.Action.Name] = seqAction + err := reader.checkAction(sequence) + if err != nil { + return err } + dep.Deployment.Packages[sequence.Packagename].Sequences[sequence.Action.Name] = sequence } return nil @@ -317,19 +232,29 @@ func (reader *ManifestReader) SetTriggers(triggers []*whisk.Trigger) error { defer dep.mt.Unlock() for _, trigger := range triggers { - existTrigger, exist := dep.Deployment.Triggers[trigger.Name] - if exist { - existTrigger.Name = trigger.Name - existTrigger.ActivationId = trigger.ActivationId - existTrigger.Namespace = trigger.Namespace - existTrigger.Annotations = trigger.Annotations - existTrigger.Version = trigger.Version - existTrigger.Parameters = trigger.Parameters - existTrigger.Publish = trigger.Publish - } else { - dep.Deployment.Triggers[trigger.Name] = trigger + if _, exists := dep.Deployment.Triggers[trigger.Name]; exists { + var feed string + var existingFeed string + for _, a := range dep.Deployment.Triggers[trigger.Name].Annotations { + if a.Key == parsers.YAML_KEY_FEED { + existingFeed = a.Value.(string) + } + } + for _, a := range trigger.Annotations { + if a.Key == parsers.YAML_KEY_FEED { + feed = a.Value.(string) + } + } + if feed != existingFeed { + feed = fmt.Sprintf("%q", feed) + existingFeed = fmt.Sprintf("%q", existingFeed) + err := wski18n.T(wski18n.ID_ERR_CONFLICTING_TRIGGERS_ACROSS_PACKAGES_X_trigger_X_feed_X, + map[string]interface{}{wski18n.KEY_TRIGGER: trigger.Name, + wski18n.KEY_TRIGGER_FEED: strings.Join([]string{feed, existingFeed}, ", ")}) + return wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err) + } } - + dep.Deployment.Triggers[trigger.Name] = trigger } return nil } @@ -341,19 +266,24 @@ func (reader *ManifestReader) SetRules(rules []*whisk.Rule) error { defer dep.mt.Unlock() for _, rule := range rules { - existRule, exist := dep.Deployment.Rules[rule.Name] - if exist { - existRule.Name = rule.Name - existRule.Publish = rule.Publish - existRule.Version = rule.Version - existRule.Namespace = rule.Namespace - existRule.Action = rule.Action - existRule.Trigger = rule.Trigger - existRule.Status = rule.Status - } else { - dep.Deployment.Rules[rule.Name] = rule + if _, exists := dep.Deployment.Rules[rule.Name]; exists { + action := rule.Action.(string) + existingAction := dep.Deployment.Rules[rule.Name].Action.(string) + trigger := rule.Trigger.(string) + existingTrigger := dep.Deployment.Rules[rule.Name].Trigger.(string) + if action != existingAction || trigger != existingTrigger { + action = fmt.Sprintf("%q", action) + existingAction = fmt.Sprintf("%q", existingAction) + trigger = fmt.Sprintf("%q", trigger) + existingTrigger = fmt.Sprintf("%q", existingTrigger) + err := wski18n.T(wski18n.ID_ERR_CONFLICTING_RULES_ACROSS_PACKAGES_X_rule_X_action_X_trigger_X, + map[string]interface{}{wski18n.KEY_RULE: rule.Name, + wski18n.KEY_TRIGGER: strings.Join([]string{trigger, existingTrigger}, ", "), + wski18n.KEY_ACTION: strings.Join([]string{action, existingAction}, ", ")}) + return wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err) + } } - + dep.Deployment.Rules[rule.Name] = rule } return nil } @@ -365,13 +295,31 @@ func (reader *ManifestReader) SetApis(ar []*whisk.ApiCreateRequest) error { defer dep.mt.Unlock() for _, api := range ar { - existApi, exist := dep.Deployment.Apis[api.ApiDoc.Action.Name] - if exist { - existApi.ApiDoc.ApiName = api.ApiDoc.ApiName - } else { - dep.Deployment.Apis[api.ApiDoc.Action.Name] = api - } + dep.Deployment.Apis[api.ApiDoc.Action.Name] = api + } + return nil +} +// Check action record before deploying it +// action record is created by reading and composing action elements from manifest file +// Action.kind is mandatory which is set to +// (1) action runtime for an action and (2) set to "sequence" for a sequence +// Also, action executable code should be specified for any action +func (reader *ManifestReader) checkAction(action utils.ActionRecord) error { + if action.Action.Exec.Kind == "" { + err := wski18n.T(wski18n.ID_ERR_ACTION_WITHOUT_KIND_X_action_X, + map[string]interface{}{wski18n.KEY_ACTION: action.Action.Name}) + return wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err) + } + + if action.Action.Exec.Code != nil { + code := *action.Action.Exec.Code + if code == "" && action.Action.Exec.Kind != parsers.YAML_KEY_SEQUENCE { + err := wski18n.T(wski18n.ID_ERR_ACTION_WITHOUT_SOURCE_X_action_X, + map[string]interface{}{wski18n.KEY_ACTION: action.Action.Name}) + return wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err) + } } + return nil } diff --git a/deployers/manifestreader_test.go b/deployers/manifestreader_test.go index 7d5acbc..bf2e439 100644 --- a/deployers/manifestreader_test.go +++ b/deployers/manifestreader_test.go @@ -20,38 +20,327 @@ package deployers import ( + "fmt" + "testing" + "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/wskprint" "github.com/stretchr/testify/assert" - "testing" ) var mr *ManifestReader var ps *parsers.YAMLParser var ms *parsers.YAML -func init() { +const ( + // local error messages + TEST_ERROR_BUILD_SERVICE_DEPLOYER = "Manifest [%s]: Failed to build service deployer." + TEST_ERROR_MANIFEST_PARSE_FAILURE = "Manifest [%s]: Failed to parse." + TEST_ERROR_MANIFEST_SET_PACKAGES = "Manifest [%s]: Failed to set packages." + TEST_ERROR_FAILED_TO_REPORT_ERROR = "Manifest [%s]: Failed to report parser error." + TEST_ERROR_MANIFEST_SET_ANNOTATION = "[%s]: Failed to set Annotation value." + TEST_ERROR_MANIFEST_SET_INPUT_PARAMETER = "[%s]: Failed to set input Parameter value." + TEST_ERROR_MANIFEST_SET_PUBLISH = "Package [%s]: Failed to set publish." + TEST_ERROR_MANIFEST_SET_DEPENDENCIES = "Package [%s]: Failed to set dependencies." + TEST_ERROR_MANIFEST_SET_ACTION_CODE = "Action [%s]: Failed to set action code." + TEST_ERROR_MANIFEST_SET_ACTION_KIND = "Action [%s]: Failed to set action kind." + TEST_ERROR_MANIFEST_SET_ACTION_WEB = "Action [%s]: Failed to set web action." + TEST_ERROR_MANIFEST_SET_ACTION_CONDUCTOR = "Action [%s]: Failed to set conductor action." + TEST_ERROR_MANIFEST_SET_ACTION_IMAGE = "Action [%s]: Failed to set action image." +) +func init() { // Setup "trace" flag for unit tests based upon "go test" -v flag utils.Flags.Trace = wskprint.DetectGoTestVerbose() - - sd = NewServiceDeployer() - sd.ManifestPath = manifest_file - mr = NewManifestReader(sd) - ps = parsers.NewYAMLParser() - ms, _ = ps.ParseManifest(manifest_file) } -// Test could parse Manifest file successfully -func TestManifestReader_ParseManifest(t *testing.T) { - _, _, err := mr.ParseManifest() - assert.Equal(t, err, nil, "New ManifestReader failed") +func buildServiceDeployer(manifestFile string) (*ServiceDeployer, error) { + deploymentFile := "" + var deployer = NewServiceDeployer() + deployer.ManifestPath = manifestFile + deployer.DeploymentPath = deploymentFile + deployer.Preview = utils.Flags.Preview + + deployer.DependencyMaster = make(map[string]utils.DependencyRecord) + + config := whisk.Config{ + Namespace: "test", + AuthToken: "user:pass", + Host: "host", + ApigwAccessToken: "token", + } + deployer.ClientConfig = &config + + op, error := utils.ParseOpenWhisk(deployer.ClientConfig.Host) + if error == nil { + utils.SupportedRunTimes = utils.ConvertToMap(op) + utils.DefaultRunTimes = utils.DefaultRuntimes(op) + utils.FileExtensionRuntimeKindMap = utils.FileExtensionRuntimes(op) + utils.FileRuntimeExtensionsMap = utils.FileRuntimeExtensions(op) + } + + return deployer, nil } -// Test could Init root package successfully. func TestManifestReader_InitPackages(t *testing.T) { - err := mr.InitPackages(ps, ms, whisk.KeyValue{}) - assert.Equal(t, err, nil, "Init Root Package failed") + manifestFile := "../tests/dat/manifest_validate_package_inputs_and_annotations.yaml" + deployer, err := buildServiceDeployer(manifestFile) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_BUILD_SERVICE_DEPLOYER, manifestFile)) + + var manifestReader = NewManifestReader(deployer) + manifestReader.IsUndeploy = false + manifest, manifestParser, err := manifestReader.ParseManifest() + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, manifestFile)) + + err = manifestReader.InitPackages(manifestParser, manifest, whisk.KeyValue{}) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, manifestFile)) + assert.Equal(t, 3, len(deployer.Deployment.Packages), fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, manifestFile, "")) + + expectedParametersAndAnnotations := 0 + + for packageName, pack := range deployer.Deployment.Packages { + switch packageName { + case "helloworld1": + expectedParametersAndAnnotations = 0 + assert.False(t, *pack.Package.Publish, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PUBLISH, packageName)) + case "helloworld2": + expectedParametersAndAnnotations = 1 + for _, param := range pack.Package.Parameters { + switch param.Key { + case "helloworld_input1": + assert.Equal(t, "value1", param.Value, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_INPUT_PARAMETER, packageName)) + } + } + for _, annotation := range pack.Package.Annotations { + switch annotation.Key { + case "helloworld_annotation1": + assert.Equal(t, "value1", annotation.Value, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ANNOTATION, packageName)) + } + } + assert.False(t, *pack.Package.Publish, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PUBLISH, packageName)) + case "helloworld3": + expectedParametersAndAnnotations = 2 + for _, param := range pack.Package.Parameters { + switch param.Key { + case "helloworld_input1": + assert.Equal(t, "value1", param.Value, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_INPUT_PARAMETER, packageName)) + case "helloworld_input2": + assert.Equal(t, "value2", param.Value, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_INPUT_PARAMETER, packageName)) + } + } + for _, annotation := range pack.Package.Annotations { + switch annotation.Key { + case "helloworld_annotation1": + assert.Equal(t, "value1", annotation.Value, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ANNOTATION, packageName)) + case "helloworld_annotation2": + assert.Equal(t, "value2", annotation.Value, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ANNOTATION, packageName)) + } + } + assert.True(t, *pack.Package.Publish, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PUBLISH, packageName)) + } + assert.Equal(t, expectedParametersAndAnnotations, len(pack.Package.Parameters), + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_INPUT_PARAMETER, packageName)) + assert.Equal(t, expectedParametersAndAnnotations, len(pack.Package.Annotations), + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ANNOTATION, packageName)) + } +} + +func TestManifestReader_SetDependencies(t *testing.T) { + manifestFile := "../tests/dat/manifest_validate_dependencies.yaml" + deployer, err := buildServiceDeployer(manifestFile) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_BUILD_SERVICE_DEPLOYER, manifestFile)) + + var manifestReader = NewManifestReader(deployer) + manifestReader.IsUndeploy = false + manifest, manifestParser, err := manifestReader.ParseManifest() + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, manifestFile)) + + err = manifestReader.InitPackages(manifestParser, manifest, whisk.KeyValue{}) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, manifestFile)) + + err = manifestReader.HandleYaml(deployer, manifestParser, manifest, whisk.KeyValue{}) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, manifestFile)) + + expectedLocationHelloWorlds := "https://github.com/apache/incubator-openwhisk-test/packages/helloworlds" + expectedLocationHelloWhisk := "https://github.com/apache/incubator-openwhisk-test/packages/hellowhisk" + expectedLocationUtils := "/whisk.system/utils" + + for pkgName, pkg := range deployer.Deployment.Packages { + switch pkgName { + case "helloworld1": + for depName, dep := range pkg.Dependencies { + switch depName { + case "dependency1": + case "helloworlds": + assert.Equal(t, expectedLocationHelloWorlds, dep.Location, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_DEPENDENCIES, pkgName)) + case "dependency2": + assert.Equal(t, expectedLocationHelloWhisk, dep.Location, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_DEPENDENCIES, pkgName)) + case "dependency3": + assert.Equal(t, expectedLocationUtils, dep.Location, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_DEPENDENCIES, pkgName)) + } + } + + case "helloworld2": + for depName, dep := range pkg.Dependencies { + switch depName { + case "helloworlds": + case "dependency1": + case "dependency4": + assert.Equal(t, expectedLocationHelloWorlds, dep.Location, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_DEPENDENCIES, pkgName)) + case "dependency5": + assert.Equal(t, expectedLocationHelloWhisk, dep.Location, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_DEPENDENCIES, pkgName)) + case "dependency6": + assert.Equal(t, expectedLocationUtils, dep.Location, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_DEPENDENCIES, pkgName)) + } + } + } + } +} + +func TestManifestReader_SetDependencies_Bogus(t *testing.T) { + manifestFile := "../tests/dat/manifest_validate_dependencies_bogus.yaml" + deployer, err := buildServiceDeployer(manifestFile) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_BUILD_SERVICE_DEPLOYER, manifestFile)) + + var manifestReader = NewManifestReader(deployer) + manifestReader.IsUndeploy = false + manifest, manifestParser, err := manifestReader.ParseManifest() + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, manifestFile)) + + err = manifestReader.InitPackages(manifestParser, manifest, whisk.KeyValue{}) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, manifestFile)) + + err = manifestReader.HandleYaml(deployer, manifestParser, manifest, whisk.KeyValue{}) + assert.NotNil(t, err, fmt.Sprintf(TEST_ERROR_FAILED_TO_REPORT_ERROR, manifestFile)) +} + +func TestManifestReader_SetActions(t *testing.T) { + manifestFile := "../tests/dat/manifest_validate_action_all.yaml" + deployer, err := buildServiceDeployer(manifestFile) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_BUILD_SERVICE_DEPLOYER, manifestFile)) + + var manifestReader = NewManifestReader(deployer) + manifestReader.IsUndeploy = false + manifest, manifestParser, err := manifestReader.ParseManifest() + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, manifestFile)) + + err = manifestReader.InitPackages(manifestParser, manifest, whisk.KeyValue{}) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, manifestFile)) + + err = manifestReader.HandleYaml(deployer, manifestParser, manifest, whisk.KeyValue{}) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, manifestFile)) + + expectedRuntime := "nodejs:6" + expectedImage := "openwhisk/skeleton" + + for actionName, action := range deployer.Deployment.Packages["helloworld"].Actions { + switch actionName { + case "helloworld1": + case "helloworld2": + assert.NotEmpty(t, action.Action.Exec.Code, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ACTION_CODE, actionName)) + assert.Equal(t, expectedRuntime, action.Action.Exec.Kind, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ACTION_KIND, actionName)) + case "helloworld3": + for _, param := range action.Action.Parameters { + switch param.Key { + case "parameter1": + assert.Equal(t, "value1", param.Value, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_INPUT_PARAMETER, actionName)) + case "parameter2": + assert.Equal(t, "value2", param.Value, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_INPUT_PARAMETER, actionName)) + } + } + for _, annotation := range action.Action.Annotations { + switch annotation.Key { + case "annotation1": + assert.Equal(t, "value1", annotation.Value, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ANNOTATION, actionName)) + case "annotation2": + assert.Equal(t, "value2", annotation.Value, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ANNOTATION, actionName)) + } + } + case "helloworld4": + assert.True(t, action.Action.WebAction(), + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ACTION_WEB, actionName)) + case "helloworld5": + for _, annotation := range action.Action.Annotations { + switch annotation.Key { + case "conductor": + assert.True(t, annotation.Value.(bool), + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ACTION_CONDUCTOR, actionName)) + } + } + case "helloworld6": + assert.Equal(t, expectedImage, action.Action.Exec.Image, + fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ACTION_IMAGE, actionName)) + } + } +} + +func TestManifestReader_SetSequences_Bogus(t *testing.T) { + manifestFile := "../tests/dat/manifest_validate_sequences_bogus.yaml" + deployer, err := buildServiceDeployer(manifestFile) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_BUILD_SERVICE_DEPLOYER, manifestFile)) + + var manifestReader = NewManifestReader(deployer) + manifestReader.IsUndeploy = false + manifest, manifestParser, err := manifestReader.ParseManifest() + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, manifestFile)) + + err = manifestReader.InitPackages(manifestParser, manifest, whisk.KeyValue{}) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, manifestFile)) + + err = manifestReader.HandleYaml(deployer, manifestParser, manifest, whisk.KeyValue{}) + assert.NotNil(t, err, fmt.Sprintf(TEST_ERROR_FAILED_TO_REPORT_ERROR, manifestFile)) +} + +func TestManifestReader_SetTriggers_Bogus(t *testing.T) { + manifestFile := "../tests/dat/manifest_validate_triggers_bogus.yaml" + deployer, err := buildServiceDeployer(manifestFile) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_BUILD_SERVICE_DEPLOYER, manifestFile)) + + var manifestReader = NewManifestReader(deployer) + manifestReader.IsUndeploy = false + manifest, manifestParser, err := manifestReader.ParseManifest() + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, manifestFile)) + + err = manifestReader.InitPackages(manifestParser, manifest, whisk.KeyValue{}) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, manifestFile)) + + err = manifestReader.HandleYaml(deployer, manifestParser, manifest, whisk.KeyValue{}) + assert.NotNil(t, err, fmt.Sprintf(TEST_ERROR_FAILED_TO_REPORT_ERROR, manifestFile)) +} + +func TestManifestReader_SetRules_Bogus(t *testing.T) { + manifestFile := "../tests/dat/manifest_validate_rules_bogus.yaml" + deployer, err := buildServiceDeployer(manifestFile) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_BUILD_SERVICE_DEPLOYER, manifestFile)) + + var manifestReader = NewManifestReader(deployer) + manifestReader.IsUndeploy = false + manifest, manifestParser, err := manifestReader.ParseManifest() + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, manifestFile)) + + err = manifestReader.InitPackages(manifestParser, manifest, whisk.KeyValue{}) + assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, manifestFile)) + + err = manifestReader.HandleYaml(deployer, manifestParser, manifest, whisk.KeyValue{}) + assert.NotNil(t, err, fmt.Sprintf(TEST_ERROR_FAILED_TO_REPORT_ERROR, manifestFile)) } diff --git a/deployers/servicedeployer.go b/deployers/servicedeployer.go index e35fe96..d3a9894 100644 --- a/deployers/servicedeployer.go +++ b/deployers/servicedeployer.go @@ -1570,8 +1570,6 @@ func (deployer *ServiceDeployer) getDependentDeployer(depName string, depRecord depServiceDeployer.Client = deployer.Client depServiceDeployer.ClientConfig = deployer.ClientConfig - depServiceDeployer.DependencyMaster = deployer.DependencyMaster - // share the master dependency list depServiceDeployer.DependencyMaster = deployer.DependencyMaster diff --git a/parsers/manifest_parser.go b/parsers/manifest_parser.go index c63e4dd..3403820 100644 --- a/parsers/manifest_parser.go +++ b/parsers/manifest_parser.go @@ -20,14 +20,12 @@ package parsers import ( "encoding/base64" "errors" + "gopkg.in/yaml.v2" "io/ioutil" "os" "path" - "strings" - - "gopkg.in/yaml.v2" - "path/filepath" + "strings" "github.com/apache/incubator-openwhisk-client-go/whisk" "github.com/apache/incubator-openwhisk-wskdeploy/utils" diff --git a/tests/dat/manifest_validate_action_all.yaml b/tests/dat/manifest_validate_action_all.yaml new file mode 100644 index 0000000..8faf05f --- /dev/null +++ b/tests/dat/manifest_validate_action_all.yaml @@ -0,0 +1,43 @@ +# +# 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. +# + +packages: + helloworld: + actions: + helloworld1: + function: actions/hello.js + helloworld2: + code: const main = ({ msg }) => { console.log(msg); return {msg}; } + runtime: nodejs:6 + helloworld3: + function: actions/hello.js + annotations: + annotation1: value1 + annotation2: value2 + inputs: + parameter1: value1 + parameter2: value2 + helloworld4: + function: actions/hello.js + web: true + helloworld5: + function: actions/hello.js + conductor: true + helloworld6: + function: actions/hello.js + docker: openwhisk/skeleton + + diff --git a/tests/dat/manifest_validate_dependencies.yaml b/tests/dat/manifest_validate_dependencies.yaml new file mode 100644 index 0000000..300cdad --- /dev/null +++ b/tests/dat/manifest_validate_dependencies.yaml @@ -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. +# + +packages: + helloworld1: + dependencies: + helloworlds: + location: github.com/apache/incubator-openwhisk-test/packages/helloworlds + dependency1: + location: github.com/apache/incubator-openwhisk-test/packages/helloworlds + dependency2: + location: github.com/apache/incubator-openwhisk-test/packages/hellowhisk + dependency3: + location: /whisk.system/utils + helloworld2: + dependencies: + helloworlds: + location: github.com/apache/incubator-openwhisk-test/packages/helloworlds + dependency1: + location: github.com/apache/incubator-openwhisk-test/packages/helloworlds + dependency4: + location: github.com/apache/incubator-openwhisk-test/packages/helloworlds + dependency5: + location: github.com/apache/incubator-openwhisk-test/packages/hellowhisk + dependency6: + location: /whisk.system/utils + + + diff --git a/tests/dat/manifest_validate_dependencies_bogus.yaml b/tests/dat/manifest_validate_dependencies_bogus.yaml new file mode 100644 index 0000000..f75c3b1 --- /dev/null +++ b/tests/dat/manifest_validate_dependencies_bogus.yaml @@ -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. +# + +packages: + helloworld1: + dependencies: + helloworlds: + location: github.com/apache/incubator-openwhisk-test/packages/helloworlds + dependency1: + location: github.com/apache/incubator-openwhisk-test/packages/helloworlds + dependency2: + location: github.com/apache/incubator-openwhisk-test/packages/hellowhisk + dependency3: + location: /whisk.system/utils + helloworld2: + dependencies: + helloworlds: + location: github.com/apache/incubator-openwhisk-test/packages/helloworlds + dependency1: + location: github.com/apache/incubator-openwhisk-test/packages/hellowhisk + dependency4: + location: github.com/apache/incubator-openwhisk-test/packages/helloworlds + dependency5: + location: github.com/apache/incubator-openwhisk-test/packages/hellowhisk + dependency6: + location: /whisk.system/utils + + + diff --git a/tests/dat/manifest_validate_package_inputs_and_annotations.yaml b/tests/dat/manifest_validate_package_inputs_and_annotations.yaml new file mode 100644 index 0000000..ea5f253 --- /dev/null +++ b/tests/dat/manifest_validate_package_inputs_and_annotations.yaml @@ -0,0 +1,37 @@ +# +# 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. +# + +packages: + helloworld1: + license: Apache-2.0 + helloworld2: + version: 2.0.0 + license: MIT + inputs: + helloworld_input1: value1 + annotations: + helloworld_annotation1: value1 + helloworld3: + version: 3.0.0 + license: GPL-3.0 + inputs: + helloworld_input1: value1 + helloworld_input2: value2 + annotations: + helloworld_annotation1: value1 + helloworld_annotation2: value2 + public: true + diff --git a/tests/dat/manifest_validate_rules_bogus.yaml b/tests/dat/manifest_validate_rules_bogus.yaml new file mode 100644 index 0000000..587929f --- /dev/null +++ b/tests/dat/manifest_validate_rules_bogus.yaml @@ -0,0 +1,41 @@ +# +# 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. +# + +packages: + helloworld1: + actions: + hello: + function: actions/hello.js + triggers: + trigger1: + rules: + rule1: + trigger: trigger1 + action: hello + helloworld2: + actions: + hello: + function: actions/hello.js + triggers: + trigger2: + rules: + rule1: + trigger: trigger2 + action: hello + rule2: + trigger: trigger2 + action: hello + diff --git a/tests/dat/manifest_validate_sequences_bogus.yaml b/tests/dat/manifest_validate_sequences_bogus.yaml new file mode 100644 index 0000000..4d5425d --- /dev/null +++ b/tests/dat/manifest_validate_sequences_bogus.yaml @@ -0,0 +1,38 @@ +# +# 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. +# + +packages: + helloworld: + actions: + hello: + function: actions/hello.js + runtime: nodejs:6 + helloWithParams: + function: actions/hello.js + runtime: nodejs:6 + inputs: + name: Amy + place: Paris + helloWithParams1: + function: actions/hello.js + runtime: nodejs:6 + inputs: + name: Amy + place: Paris + sequences: + hello: + actions: helloWithParams, helloWithParams1 + diff --git a/tests/dat/manifest_validate_triggers_bogus.yaml b/tests/dat/manifest_validate_triggers_bogus.yaml new file mode 100644 index 0000000..2b3b2c2 --- /dev/null +++ b/tests/dat/manifest_validate_triggers_bogus.yaml @@ -0,0 +1,33 @@ +# +# 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. +# + +packages: + helloworld1: + actions: + hello: + function: actions/hello.js + triggers: + trigger1: + trigger2: + helloworld2: + actions: + hello: + function: actions/hello.js + triggers: + trigger1: + trigger2: + feed: /whisk.system/alarms/alarm + diff --git a/utils/dependencies.go b/utils/dependencies.go index 9f1dd08..eba29b8 100644 --- a/utils/dependencies.go +++ b/utils/dependencies.go @@ -88,3 +88,13 @@ func LocationIsGithub(location string) bool { paths := strings.SplitN(removeProtocol(location), "/", 2) return strings.Contains(paths[0], GITHUB) } + +func CompareDependencyRecords(d1 DependencyRecord, d2 DependencyRecord) bool { + if (d1.Location == d2.Location) && (d1.Version == d2.Version) { + return true + } + if (d1.BaseRepo == d2.BaseRepo) && (d1.SubFolder == d2.SubFolder) && (d1.Version == d2.Version) { + return true + } + return false +} diff --git a/utils/gitreader.go b/utils/gitreader.go index 9d9c84b..741da88 100644 --- a/utils/gitreader.go +++ b/utils/gitreader.go @@ -129,6 +129,5 @@ func (reader *GitReader) CloneDependency() error { } os.Rename(rootDir, depPath) - return nil } diff --git a/wski18n/i18n_ids.go b/wski18n/i18n_ids.go index eae4a0b..9807f0d 100644 --- a/wski18n/i18n_ids.go +++ b/wski18n/i18n_ids.go @@ -78,6 +78,9 @@ const ( KEY_DEPENDENCY = "dependency" KEY_LOCATION = "location" KEY_SEQUENCE = "sequence" + KEY_TRIGGER = "trigger" + KEY_TRIGGER_FEED = "feed" + KEY_RULE = "rule" ) // DO NOT TRANSLATE @@ -163,25 +166,31 @@ const ( ID_MSG_MANAGED_FOUND_DELETED_X_key_X_name_X_project_X = "msg_managed_found_deleted_entity" // Errors - ID_ERR_DEPENDENCY_UNKNOWN_TYPE = "msg_err_dependency_unknown_type" - ID_ERR_ENTITY_CREATE_X_key_X_err_X_code_X = "msg_err_entity_create" - ID_ERR_ENTITY_DELETE_X_key_X_err_X_code_X = "msg_err_entity_delete" - ID_ERR_FEED_INVOKE_X_err_X_code_X = "msg_err_feed_invoke" - ID_ERR_KEY_MISSING_X_key_X = "msg_err_key_missing_mandatory" - ID_ERR_MANIFEST_FILE_NOT_FOUND_X_path_X = "msg_err_manifest_not_found" - ID_ERR_NAME_MISMATCH_X_key_X_dname_X_dpath_X_mname_X_moath_X = "msg_err_name_mismatch" - ID_ERR_RUNTIME_INVALID_X_runtime_X_action_X = "msg_err_runtime_invalid" - ID_ERR_RUNTIME_MISMATCH_X_runtime_X_ext_X_action_X = "msg_err_runtime_mismatch" - ID_ERR_RUNTIMES_GET_X_err_X = "msg_err_runtimes_get" - ID_ERR_RUNTIME_ACTION_SOURCE_NOT_SUPPORTED_X_ext_X_action_X = "msg_err_runtime_action_source_not_supported" - ID_ERR_URL_INVALID_X_urltype_X_url_X_filetype_X = "msg_err_url_invalid" - ID_ERR_URL_MALFORMED_X_urltype_X_url_X = "msg_err_url_malformed" - ID_ERR_API_MISSING_ACTION_OR_SEQUENCE_X_action_or_sequence_X_api_X = "msg_err_api_missing_action_or_sequence" - ID_ERR_ACTION_INVALID_X_action_X = "msg_err_action_invalid" - ID_ERR_ACTION_MISSING_RUNTIME_WITH_CODE_X_action_X = "msg_err_action_missing_runtime_with_code" - ID_ERR_ACTION_FUNCTION_REMOTE_DIR_NOT_SUPPORTED_X_action_X_url_X = "msg_err_action_function_remote_dir_not_supported" - ID_ERR_CANT_SAVE_DOCKER_RUNTIME = "msg_err_cant_save_docker" - ID_ERR_FILE_ALREADY_EXISTS = "msg_err_file_already_exists" + ID_ERR_DEPENDENCY_UNKNOWN_TYPE = "msg_err_dependency_unknown_type" + ID_ERR_ENTITY_CREATE_X_key_X_err_X_code_X = "msg_err_entity_create" + ID_ERR_ENTITY_DELETE_X_key_X_err_X_code_X = "msg_err_entity_delete" + ID_ERR_FEED_INVOKE_X_err_X_code_X = "msg_err_feed_invoke" + ID_ERR_KEY_MISSING_X_key_X = "msg_err_key_missing_mandatory" + ID_ERR_MANIFEST_FILE_NOT_FOUND_X_path_X = "msg_err_manifest_not_found" + ID_ERR_NAME_MISMATCH_X_key_X_dname_X_dpath_X_mname_X_moath_X = "msg_err_name_mismatch" + ID_ERR_RUNTIME_INVALID_X_runtime_X_action_X = "msg_err_runtime_invalid" + ID_ERR_RUNTIME_MISMATCH_X_runtime_X_ext_X_action_X = "msg_err_runtime_mismatch" + ID_ERR_RUNTIMES_GET_X_err_X = "msg_err_runtimes_get" + ID_ERR_RUNTIME_ACTION_SOURCE_NOT_SUPPORTED_X_ext_X_action_X = "msg_err_runtime_action_source_not_supported" + ID_ERR_URL_INVALID_X_urltype_X_url_X_filetype_X = "msg_err_url_invalid" + ID_ERR_URL_MALFORMED_X_urltype_X_url_X = "msg_err_url_malformed" + ID_ERR_API_MISSING_ACTION_OR_SEQUENCE_X_action_or_sequence_X_api_X = "msg_err_api_missing_action_or_sequence" + ID_ERR_ACTION_INVALID_X_action_X = "msg_err_action_invalid" + ID_ERR_ACTION_MISSING_RUNTIME_WITH_CODE_X_action_X = "msg_err_action_missing_runtime_with_code" + ID_ERR_ACTION_FUNCTION_REMOTE_DIR_NOT_SUPPORTED_X_action_X_url_X = "msg_err_action_function_remote_dir_not_supported" + ID_ERR_CANT_SAVE_DOCKER_RUNTIME = "msg_err_cant_save_docker" + ID_ERR_FILE_ALREADY_EXISTS = "msg_err_file_already_exists" + ID_ERR_DEPENDENCIES_WITH_SAME_LABEL_X_dependency_X_location_X = "msg_err_different_dependencies_with_same_label" + ID_ERR_ACTION_WITHOUT_KIND_X_action_X = "msg_err_action_without_kind" + ID_ERR_ACTION_WITHOUT_SOURCE_X_action_X = "msg_err_action_without_source" + ID_ERR_SEQUENCE_HAVING_SAME_NAME_AS_ACTION_X_action_X = "msg_err_sequence_having_same_name_as_action" + ID_ERR_CONFLICTING_TRIGGERS_ACROSS_PACKAGES_X_trigger_X_feed_X = "msg_err_conflicting_triggers_across_packages" + ID_ERR_CONFLICTING_RULES_ACROSS_PACKAGES_X_rule_X_action_X_trigger_X = "msg_err_conflicting_rules_across_packages" // Server-side Errors (wskdeploy as an Action) ID_ERR_JSON_MISSING_KEY_CMD = "msg_err_json_missing_cmd_key" diff --git a/wski18n/i18n_resources.go b/wski18n/i18n_resources.go index e77a8f5..030d962 100755 --- 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\x6f\x8f\xdb\x36\xd2\x7f\x9f\x4f\x31\x08\x1e\x20\x2d\xe0\x28\x69\x1f\x3c\xc0\x83\x00\x79\x91\x6b\xd2\x76\xaf\x4d\x36\xd8\xcd\x5e\x50\xe4\x16\x0a\x2d\x8d\x6d\xd6\x12\xa9\x23\x29\x3b\xae\xe1\xef\x7e\x98\x21\xf5\xc7\xde\xa5\xa4\x75\xda\xbb\xbe\xa9\xbb\x1c\xce\xfc\x66\x38\x9c\x7f\x54\x3f\x3d\x02\xd8\x3f\x02\x00\x78\x2c\xf3\xc7\x2f\xe0\x71\x69\x97\x69\x65\x70\x21\xbf\xa4\x68\x8c\x36\x8f\x67\x7e\xd5\x19 [...] +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\x6d\xda\xc3\x01\x87\x00\x79\xc8\x35\x69\x9b\x6b\x93\x0d\x76\x93\x0b\x8a\xdc\x42\xa1\xa5\xb1\xcd\x5a\x22\x75\x24\x65\xc7\x5d\xec\x77\x3f\xcc\x90\x94\x64\xaf\xf5\xc7\x4e\x7a\x97\x97\x68\x97\xe4\xcc\x6f\x86\xc3\xf9\x47\xee\xc7\x07\x00\xb7\x0f\x00\x00\x1e\xca\xfc\xe1\x53\x78\x58\xda\x65\x5a\x19\x5c\xc8\xcf\x29\x1a\xa3\xcd\xc3\x99\x1f\x75\x46\x28 [...] 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: 14286, mode: os.FileMode(420), modTime: time.Unix(1523039220, 0)} + info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 15831, mode: os.FileMode(420), modTime: time.Unix(1523315322, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/wski18n/resources/en_US.all.json b/wski18n/resources/en_US.all.json index f765820..5b32270 100644 --- a/wski18n/resources/en_US.all.json +++ b/wski18n/resources/en_US.all.json @@ -316,6 +316,30 @@ "translation": "File already exists." }, { + "id": "msg_err_different_dependencies_with_same_label", + "translation": "One single dependency [{{.dependency}}] has two different locations [{{.location}}]. This kind of specification is not supported. Please update the dependency label [{{.dependency}}] in the manifest file to point to same location or create two separate labels for two different locations." + }, + { + "id": "msg_err_action_without_kind", + "translation": "Action [{{.action}}] has no kind set." + }, + { + "id": "msg_err_action_without_code", + "translation": "Action [{{.action}}] has no source code." + }, + { + "id": "msg_err_sequence_having_same_name_as_action", + "translation": "Sequence [{{.sequence}}] is already defined as an action under the same package. Actions and sequences can not have same name in a single package." + }, + { + "id": "msg_err_conflicting_triggers_across_packages", + "translation": "One single trigger [{{.trigger}}] is defined with multiple feeds [{{.feed}}]. Triggers are created directly under the namespace, its not possible to have triggers with same name but different feeds. Please update trigger names in manifest file." + }, + { + "id": "msg_err_conflicting_rules_across_packages", + "translation": "One single rule [{{.rule}}] is defined with different actions [{{.action}}] and/or triggers [{{.trigger}}]. Rules are created directly under the namespace, its not possible to have rules with same name but associated with different actions/triggers. Please update rule names in manifest file." + }, + { "id": "WARNINGS", "translation": "================= WARNINGS ===================" }, -- To stop receiving notification emails like this one, please contact mrutkow...@apache.org.