コード例 #1
0
ファイル: api.go プロジェクト: dholbach/snappy
// 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()})
}
コード例 #2
0
ファイル: api.go プロジェクト: dholbach/snappy
func (inst *snapInstruction) update() (*state.Change, error) {
	flags := snappy.DoInstallGC
	if inst.LeaveOld {
		flags = 0
	}
	state := inst.overlord.State()
	state.Lock()
	msg := fmt.Sprintf(i18n.G("Refresh %q snap"), inst.pkg)
	if inst.Channel != "stable" && inst.Channel != "" {
		msg = fmt.Sprintf(i18n.G("Refresh %q snap from %q channel"), inst.pkg, inst.Channel)
	}
	chg := state.NewChange("refresh-snap", msg)
	ts, err := snapstateUpdate(state, inst.pkg, inst.Channel, inst.userID, flags)
	if err == nil {
		chg.AddAll(ts)
	}
	state.Unlock()
	if err != nil {
		return nil, err
	}

	state.EnsureBefore(0)

	return chg, nil
}
コード例 #3
0
ファイル: api.go プロジェクト: dholbach/snappy
func (inst *snapInstruction) deactivate() (*state.Change, error) {
	state := inst.overlord.State()
	state.Lock()
	msg := fmt.Sprintf(i18n.G("Deactivate %q snap"), inst.pkg)
	chg := state.NewChange("deactivate-snap", msg)
	ts, err := snapstate.Deactivate(state, inst.pkg)
	if err == nil {
		chg.AddAll(ts)
	}
	state.Unlock()
	if err != nil {
		return nil, err
	}

	state.EnsureBefore(0)

	return chg, nil
}
コード例 #4
0
ファイル: api.go プロジェクト: dholbach/snappy
func (inst *snapInstruction) rollback() (*state.Change, error) {
	state := inst.overlord.State()
	state.Lock()
	msg := fmt.Sprintf(i18n.G("Rollback %q snap"), inst.pkg)
	chg := state.NewChange("rollback-snap", msg)
	// use previous version
	ver := ""
	ts, err := snapstate.Rollback(state, inst.pkg, ver)
	if err == nil {
		chg.AddAll(ts)
	}
	state.Unlock()
	if err != nil {
		return nil, err
	}

	state.EnsureBefore(0)

	return chg, nil
}
コード例 #5
0
ファイル: api.go プロジェクト: dholbach/snappy
func (inst *snapInstruction) remove() (*state.Change, error) {
	flags := snappy.DoRemoveGC
	if inst.LeaveOld {
		flags = 0
	}
	state := inst.overlord.State()
	state.Lock()
	msg := fmt.Sprintf(i18n.G("Remove %q snap"), inst.pkg)
	chg := state.NewChange("remove-snap", msg)
	ts, err := snapstate.Remove(state, inst.pkg, flags)
	if err == nil {
		chg.AddAll(ts)
	}
	state.Unlock()
	if err != nil {
		return nil, err
	}

	state.EnsureBefore(0)

	return chg, nil
}
コード例 #6
0
ファイル: api.go プロジェクト: dholbach/snappy
func sideloadSnap(c *Command, r *http.Request) Response {
	route := c.d.router.Get(stateChangeCmd.Path)
	if route == nil {
		return InternalError("cannot find route for change")
	}

	body := r.Body
	contentType := r.Header.Get("Content-Type")

	if !strings.HasPrefix(contentType, "multipart/") {
		return BadRequest("unknown content type: %s", contentType)
	}

	// POSTs to sideload snaps must be a multipart/form-data file upload.
	_, params, err := mime.ParseMediaType(contentType)
	if err != nil {
		return BadRequest("cannot parse POST body: %v", err)
	}

	form, err := multipart.NewReader(r.Body, params["boundary"]).ReadForm(maxReadBuflen)
	if err != nil {
		return BadRequest("cannot read POST form: %v", err)
	}

	var flags snappy.InstallFlags

	if len(form.Value["devmode"]) > 0 && form.Value["devmode"][0] == "true" {
		flags |= snappy.DeveloperMode
	}

	// form.File is a map of arrays of *FileHeader things
	// we just allow one (for now at least)
out:
	for _, v := range form.File {
		for i := range v {
			body, err = v[i].Open()
			if err != nil {
				return BadRequest("cannot open POST form file: %v", err)
			}
			defer body.Close()

			break out
		}
	}
	defer form.RemoveAll()

	tmpf, err := ioutil.TempFile("", "snapd-sideload-pkg-")
	if err != nil {
		return InternalError("cannot create temporary file: %v", err)
	}

	if _, err := io.Copy(tmpf, body); err != nil {
		os.Remove(tmpf.Name())
		return InternalError("cannot copy request into temporary file: %v", err)
	}

	snap := tmpf.Name()

	state := c.d.overlord.State()
	state.Lock()
	defer state.Unlock()

	msg := fmt.Sprintf(i18n.G("Install %q snap file"), snap)
	chg := state.NewChange("install-snap", msg)

	var userID int
	user, err := UserFromRequest(state, r)
	if err == nil {
		userID = user.ID
	} else if err != auth.ErrInvalidAuth {
		return InternalError("%v", err)
	}

	err = ensureUbuntuCore(chg, userID)
	if err == nil {
		ts, err := snapstateInstallPath(state, snap, "", flags)
		if err == nil {
			chg.AddAll(ts)
		}
	}

	go func() {
		// XXX this needs to be a task in the manager; this is a hack to keep this branch smaller
		<-chg.Ready()
		os.Remove(snap)
	}()
	if err != nil {
		return InternalError("cannot install snap file: %v", err)
	}
	state.EnsureBefore(0)

	return AsyncResponse(nil, &Meta{Change: chg.ID()})
}