Ai
1 Star 0 Fork 1

mysnapcore/mysnapd

forked from tupelo-shen/mysnapd 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
api_interfaces.go 7.68 KB
一键复制 编辑 原始数据 按行查看 历史
tupelo-shen 提交于 2022-11-08 22:56 +08:00 . fix: daemon commit
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2015-2020 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package daemon
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"sort"
"strings"
"gitee.com/mysnapcore/mysnapd/interfaces"
"gitee.com/mysnapcore/mysnapd/overlord/auth"
"gitee.com/mysnapcore/mysnapd/overlord/ifacestate"
"gitee.com/mysnapcore/mysnapd/overlord/snapstate"
"gitee.com/mysnapcore/mysnapd/overlord/state"
)
var (
interfacesCmd = &Command{
Path: "/v2/interfaces",
GET: interfacesConnectionsMultiplexer,
POST: changeInterfaces,
ReadAccess: openAccess{},
WriteAccess: authenticatedAccess{Polkit: polkitActionManageInterfaces},
}
)
// interfacesConnectionsMultiplexer multiplexes to either legacy (connection) or modern behavior (interfaces).
func interfacesConnectionsMultiplexer(c *Command, r *http.Request, user *auth.UserState) Response {
query := r.URL.Query()
qselect := query.Get("select")
if qselect == "" {
return getLegacyConnections(c, r, user)
} else {
return getInterfaces(c, r, user)
}
}
func getInterfaces(c *Command, r *http.Request, user *auth.UserState) Response {
// Collect query options from request arguments.
q := r.URL.Query()
pselect := q.Get("select")
if pselect != "all" && pselect != "connected" {
return BadRequest("unsupported select qualifier")
}
var names []string // Interface names
namesStr := q.Get("names")
if namesStr != "" {
names = strings.Split(namesStr, ",")
}
opts := &interfaces.InfoOptions{
Names: names,
Doc: q.Get("doc") == "true",
Plugs: q.Get("plugs") == "true",
Slots: q.Get("slots") == "true",
Connected: pselect == "connected",
}
// Query the interface repository (this returns []*interface.Info).
infos := c.d.overlord.InterfaceManager().Repository().Info(opts)
infoJSONs := make([]*interfaceJSON, 0, len(infos))
for _, info := range infos {
// Convert interfaces.Info into interfaceJSON
plugs := make([]*plugJSON, 0, len(info.Plugs))
for _, plug := range info.Plugs {
plugs = append(plugs, &plugJSON{
Snap: plug.Snap.InstanceName(),
Name: plug.Name,
Attrs: plug.Attrs,
Label: plug.Label,
})
}
slots := make([]*slotJSON, 0, len(info.Slots))
for _, slot := range info.Slots {
slots = append(slots, &slotJSON{
Snap: slot.Snap.InstanceName(),
Name: slot.Name,
Attrs: slot.Attrs,
Label: slot.Label,
})
}
infoJSONs = append(infoJSONs, &interfaceJSON{
Name: info.Name,
Summary: info.Summary,
DocURL: info.DocURL,
Plugs: plugs,
Slots: slots,
})
}
return SyncResponse(infoJSONs)
}
func getLegacyConnections(c *Command, r *http.Request, user *auth.UserState) Response {
connsjson, err := collectConnections(c.d.overlord.InterfaceManager(), collectFilter{})
if err != nil {
return InternalError("collecting connection information failed: %v", err)
}
legacyconnsjson := legacyConnectionsJSON{
Plugs: connsjson.Plugs,
Slots: connsjson.Slots,
}
return SyncResponse(legacyconnsjson)
}
// changeInterfaces controls the interfaces system.
// Plugs can be connected to and disconnected from slots.
func changeInterfaces(c *Command, r *http.Request, user *auth.UserState) Response {
var a interfaceAction
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&a); err != nil {
return BadRequest("cannot decode request body into an interface action: %v", err)
}
if a.Action == "" {
return BadRequest("interface action not specified")
}
if len(a.Plugs) > 1 || len(a.Slots) > 1 {
return NotImplemented("many-to-many operations are not implemented")
}
if a.Action != "connect" && a.Action != "disconnect" {
return BadRequest("unsupported interface action: %q", a.Action)
}
if len(a.Plugs) == 0 || len(a.Slots) == 0 {
return BadRequest("at least one plug and slot is required")
}
var summary string
var err error
var tasksets []*state.TaskSet
var affected []string
st := c.d.overlord.State()
st.Lock()
defer st.Unlock()
checkInstalled := func(snapName string) error {
// empty snap name is fine, ResolveConnect/ResolveDisconnect handles it.
if snapName == "" {
return nil
}
var snapst snapstate.SnapState
err := snapstate.Get(st, snapName, &snapst)
if (err == nil && !snapst.IsInstalled()) || errors.Is(err, state.ErrNoState) {
return fmt.Errorf("snap %q is not installed", snapName)
}
if err == nil {
return nil
}
return fmt.Errorf("internal error: cannot get state of snap %q: %v", snapName, err)
}
for i := range a.Plugs {
a.Plugs[i].Snap = ifacestate.RemapSnapFromRequest(a.Plugs[i].Snap)
if err := checkInstalled(a.Plugs[i].Snap); err != nil {
return errToResponse(err, nil, BadRequest, "%v")
}
}
for i := range a.Slots {
a.Slots[i].Snap = ifacestate.RemapSnapFromRequest(a.Slots[i].Snap)
if err := checkInstalled(a.Slots[i].Snap); err != nil {
return errToResponse(err, nil, BadRequest, "%v")
}
}
switch a.Action {
case "connect":
var connRef *interfaces.ConnRef
repo := c.d.overlord.InterfaceManager().Repository()
connRef, err = repo.ResolveConnect(a.Plugs[0].Snap, a.Plugs[0].Name, a.Slots[0].Snap, a.Slots[0].Name)
if err == nil {
var ts *state.TaskSet
affected = snapNamesFromConns([]*interfaces.ConnRef{connRef})
summary = fmt.Sprintf("Connect %s:%s to %s:%s", connRef.PlugRef.Snap, connRef.PlugRef.Name, connRef.SlotRef.Snap, connRef.SlotRef.Name)
ts, err = ifacestate.Connect(st, connRef.PlugRef.Snap, connRef.PlugRef.Name, connRef.SlotRef.Snap, connRef.SlotRef.Name)
if _, ok := err.(*ifacestate.ErrAlreadyConnected); ok {
change := newChange(st, a.Action+"-snap", summary, nil, affected)
change.SetStatus(state.DoneStatus)
return AsyncResponse(nil, change.ID())
}
tasksets = append(tasksets, ts)
}
case "disconnect":
var conns []*interfaces.ConnRef
summary = fmt.Sprintf("Disconnect %s:%s from %s:%s", a.Plugs[0].Snap, a.Plugs[0].Name, a.Slots[0].Snap, a.Slots[0].Name)
conns, err = c.d.overlord.InterfaceManager().ResolveDisconnect(a.Plugs[0].Snap, a.Plugs[0].Name, a.Slots[0].Snap, a.Slots[0].Name, a.Forget)
if err == nil {
if len(conns) == 0 {
return InterfacesUnchanged("nothing to do")
}
repo := c.d.overlord.InterfaceManager().Repository()
for _, connRef := range conns {
var ts *state.TaskSet
var conn *interfaces.Connection
if a.Forget {
ts, err = ifacestate.Forget(st, repo, connRef)
} else {
conn, err = repo.Connection(connRef)
if err != nil {
break
}
ts, err = ifacestate.Disconnect(st, conn)
if err != nil {
break
}
}
if err != nil {
break
}
ts.JoinLane(st.NewLane())
tasksets = append(tasksets, ts)
}
affected = snapNamesFromConns(conns)
}
}
if err != nil {
return errToResponse(err, nil, BadRequest, "%v")
}
change := newChange(st, a.Action+"-snap", summary, tasksets, affected)
st.EnsureBefore(0)
return AsyncResponse(nil, change.ID())
}
func snapNamesFromConns(conns []*interfaces.ConnRef) []string {
m := make(map[string]bool)
for _, conn := range conns {
m[conn.PlugRef.Snap] = true
m[conn.SlotRef.Snap] = true
}
l := make([]string, 0, len(m))
for name := range m {
l = append(l, name)
}
sort.Strings(l)
return l
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/mysnapcore/mysnapd.git
git@gitee.com:mysnapcore/mysnapd.git
mysnapcore
mysnapd
mysnapd
v0.1.0

搜索帮助