// changeInterfaces controls the interfaces system. // Plugs can be connected to and disconnected from slots. // When enableInternalInterfaceActions is true plugs and slots can also be // explicitly added and removed. func changeInterfaces(c *Command, r *http.Request) 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 !c.d.enableInternalInterfaceActions && a.Action != "connect" && a.Action != "disconnect" { return BadRequest("internal interface actions are disabled") } 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 change *state.Change var taskset *state.TaskSet var err error state := c.d.overlord.State() state.Lock() defer state.Unlock() switch a.Action { case "connect": summary := fmt.Sprintf("Connect %s:%s to %s:%s", a.Plugs[0].Snap, a.Plugs[0].Name, a.Slots[0].Snap, a.Slots[0].Name) change = state.NewChange("connect-snap", summary) taskset, err = ifacestate.Connect(state, a.Plugs[0].Snap, a.Plugs[0].Name, a.Slots[0].Snap, a.Slots[0].Name) case "disconnect": 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) change = state.NewChange("disconnect-snap", summary) taskset, err = ifacestate.Disconnect(state, a.Plugs[0].Snap, a.Plugs[0].Name, a.Slots[0].Snap, a.Slots[0].Name) } if err == nil { change.AddAll(taskset) } if err != nil { return BadRequest("%v", err) } state.EnsureBefore(0) return AsyncResponse(nil, &Meta{Change: change.ID()}) }
func installSnap(chg *state.Change, name, channel string, userID int, flags snappy.InstallFlags) error { st := chg.State() ts, err := snapstateInstall(st, name, channel, userID, flags) if err != nil { return err } // ensure that each of our task runs after the existing tasks chgts := state.NewTaskSet(chg.Tasks()...) for _, t := range ts.Tasks() { t.WaitAll(chgts) } chg.AddAll(ts) return nil }