github.com/chipaca/snappy@v0.0.0-20210104084008-1f06296fe8ad/client/snapctl.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package client 21 22 import ( 23 "bytes" 24 "encoding/json" 25 "fmt" 26 "io" 27 "io/ioutil" 28 ) 29 30 // InternalSnapctlCmdNeedsStdin returns true if the given snapctl command 31 // needs data from stdin 32 func InternalSnapctlCmdNeedsStdin(name string) bool { 33 switch name { 34 case "fde-setup-result": 35 return true 36 default: 37 return false 38 } 39 } 40 41 // SnapCtlOptions holds the various options with which snapctl is invoked. 42 type SnapCtlOptions struct { 43 // ContextID is a string used to determine the context of this call (e.g. 44 // which context and handler should be used, etc.) 45 ContextID string `json:"context-id"` 46 47 // Args contains a list of parameters to use for this invocation. 48 Args []string `json:"args"` 49 } 50 51 // SnapCtlPostData is the data posted to the daemon /v2/snapctl endpoint 52 // TODO: this can be removed again once we no longer need to pass stdin data 53 // but instead use a real stdin stream 54 type SnapCtlPostData struct { 55 SnapCtlOptions 56 57 Stdin []byte `json:"stdin,omitempty"` 58 } 59 60 type snapctlOutput struct { 61 Stdout string `json:"stdout"` 62 Stderr string `json:"stderr"` 63 } 64 65 // RunSnapctl requests a snapctl run for the given options. 66 func (client *Client) RunSnapctl(options *SnapCtlOptions, stdin io.Reader) (stdout, stderr []byte, err error) { 67 // TODO: instead of reading all of stdin here we need to forward it to 68 // the daemon eventually 69 var stdinData []byte 70 if stdin != nil { 71 stdinData, err = ioutil.ReadAll(stdin) 72 if err != nil { 73 return nil, nil, fmt.Errorf("cannot read stdin: %v", err) 74 } 75 } 76 77 b, err := json.Marshal(SnapCtlPostData{ 78 SnapCtlOptions: *options, 79 Stdin: stdinData, 80 }) 81 if err != nil { 82 return nil, nil, fmt.Errorf("cannot marshal options: %s", err) 83 } 84 85 var output snapctlOutput 86 _, err = client.doSync("POST", "/v2/snapctl", nil, nil, bytes.NewReader(b), &output) 87 if err != nil { 88 return nil, nil, err 89 } 90 91 return []byte(output.Stdout), []byte(output.Stderr), nil 92 }