gitee.com/mysnapcore/mysnapd@v0.1.0/daemon/api_aliases.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2015-2020 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 daemon 21 22 import ( 23 "encoding/json" 24 "errors" 25 "fmt" 26 "net/http" 27 28 "gitee.com/mysnapcore/mysnapd/i18n" 29 "gitee.com/mysnapcore/mysnapd/overlord/auth" 30 "gitee.com/mysnapcore/mysnapd/overlord/snapstate" 31 "gitee.com/mysnapcore/mysnapd/overlord/state" 32 "gitee.com/mysnapcore/mysnapd/snap" 33 ) 34 35 var ( 36 aliasesCmd = &Command{ 37 Path: "/v2/aliases", 38 GET: getAliases, 39 POST: changeAliases, 40 ReadAccess: openAccess{}, 41 WriteAccess: authenticatedAccess{}, 42 } 43 ) 44 45 // aliasAction is an action performed on aliases 46 type aliasAction struct { 47 Action string `json:"action"` 48 Snap string `json:"snap"` 49 App string `json:"app"` 50 Alias string `json:"alias"` 51 // old now unsupported api 52 Aliases []string `json:"aliases"` 53 } 54 55 func changeAliases(c *Command, r *http.Request, user *auth.UserState) Response { 56 var a aliasAction 57 decoder := json.NewDecoder(r.Body) 58 if err := decoder.Decode(&a); err != nil { 59 return BadRequest("cannot decode request body into an alias action: %v", err) 60 } 61 if len(a.Aliases) != 0 { 62 return BadRequest("cannot interpret request, snaps can no longer be expected to declare their aliases") 63 } 64 65 var taskset *state.TaskSet 66 var err error 67 68 st := c.d.overlord.State() 69 st.Lock() 70 defer st.Unlock() 71 72 switch a.Action { 73 default: 74 return BadRequest("unsupported alias action: %q", a.Action) 75 case "alias": 76 taskset, err = snapstate.Alias(st, a.Snap, a.App, a.Alias) 77 case "unalias": 78 if a.Alias == a.Snap { 79 // Do What I mean: 80 // check if a snap is referred/intended 81 // or just an alias 82 var snapst snapstate.SnapState 83 err := snapstate.Get(st, a.Snap, &snapst) 84 if err != nil && !errors.Is(err, state.ErrNoState) { 85 return InternalError("%v", err) 86 } 87 if errors.Is(err, state.ErrNoState) { // not a snap 88 a.Snap = "" 89 } 90 } 91 if a.Snap != "" { 92 a.Alias = "" 93 taskset, err = snapstate.DisableAllAliases(st, a.Snap) 94 } else { 95 taskset, a.Snap, err = snapstate.RemoveManualAlias(st, a.Alias) 96 } 97 case "prefer": 98 taskset, err = snapstate.Prefer(st, a.Snap) 99 } 100 if err != nil { 101 return errToResponse(err, nil, BadRequest, "%v") 102 } 103 104 var summary string 105 switch a.Action { 106 case "alias": 107 summary = fmt.Sprintf(i18n.G("Setup alias %q => %q for snap %q"), a.Alias, a.App, a.Snap) 108 case "unalias": 109 if a.Alias != "" { 110 summary = fmt.Sprintf(i18n.G("Remove manual alias %q for snap %q"), a.Alias, a.Snap) 111 } else { 112 summary = fmt.Sprintf(i18n.G("Disable all aliases for snap %q"), a.Snap) 113 } 114 case "prefer": 115 summary = fmt.Sprintf(i18n.G("Prefer aliases of snap %q"), a.Snap) 116 } 117 118 change := newChange(st, a.Action, summary, []*state.TaskSet{taskset}, []string{a.Snap}) 119 st.EnsureBefore(0) 120 121 return AsyncResponse(nil, change.ID()) 122 } 123 124 type aliasStatus struct { 125 Command string `json:"command"` 126 Status string `json:"status"` 127 Manual string `json:"manual,omitempty"` 128 Auto string `json:"auto,omitempty"` 129 } 130 131 // getAliases produces a response with a map snap -> alias -> aliasStatus 132 func getAliases(c *Command, r *http.Request, user *auth.UserState) Response { 133 state := c.d.overlord.State() 134 state.Lock() 135 defer state.Unlock() 136 137 res := make(map[string]map[string]aliasStatus) 138 139 allStates, err := snapstate.All(state) 140 if err != nil { 141 return InternalError("cannot list local snaps: %v", err) 142 } 143 144 for snapName, snapst := range allStates { 145 if err != nil { 146 return InternalError("cannot retrieve info for snap %q: %v", snapName, err) 147 } 148 if len(snapst.Aliases) != 0 { 149 snapAliases := make(map[string]aliasStatus) 150 res[snapName] = snapAliases 151 autoDisabled := snapst.AutoAliasesDisabled 152 for alias, aliasTarget := range snapst.Aliases { 153 aliasStatus := aliasStatus{ 154 Manual: aliasTarget.Manual, 155 Auto: aliasTarget.Auto, 156 } 157 status := "auto" 158 tgt := aliasTarget.Effective(autoDisabled) 159 if tgt == "" { 160 status = "disabled" 161 tgt = aliasTarget.Auto 162 } else if aliasTarget.Manual != "" { 163 status = "manual" 164 } 165 aliasStatus.Status = status 166 aliasStatus.Command = snap.JoinSnapApp(snapName, tgt) 167 snapAliases[alias] = aliasStatus 168 } 169 } 170 } 171 172 return SyncResponse(res) 173 }