Skip to content
This repository has been archived by the owner on Sep 14, 2019. It is now read-only.

Commit

Permalink
[medium] move compression apply into client package
Browse files Browse the repository at this point in the history
  • Loading branch information
Aaron Meihm committed Jan 22, 2016
1 parent 853d722 commit 1d73fab
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 34 deletions.
43 changes: 39 additions & 4 deletions action.go
Expand Up @@ -84,10 +84,13 @@ type Operation struct {
Module string `json:"module"`
Parameters interface{} `json:"parameters"`

// If IsCompressed is true, Parameters is a base64 encoded gzip
// stream of the marshaled parameters. If false, Parameters is
// JSON parameter data.
IsCompressed bool `json:"is_compressed"`
// If WantCompressed is set in the operation, the parameters
// will be compressed in PostAction() when the client sends the
// action to the API. This will also result in IsCompressed being
// marked as true, so the receiving agent knows it must decompress
// the parameter data.
IsCompressed bool `json:"is_compressed,omitempty"`
WantCompressed bool `json:"want_compressed,omitempty"`
}

// Compress the parameters stored within an operation
Expand Down Expand Up @@ -115,6 +118,38 @@ func (op *Operation) CompressOperationParam() (err error) {
return
}

// Decompress the parameters stored within an operation
func (op *Operation) DecompressOperationParam() (err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("DecompressOperationParam() -> %v", e)
}
}()
if !op.IsCompressed {
return nil
}
pstr, ok := op.Parameters.(string)
if !ok {
panic("Compressed parameter was not a string")
}
b := bytes.NewBuffer([]byte(pstr))
rb64 := base64.NewDecoder(base64.StdEncoding, b)
r, err := gzip.NewReader(rb64)
if err != nil {
panic(err)
}
rb, err := ioutil.ReadAll(r)
if err != nil {
panic(err)
}
err = json.Unmarshal(rb, &op.Parameters)
if err != nil {
panic(err)
}
op.IsCompressed = false
return
}

// ActionFromFile() reads an action from a local file on the file system
// and returns a mig.Action structure
func ActionFromFile(path string) (Action, error) {
Expand Down
27 changes: 27 additions & 0 deletions client/client.go
Expand Up @@ -672,6 +672,33 @@ func (cli Client) MakeSignedToken() (token string, err error) {
return
}

// CompressAction takens a MIG action, and applies compression to any operations
// within the action for which compression is requested.
//
// This function should be called on the action prior to signing it for submission
// to the API.
func (cli Client) CompressAction(a mig.Action) (comp_action mig.Action, err error) {
comp_action = a
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("CompressAction() -> %v", e)
}
}()
for i := range comp_action.Operations {
if !comp_action.Operations[i].WantCompressed {
continue
}
if comp_action.Operations[i].IsCompressed {
continue
}
err = comp_action.Operations[i].CompressOperationParam()
if err != nil {
panic(err)
}
}
return
}

// SignAction takes a MIG Action, signs it with the key identified in the configuration
// and returns the signed action
func (cli Client) SignAction(a mig.Action) (signed_action mig.Action, err error) {
Expand Down
4 changes: 4 additions & 0 deletions client/mig-action-generator/generator.go
Expand Up @@ -99,6 +99,10 @@ func main() {
a.Target = *target
}

a, err = cli.CompressAction(a)
if err != nil {
panic(err)
}
asig, err := cli.SignAction(a)
if err != nil {
panic(err)
Expand Down
78 changes: 57 additions & 21 deletions client/mig-console/action_launcher.go
Expand Up @@ -100,11 +100,7 @@ func actionLauncher(tpl mig.Action, cli client.Client) (err error) {
break
}
if paramCompression {
err = operation.CompressOperationParam()
if err != nil {
fmt.Println("Compression failed: %v\n", err)
}
break
operation.WantCompressed = true
}
a.Operations = append(a.Operations, operation)
opjson, err := json.MarshalIndent(operation, "", " ")
Expand All @@ -124,25 +120,23 @@ func actionLauncher(tpl mig.Action, cli client.Client) (err error) {
}
switch strings.ToLower(orders[1]) {
case "false":
for _, x := range a.Operations {
if x.IsCompressed {
fmt.Println("Warning: some operations have already been compressed")
fmt.Println("Restart action creation if this is not desired")
break
paramCompression = false
// Disable compression on all existing operations
for i := range a.Operations {
a.Operations[i].WantCompressed = false
err = a.Operations[i].DecompressOperationParam()
if err != nil {
panic(err)
}
}
paramCompression = false
// Invalidate any signatures applied to the action at this point
hasSignatures = false
a.PGPSignatures = nil
case "true":
paramCompression = true
// Enable compression on all existing operations
for i := range a.Operations {
if a.Operations[i].IsCompressed {
continue
}
err = a.Operations[i].CompressOperationParam()
if err != nil {
panic(err)
}
a.Operations[i].WantCompressed = true
}
default:
fmt.Println("Argument to compress must be true or false")
Expand Down Expand Up @@ -176,7 +170,7 @@ func actionLauncher(tpl mig.Action, cli client.Client) (err error) {
case "help":
fmt.Printf(`The following orders are available:
addoperation <module> append a new operation of type <module> to the action operations
compress <false|true> compress parameters in operations stored in action
compress <false|true> request parameter compression in operations stored in action
listagents list agents targetted by an action
deloperation <opnum> remove operation numbered <opnum> from operations array, count starts at zero
details display the action details
Expand All @@ -200,11 +194,15 @@ times show the various timestamps of the action
fmt.Printf("Unknown option '%s'\n", orders[1])
}
}
tmpAction, err := getActionView(a)
if err != nil {
panic(err)
}
var ajson []byte
if pack {
ajson, err = json.Marshal(a)
ajson, err = json.Marshal(tmpAction)
} else {
ajson, err = json.MarshalIndent(a, "", " ")
ajson, err = json.MarshalIndent(tmpAction, "", " ")
}
if err != nil {
panic(err)
Expand Down Expand Up @@ -260,6 +258,10 @@ times show the various timestamps of the action
hasTimes = true
}
if !hasSignatures {
a, err = cli.CompressAction(a)
if err != nil {
panic(err)
}
asig, err := cli.SignAction(a)
if err != nil {
panic(err)
Expand Down Expand Up @@ -307,6 +309,10 @@ times show the various timestamps of the action
fmt.Println("Times must be set prior to signing")
break
}
a, err = cli.CompressAction(a)
if err != nil {
panic(err)
}
asig, err := cli.SignAction(a)
if err != nil {
panic(err)
Expand Down Expand Up @@ -454,3 +460,33 @@ finish:
a.Counters.Failed, a.Counters.TimeOut, a.Counters.InFlight)
return
}

// Return a view of an action suitable for JSON display in the console; this
// function essentially strips compression from the parameters, but leaves
// other fields intact -- the output should be used for display purposes only.
func getActionView(a mig.Action) (ret mig.Action, err error) {
ret = a
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("getActionView() -> %v", e)
}
}()
// Create a copy of the original operations to modify, so we don't
// change any of the original action parameters
ret.Operations = make([]mig.Operation, len(a.Operations))
copy(ret.Operations, a.Operations)
for i := range ret.Operations {
if !ret.Operations[i].IsCompressed {
continue
}
err = ret.Operations[i].DecompressOperationParam()
if err != nil {
panic(err)
}
// Reset the IsCompressed flag, purely for visual purposes to
// indicate the parameters are compressed when the JSON is
// viewed
ret.Operations[i].IsCompressed = true
}
return
}
6 changes: 5 additions & 1 deletion client/mig-console/action_reader.go
Expand Up @@ -132,8 +132,12 @@ times show the various timestamps of the action
fmt.Println(i.Name, "- Key ID:", i.PGPFingerprint)
}
case "json":
tmpAction, err := getActionView(a)
if err != nil {
panic(err)
}
var ajson []byte
ajson, err = json.MarshalIndent(a, "", " ")
ajson, err = json.MarshalIndent(tmpAction, "", " ")
if err != nil {
panic(err)
}
Expand Down
16 changes: 8 additions & 8 deletions client/mig/main.go
Expand Up @@ -98,7 +98,7 @@ func main() {
fs.StringVar(&afile, "i", "/path/to/file", "Load action from file")
fs.BoolVar(&verbose, "v", false, "Enable verbose output")
fs.BoolVar(&showversion, "V", false, "Show version")
fs.BoolVar(&compressAction, "z", false, "Compress action before sending it to agents")
fs.BoolVar(&compressAction, "z", false, "Request compression of action parameters")

// if first argument is missing, or is help, print help
// otherwise, pass the remainder of the arguments to the module for parsing
Expand Down Expand Up @@ -184,18 +184,14 @@ func main() {
if err != nil || op.Parameters == nil {
panic(err)
}
// If compression has been enabled, replace the parameters with a
// compressed version and set the flag.
// If compression has been enabled, flag it in the operation.
if compressAction {
err = op.CompressOperationParam()
if err != nil {
panic(err)
}
op.WantCompressed = true
}
// If running against the local target, don't post the action to the MIG API
// but run it locally instead.
if target == "local" {
msg, err := modules.MakeMessage(modules.MsgClassParameters, op.Parameters, op.IsCompressed)
msg, err := modules.MakeMessage(modules.MsgClassParameters, op.Parameters, false)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -263,6 +259,10 @@ readytolaunch:
// add extra 60 seconds taken for clock skew
a.ExpireAfter = a.ExpireAfter.Add(60 * time.Second).UTC()

a, err = cli.CompressAction(a)
if err != nil {
panic(err)
}
asig, err := cli.SignAction(a)
if err != nil {
panic(err)
Expand Down
4 changes: 4 additions & 0 deletions mig-runner/entity.go
Expand Up @@ -90,6 +90,10 @@ func (e *entity) launchAction() (err error) {
// time begins in the past.
period += -window
act.ExpireAfter = act.ValidFrom.Add(period)
act, err = cli.CompressAction(act)
if err != nil {
panic(err)
}
asig, err := cli.SignAction(act)
if err != nil {
panic(err)
Expand Down

0 comments on commit 1d73fab

Please sign in to comment.