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  }