github.com/rigado/snapd@v2.42.5-go-mod+incompatible/client/model.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019 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 "net/url" 27 28 "github.com/snapcore/snapd/asserts" 29 ) 30 31 type remodelData struct { 32 NewModel string `json:"new-model"` 33 } 34 35 // Remodel tries to remodel the system with the given assertion data 36 func (client *Client) Remodel(b []byte) (changeID string, err error) { 37 data, err := json.Marshal(&remodelData{ 38 NewModel: string(b), 39 }) 40 if err != nil { 41 return "", fmt.Errorf("cannot marshal remodel data: %v", err) 42 } 43 headers := map[string]string{ 44 "Content-Type": "application/json", 45 } 46 47 return client.doAsync("POST", "/v2/model", nil, headers, bytes.NewReader(data)) 48 } 49 50 // CurrentModelAssertion returns the current model assertion 51 func (client *Client) CurrentModelAssertion() (*asserts.Model, error) { 52 assert, err := currentAssertion(client, "/v2/model") 53 if err != nil { 54 return nil, err 55 } 56 modelAssert, ok := assert.(*asserts.Model) 57 if !ok { 58 return nil, fmt.Errorf("unexpected assertion type (%s) returned", assert.Type().Name) 59 } 60 return modelAssert, nil 61 } 62 63 // CurrentSerialAssertion returns the current serial assertion 64 func (client *Client) CurrentSerialAssertion() (*asserts.Serial, error) { 65 assert, err := currentAssertion(client, "/v2/model/serial") 66 if err != nil { 67 return nil, err 68 } 69 serialAssert, ok := assert.(*asserts.Serial) 70 if !ok { 71 return nil, fmt.Errorf("unexpected assertion type (%s) returned", assert.Type().Name) 72 } 73 return serialAssert, nil 74 } 75 76 // helper function for getting assertions from the daemon via a REST path 77 func currentAssertion(client *Client, path string) (asserts.Assertion, error) { 78 q := url.Values{} 79 80 response, err := client.raw("GET", path, q, nil, nil) 81 if err != nil { 82 return nil, fmt.Errorf("failed to query current assertion: %v", err) 83 } 84 defer response.Body.Close() 85 if response.StatusCode != 200 { 86 return nil, parseError(response) 87 } 88 89 dec := asserts.NewDecoder(response.Body) 90 91 // only decode a single assertion - we can't ever get more than a single 92 // assertion through these endpoints by design 93 assert, err := dec.Decode() 94 if err != nil { 95 return nil, fmt.Errorf("failed to decode assertions: %v", err) 96 } 97 98 return assert, nil 99 }