github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/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  }