| /* |
| * 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 parsers |
| |
| import ( |
| "io/ioutil" |
| "log" |
| "os" |
| "path" |
| "strings" |
| |
| "encoding/json" |
| "github.com/openwhisk/openwhisk-client-go/whisk" |
| "github.com/openwhisk/openwhisk-wskdeploy/utils" |
| "gopkg.in/yaml.v2" |
| ) |
| |
| // Read existing manifest file or create new if none exists |
| func ReadOrCreateManifest() *ManifestYAML { |
| maniyaml := ManifestYAML{} |
| |
| if _, err := os.Stat("manifest.yaml"); err == nil { |
| dat, _ := ioutil.ReadFile("manifest.yaml") |
| err := NewYAMLParser().Unmarshal(dat, &maniyaml) |
| utils.Check(err) |
| } |
| return &maniyaml |
| } |
| |
| // Serialize manifest to local file |
| func Write(manifest *ManifestYAML, filename string) { |
| output, err := NewYAMLParser().Marshal(manifest) |
| utils.Check(err) |
| |
| f, err := os.Create(filename) |
| utils.Check(err) |
| defer f.Close() |
| |
| f.Write(output) |
| } |
| |
| func (dm *YAMLParser) Unmarshal(input []byte, manifest *ManifestYAML) error { |
| err := yaml.Unmarshal(input, manifest) |
| if err != nil { |
| log.Printf("error happened during unmarshal :%v", err) |
| return err |
| } |
| return nil |
| } |
| |
| func (dm *YAMLParser) Marshal(manifest *ManifestYAML) (output []byte, err error) { |
| data, err := yaml.Marshal(manifest) |
| if err != nil { |
| log.Printf("err happened during marshal :%v", err) |
| return nil, err |
| } |
| return data, nil |
| } |
| |
| func (dm *YAMLParser) ParseManifest(mani string) *ManifestYAML { |
| mm := NewYAMLParser() |
| maniyaml := ManifestYAML{} |
| |
| content, err := utils.Read(mani) |
| utils.Check(err) |
| |
| err = mm.Unmarshal(content, &maniyaml) |
| utils.Check(err) |
| maniyaml.Filepath = mani |
| return &maniyaml |
| } |
| |
| // Is we consider multi pacakge in one yaml? |
| func (dm *YAMLParser) ComposePackage(mani *ManifestYAML) (*whisk.Package, error) { |
| //mani := dm.ParseManifest(manipath) |
| pag := &whisk.Package{} |
| pag.Name = mani.Package.Packagename |
| //The namespace for this package is absent, so we use default guest here. |
| pag.Namespace = mani.Package.Namespace |
| pub := false |
| pag.Publish = &pub |
| |
| keyValArr := make(whisk.KeyValueArr, 0) |
| for name, param := range mani.Package.Inputs { |
| var keyVal whisk.KeyValue |
| keyVal.Key = name |
| |
| keyVal.Value = ResolveParameter(¶m) |
| |
| if keyVal.Value != nil { |
| keyValArr = append(keyValArr, keyVal) |
| } |
| } |
| |
| if len(keyValArr) > 0 { |
| pag.Parameters = keyValArr |
| } |
| return pag, nil |
| } |
| |
| func (dm *YAMLParser) ComposeSequences(namespace string, mani *ManifestYAML) ([]utils.ActionRecord, error) { |
| var s1 []utils.ActionRecord = make([]utils.ActionRecord, 0) |
| for key, sequence := range mani.Package.Sequences { |
| wskaction := new(whisk.Action) |
| wskaction.Exec = new(whisk.Exec) |
| wskaction.Exec.Kind = "sequence" |
| actionList := strings.Split(sequence.Actions, ",") |
| |
| var components []string |
| for _, a := range actionList { |
| |
| act := strings.TrimSpace(a) |
| |
| if !strings.HasPrefix(act, mani.Package.Packagename+"/") { |
| act = path.Join(mani.Package.Packagename, act) |
| } |
| components = append(components, path.Join("/"+namespace, act)) |
| } |
| |
| wskaction.Exec.Components = components |
| wskaction.Name = key |
| pub := false |
| wskaction.Publish = &pub |
| wskaction.Namespace = namespace |
| |
| record := utils.ActionRecord{wskaction, mani.Package.Packagename, key} |
| s1 = append(s1, record) |
| } |
| return s1, nil |
| } |
| |
| func (dm *YAMLParser) ComposeActions(mani *ManifestYAML, manipath string) ([]utils.ActionRecord, error) { |
| |
| var s1 []utils.ActionRecord = make([]utils.ActionRecord, 0) |
| |
| for key, action := range mani.Package.Actions { |
| splitmanipath := strings.Split(manipath, string(os.PathSeparator)) |
| |
| wskaction := new(whisk.Action) |
| wskaction.Exec = new(whisk.Exec) |
| |
| if action.Location != "" { |
| filePath := strings.TrimRight(manipath, splitmanipath[len(splitmanipath)-1]) + action.Location |
| action.Location = filePath |
| dat, err := utils.Read(filePath) |
| utils.Check(err) |
| code := string(dat) |
| wskaction.Exec.Code = &code |
| |
| ext := path.Ext(filePath) |
| kind := "nodejs:default" |
| |
| switch ext { |
| case ".swift": |
| kind = "swift:default" |
| case ".js": |
| kind = "nodejs:default" |
| case ".py": |
| kind = "python" |
| } |
| |
| wskaction.Exec.Kind = kind |
| } |
| |
| if action.Runtime != "" { |
| wskaction.Exec.Kind = action.Runtime |
| } |
| |
| keyValArr := make(whisk.KeyValueArr, 0) |
| for name, param := range action.Inputs { |
| var keyVal whisk.KeyValue |
| keyVal.Key = name |
| |
| keyVal.Value = ResolveParameter(¶m) |
| |
| if keyVal.Value != nil { |
| keyValArr = append(keyValArr, keyVal) |
| } |
| } |
| |
| if len(keyValArr) > 0 { |
| wskaction.Parameters = keyValArr |
| } |
| |
| keyValArr = make(whisk.KeyValueArr, 0) |
| for name, value := range action.Annotations { |
| var keyVal whisk.KeyValue |
| keyVal.Key = name |
| keyVal.Value = utils.GetEnvVar(value) |
| |
| keyValArr = append(keyValArr, keyVal) |
| } |
| |
| if len(keyValArr) > 0 { |
| wskaction.Annotations = keyValArr |
| } |
| |
| wskaction.Name = key |
| pub := false |
| wskaction.Publish = &pub |
| |
| record := utils.ActionRecord{wskaction, mani.Package.Packagename, action.Location} |
| s1 = append(s1, record) |
| } |
| |
| return s1, nil |
| |
| } |
| |
| func (dm *YAMLParser) ComposeTriggers(manifest *ManifestYAML) ([]*whisk.Trigger, error) { |
| |
| var t1 []*whisk.Trigger = make([]*whisk.Trigger, 0) |
| pkg := manifest.Package |
| for _, trigger := range pkg.GetTriggerList() { |
| wsktrigger := new(whisk.Trigger) |
| wsktrigger.Name = trigger.Name |
| wsktrigger.Namespace = trigger.Namespace |
| pub := false |
| wsktrigger.Publish = &pub |
| |
| keyValArr := make(whisk.KeyValueArr, 0) |
| if trigger.Source != "" { |
| var keyVal whisk.KeyValue |
| |
| keyVal.Key = "feed" |
| keyVal.Value = trigger.Source |
| |
| keyValArr = append(keyValArr, keyVal) |
| |
| wsktrigger.Annotations = keyValArr |
| } |
| |
| keyValArr = make(whisk.KeyValueArr, 0) |
| for name, param := range trigger.Inputs { |
| var keyVal whisk.KeyValue |
| keyVal.Key = name |
| |
| keyVal.Value = ResolveParameter(¶m) |
| |
| if keyVal.Value != nil { |
| keyValArr = append(keyValArr, keyVal) |
| } |
| } |
| |
| if len(keyValArr) > 0 { |
| wsktrigger.Parameters = keyValArr |
| } |
| |
| t1 = append(t1, wsktrigger) |
| } |
| return t1, nil |
| } |
| |
| func (dm *YAMLParser) ComposeRules(manifest *ManifestYAML) ([]*whisk.Rule, error) { |
| |
| var r1 []*whisk.Rule = make([]*whisk.Rule, 0) |
| pkg := manifest.Package |
| for _, rule := range pkg.GetRuleList() { |
| wskrule := rule.ComposeWskRule() |
| r1 = append(r1, wskrule) |
| } |
| |
| return r1, nil |
| } |
| |
| func (action *Action) ComposeWskAction(manipath string) (*whisk.Action, error) { |
| wskaction, err := utils.CreateActionFromFile(manipath, action.Location) |
| utils.Check(err) |
| wskaction.Name = action.Name |
| wskaction.Version = action.Version |
| wskaction.Namespace = action.Namespace |
| return wskaction, err |
| } |
| |
| // Resolve parameter input |
| func ResolveParameter(param *Parameter) interface{} { |
| value := utils.GetEnvVar(param.Value) |
| |
| typ := param.Type |
| if str, ok := value.(string); ok && (len(typ) == 0 || typ != "string") { |
| var parsed interface{} |
| err := json.Unmarshal([]byte(str), &parsed) |
| if err == nil { |
| return parsed |
| } |
| } |
| return value |
| } |
| |
| // Provide custom Parameter marshalling and unmarshalling |
| |
| type ParsedParameter Parameter |
| |
| func (n *Parameter) UnmarshalYAML(unmarshal func(interface{}) error) error { |
| var aux ParsedParameter |
| if err := unmarshal(&aux); err == nil { |
| n.Type = aux.Type |
| n.Description = aux.Description |
| n.Value = aux.Value |
| n.Required = aux.Required |
| n.Default = aux.Default |
| n.Status = aux.Status |
| n.Schema = aux.Schema |
| return nil |
| } |
| |
| var inline interface{} |
| if err := unmarshal(&inline); err != nil { |
| return err |
| } |
| |
| n.Value = inline |
| return nil |
| } |
| |
| func (n *Parameter) MarshalYAML() (interface{}, error) { |
| if _, ok := n.Value.(string); len(n.Type) == 0 && len(n.Description) == 0 && ok { |
| if !n.Required && len(n.Status) == 0 && n.Schema == nil { |
| return n.Value.(string), nil |
| } |
| } |
| |
| return n, nil |
| } |