github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/client/interfaces.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 "net/url" 26 "strings" 27 ) 28 29 // Plug represents the potential of a given snap to connect to a slot. 30 type Plug struct { 31 Snap string `json:"snap"` 32 Name string `json:"plug"` 33 Interface string `json:"interface,omitempty"` 34 Attrs map[string]interface{} `json:"attrs,omitempty"` 35 Apps []string `json:"apps,omitempty"` 36 Label string `json:"label,omitempty"` 37 Connections []SlotRef `json:"connections,omitempty"` 38 } 39 40 // PlugRef is a reference to a plug. 41 type PlugRef struct { 42 Snap string `json:"snap"` 43 Name string `json:"plug"` 44 } 45 46 // Slot represents a capacity offered by a snap. 47 type Slot struct { 48 Snap string `json:"snap"` 49 Name string `json:"slot"` 50 Interface string `json:"interface,omitempty"` 51 Attrs map[string]interface{} `json:"attrs,omitempty"` 52 Apps []string `json:"apps,omitempty"` 53 Label string `json:"label,omitempty"` 54 Connections []PlugRef `json:"connections,omitempty"` 55 } 56 57 // SlotRef is a reference to a slot. 58 type SlotRef struct { 59 Snap string `json:"snap"` 60 Name string `json:"slot"` 61 } 62 63 // Interface holds information about a given interface and its instances. 64 type Interface struct { 65 Name string `json:"name,omitempty"` 66 Summary string `json:"summary,omitempty"` 67 DocURL string `json:"doc-url,omitempty"` 68 Plugs []Plug `json:"plugs,omitempty"` 69 Slots []Slot `json:"slots,omitempty"` 70 } 71 72 // InterfaceAction represents an action performed on the interface system. 73 type InterfaceAction struct { 74 Action string `json:"action"` 75 Forget bool `json:"forget,omitempty"` 76 Plugs []Plug `json:"plugs,omitempty"` 77 Slots []Slot `json:"slots,omitempty"` 78 } 79 80 // InterfaceOptions represents opt-in elements include in responses. 81 type InterfaceOptions struct { 82 Names []string 83 Doc bool 84 Plugs bool 85 Slots bool 86 Connected bool 87 } 88 89 // DisconnectOptions represents extra options for disconnect op 90 type DisconnectOptions struct { 91 Forget bool 92 } 93 94 func (client *Client) Interfaces(opts *InterfaceOptions) ([]*Interface, error) { 95 query := url.Values{} 96 if opts != nil && len(opts.Names) > 0 { 97 query.Set("names", strings.Join(opts.Names, ",")) // Return just those specific interfaces. 98 } 99 if opts != nil { 100 if opts.Doc { 101 query.Set("doc", "true") // Return documentation of each selected interface. 102 } 103 if opts.Plugs { 104 query.Set("plugs", "true") // Return plugs of each selected interface. 105 } 106 if opts.Slots { 107 query.Set("slots", "true") // Return slots of each selected interface. 108 } 109 } 110 // NOTE: Presence of "select" triggers the use of the new response format. 111 if opts != nil && opts.Connected { 112 query.Set("select", "connected") // Return just the connected interfaces. 113 } else { 114 query.Set("select", "all") // Return all interfaces. 115 } 116 var interfaces []*Interface 117 _, err := client.doSync("GET", "/v2/interfaces", query, nil, nil, &interfaces) 118 119 return interfaces, err 120 } 121 122 // performInterfaceAction performs a single action on the interface system. 123 func (client *Client) performInterfaceAction(sa *InterfaceAction) (changeID string, err error) { 124 b, err := json.Marshal(sa) 125 if err != nil { 126 return "", err 127 } 128 return client.doAsync("POST", "/v2/interfaces", nil, nil, bytes.NewReader(b)) 129 } 130 131 // Connect establishes a connection between a plug and a slot. 132 // The plug and the slot must have the same interface. 133 func (client *Client) Connect(plugSnapName, plugName, slotSnapName, slotName string) (changeID string, err error) { 134 return client.performInterfaceAction(&InterfaceAction{ 135 Action: "connect", 136 Plugs: []Plug{{Snap: plugSnapName, Name: plugName}}, 137 Slots: []Slot{{Snap: slotSnapName, Name: slotName}}, 138 }) 139 } 140 141 // Disconnect breaks the connection between a plug and a slot. 142 func (client *Client) Disconnect(plugSnapName, plugName, slotSnapName, slotName string, opts *DisconnectOptions) (changeID string, err error) { 143 return client.performInterfaceAction(&InterfaceAction{ 144 Action: "disconnect", 145 Forget: opts != nil && opts.Forget, 146 Plugs: []Plug{{Snap: plugSnapName, Name: plugName}}, 147 Slots: []Slot{{Snap: slotSnapName, Name: slotName}}, 148 }) 149 }