github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/cmd/juju/action/common.go (about) 1 // Copyright 2014-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package action 5 6 import ( 7 "github.com/juju/cmd" 8 "github.com/juju/errors" 9 "github.com/juju/loggo" 10 "github.com/juju/names" 11 "gopkg.in/yaml.v1" 12 13 "github.com/juju/juju/apiserver/params" 14 ) 15 16 var logger = loggo.GetLogger("juju.cmd.juju.action") 17 18 // displayActionResult returns any error from an ActionResult and displays 19 // its response values otherwise. 20 func displayActionResult(result params.ActionResult, ctx *cmd.Context, out cmd.Output) error { 21 if result.Error != nil { 22 return result.Error 23 } 24 25 if result.Action == nil { 26 return errors.New("action for result was nil") 27 } 28 29 output, err := yaml.Marshal(result.Output) 30 if err != nil { 31 return err 32 } 33 34 response := struct { 35 Action string 36 Target string 37 Status string 38 Message string 39 Results string 40 }{ 41 Action: result.Action.Name, 42 Target: result.Action.Receiver, 43 Status: result.Status, 44 Message: result.Message, 45 Results: string(output), 46 } 47 48 err = out.Write(ctx, response) 49 if err != nil { 50 return err 51 } 52 53 return nil 54 } 55 56 // getActionTagByPrefix uses the APIClient to get all ActionTags matching a prefix. 57 func getActionTagsByPrefix(api APIClient, prefix string) ([]names.ActionTag, error) { 58 results := []names.ActionTag{} 59 60 tags, err := api.FindActionTagsByPrefix(params.FindTags{Prefixes: []string{prefix}}) 61 if err != nil { 62 return results, err 63 } 64 65 matches, ok := tags.Matches[prefix] 66 if !ok || len(matches) < 1 { 67 return results, nil 68 } 69 70 results, rejects := getActionTags(matches) 71 if len(rejects) > 0 { 72 logger.Errorf("FindActionTagsByPrefix for prefix %q found invalid tags %v", prefix, rejects) 73 } 74 return results, nil 75 } 76 77 // getActionTagByPrefix uses the APIClient to get an ActionTag from a prefix. 78 func getActionTagByPrefix(api APIClient, prefix string) (names.ActionTag, error) { 79 tag := names.ActionTag{} 80 actiontags, err := getActionTagsByPrefix(api, prefix) 81 if err != nil { 82 return tag, err 83 } 84 85 if len(actiontags) < 1 { 86 return tag, errors.Errorf("actions for identifier %q not found", prefix) 87 } 88 89 if len(actiontags) > 1 { 90 return tag, errors.Errorf("identifier %q matched multiple actions %v", prefix, actiontags) 91 } 92 93 return actiontags[0], nil 94 } 95 96 // getActionTags converts a slice of params.Entity to a slice of names.ActionTag, and 97 // also populates a slice of strings for the params.Entity.Tag that are not a valid 98 // names.ActionTag. 99 func getActionTags(entities []params.Entity) (good []names.ActionTag, bad []string) { 100 for _, entity := range entities { 101 if tag, err := entityToActionTag(entity); err != nil { 102 bad = append(bad, entity.Tag) 103 } else { 104 good = append(good, tag) 105 } 106 } 107 return 108 } 109 110 // entityToActionTag converts the params.Entity type to a names.ActionTag 111 func entityToActionTag(entity params.Entity) (names.ActionTag, error) { 112 return names.ParseActionTag(entity.Tag) 113 } 114 115 // addValueToMap adds the given value to the map on which the method is run. 116 // This allows us to merge maps such as {foo: {bar: baz}} and {foo: {baz: faz}} 117 // into {foo: {bar: baz, baz: faz}}. 118 func addValueToMap(keys []string, value interface{}, target map[string]interface{}) { 119 next := target 120 121 for i := range keys { 122 // If we are on last key set or overwrite the val. 123 if i == len(keys)-1 { 124 next[keys[i]] = value 125 break 126 } 127 128 if iface, ok := next[keys[i]]; ok { 129 switch typed := iface.(type) { 130 case map[string]interface{}: 131 // If we already had a map inside, keep 132 // stepping through. 133 next = typed 134 default: 135 // If we didn't, then overwrite value 136 // with a map and iterate with that. 137 m := map[string]interface{}{} 138 next[keys[i]] = m 139 next = m 140 } 141 continue 142 } 143 144 // Otherwise, it wasn't present, so make it and step 145 // into. 146 m := map[string]interface{}{} 147 next[keys[i]] = m 148 next = m 149 } 150 }