Beispiel #1
0
func eventsSocket(r *http.Request, w http.ResponseWriter) error {
	listener := eventListener{}

	typeStr := r.FormValue("type")
	if typeStr == "" {
		typeStr = "logging,operation"
	}

	c, err := shared.WebsocketUpgrader.Upgrade(w, r, nil)
	if err != nil {
		return err
	}

	listener.active = make(chan bool, 1)
	listener.connection = c
	listener.id = uuid.NewRandom().String()
	listener.messageTypes = strings.Split(typeStr, ",")

	eventsLock.Lock()
	eventListeners[listener.id] = &listener
	eventsLock.Unlock()

	shared.Debugf("New events listener: %s", listener.id)

	<-listener.active

	eventsLock.Lock()
	delete(eventListeners, listener.id)
	eventsLock.Unlock()

	listener.connection.Close()
	shared.Debugf("Disconnected events listener: %s", listener.id)

	return nil
}
Beispiel #2
0
func (m *ConnPidMapper) ConnStateHandler(conn net.Conn, state http.ConnState) {
	unixConn := conn.(*net.UnixConn)
	switch state {
	case http.StateNew:
		pid, err := getPid(unixConn)
		if err != nil {
			shared.Debugf("Error getting pid for conn %s", err)
		} else {
			m.m[unixConn] = pid
		}
	case http.StateActive:
		return
	case http.StateIdle:
		return
	case http.StateHijacked:
		/*
		 * The "Hijacked" state indicates that the connection has been
		 * taken over from net/http. This is useful for things like
		 * developing websocket libraries, who want to upgrade the
		 * connection to a websocket one, and not use net/http any
		 * more. Whatever the case, we want to forget about it since we
		 * won't see it either.
		 */
		delete(m.m, unixConn)
	case http.StateClosed:
		delete(m.m, unixConn)
	default:
		shared.Debugf("Unknown state for connection %s", state)
	}
}
Beispiel #3
0
func (d *Daemon) verifyAdminPwd(password string) bool {
	value, err := dbPasswordGet(d.db)

	if err != nil {
		shared.Debugf("verifyAdminPwd: %s", err)
		return false
	}

	buff, err := hex.DecodeString(value)
	if err != nil {
		shared.Debugf("hex decode failed")
		return false
	}

	salt := buff[0:PW_SALT_BYTES]
	hash, err := scrypt.Key([]byte(password), salt, 1<<14, 8, 1, PW_HASH_BYTES)
	if err != nil {
		shared.Debugf("failed to create hash to check")
		return false
	}
	if !bytes.Equal(hash, buff[PW_SALT_BYTES:]) {
		shared.Debugf("Bad password received")
		return false
	}
	shared.Debugf("Verified the admin password")
	return true
}
Beispiel #4
0
func untar(tarball string, path string) error {
	extractArgs, _, err := detectCompression(tarball)
	if err != nil {
		return err
	}

	command := "tar"
	args := []string{}
	if !canMknod {
		// if we are running in a userns where we cannot mknod,
		// then run with a seccomp filter which turns mknod into a
		// a noop.  The container config had better know how to bind
		// mount the devices in at container start.
		args = append(args, "--exclude=dev/*")
	}
	args = append(args, "-C", path, "--numeric-owner")
	args = append(args, extractArgs...)
	args = append(args, tarball)

	output, err := exec.Command(command, args...).CombinedOutput()
	if err != nil {
		shared.Debugf("Unpacking failed")
		shared.Debugf(string(output))
		return err
	}

	return nil
}
Beispiel #5
0
func (op *operation) Connect(r *http.Request, w http.ResponseWriter) (chan error, error) {
	if op.class != operationClassWebsocket {
		return nil, fmt.Errorf("Only websocket operations can be connected")
	}

	if op.status != shared.Running {
		return nil, fmt.Errorf("Only running operations can be connected")
	}

	chanConnect := make(chan error, 1)

	op.lock.Lock()

	go func(op *operation, chanConnect chan error) {
		err := op.onConnect(op, r, w)
		if err != nil {
			chanConnect <- err

			shared.Debugf("Failed to handle %s operation: %s: %s", op.class.String(), op.id, err)
			return
		}

		chanConnect <- nil

		shared.Debugf("Handled %s operation: %s", op.class.String(), op.id)
	}(op, chanConnect)
	op.lock.Unlock()

	shared.Debugf("Connected %s operation: %s", op.class.String(), op.id)

	return chanConnect, nil
}
Beispiel #6
0
func main() {
	if err := run(); err != nil {
		// The action we take depends on the error we get.
		switch t := err.(type) {
		case *url.Error:
			shared.Debugf("url.Error caught in main(). Op: %s, URL: %s, Err: %s\n", t.Op, t.URL, t.Err)
			switch u := t.Err.(type) {
			case *net.OpError:
				shared.Debugf("Inner error type is a net.OpError: Op: %s Net: %s Addr: %s Err: %T", u.Op, u.Net, u.Addr, u.Err)
				if u.Op == "dial" && u.Net == "unix" {
					// The unix socket we are trying to conect to is refusing our connection attempt. Perhaps the server is not running?
					// Let's at least tell the user about it, since it's hard to get information on wether something is actually listening.
					fmt.Fprintf(os.Stderr, fmt.Sprintf(gettext.Gettext("Cannot connect to unix socket at %s Is the server running?\n"), u.Addr))
					os.Exit(1)
				}
			default:
				shared.Debugf("url.Error's inner Err type is %T", u)
			}
		default:
			shared.Debugf("Error caught in main: %T\n", t)
		}

		fmt.Fprintf(os.Stderr, gettext.Gettext("error: %v\n"), err)
		os.Exit(1)
	}
}
Beispiel #7
0
// RsyncSend sets up the sending half of an rsync, to recursively send the
// directory pointed to by path over the websocket.
func RsyncSend(path string, conn *websocket.Conn) error {
	cmd, dataSocket, stderr, err := rsyncSendSetup(path)
	if dataSocket != nil {
		defer dataSocket.Close()
	}
	if err != nil {
		return err
	}

	readDone, writeDone := shared.WebsocketMirror(conn, dataSocket, dataSocket)

	output, err := ioutil.ReadAll(stderr)
	if err != nil {
		shared.Debugf("problem reading rsync stderr %s", err)
	}

	if err := cmd.Wait(); err != nil {
		shared.Debugf("problem with rsync send of %s: %s: %s", path, err, string(output))
	}

	<-readDone
	<-writeDone

	return err
}
Beispiel #8
0
func removeImgWorkdir(d *Daemon, builddir string) {
	vgname, _, err := getServerConfigValue(d, "core.lvm_vg_name")
	if err != nil {
		shared.Debugf("Error checking server config: %v", err)
	}

	matches, _ := filepath.Glob(fmt.Sprintf("%s/*.lv", builddir))
	if len(matches) > 0 {
		if len(matches) > 1 {
			shared.Debugf("Unexpected - more than one .lv file in builddir. using first: %v", matches)
		}
		lvsymlink := matches[0]
		if lvpath, err := os.Readlink(lvsymlink); err != nil {
			shared.Debugf("Error reading target of symlink '%s'", lvsymlink)
		} else {
			err = shared.LVMRemoveLV(vgname, filepath.Base(lvpath))
			if err != nil {
				shared.Debugf("Error removing LV '%s': %v", lvpath, err)
			}
		}
	}

	if d.BackingFs == "btrfs" {
		/* cannot rm -rf /a if /a/b is a subvolume, so first delete subvolumes */
		/* todo: find the .btrfs file under dir */
		fnamelist, _ := shared.ReadDir(builddir)
		for _, fname := range fnamelist {
			subvol := filepath.Join(builddir, fname)
			btrfsDeleteSubvol(subvol)
		}
	}
	if remErr := os.RemoveAll(builddir); remErr != nil {
		shared.Debugf("Error deleting temporary directory: %s", remErr)
	}
}
Beispiel #9
0
func untar(tarball string, path string) error {
	extractArgs, _, err := detectCompression(tarball)
	if err != nil {
		return err
	}

	command := "tar"
	args := []string{}
	if runningInUserns {
		args = append(args, "--wildcards")
		args = append(args, "--exclude=dev/*")
		args = append(args, "--exclude=./dev/*")
		args = append(args, "--exclude=rootfs/dev/*")
		args = append(args, "--exclude=rootfs/./dev/*")
	}
	args = append(args, "-C", path, "--numeric-owner")
	args = append(args, extractArgs...)
	args = append(args, tarball)

	output, err := exec.Command(command, args...).CombinedOutput()
	if err != nil {
		shared.Debugf("Unpacking failed")
		shared.Debugf(string(output))
		return err
	}

	return nil
}
Beispiel #10
0
func rsyncWebsocket(cmd *exec.Cmd, conn *websocket.Conn) error {
	stdin, err := cmd.StdinPipe()
	if err != nil {
		return err
	}

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}

	stderr, err := cmd.StderrPipe()
	if err != nil {
		return err
	}

	if err := cmd.Start(); err != nil {
		return err
	}

	shared.WebsocketMirror(conn, stdin, stdout)
	data, err2 := ioutil.ReadAll(stderr)
	if err2 != nil {
		shared.Debugf("error reading rsync stderr: %s", err2)
		return err2
	}
	shared.Debugf("Stderr from rsync: %s", data)

	err = cmd.Wait()
	if err != nil {
		shared.Debugf("rsync recv error %s: %s", err, string(data))
	}

	return err
}
Beispiel #11
0
func untarImage(imagefname string, destpath string) error {
	compression, _, err := detectCompression(imagefname)
	if err != nil {
		return err
	}

	args := []string{"-C", destpath, "--numeric-owner"}
	switch compression {
	case COMPRESSION_TAR:
		args = append(args, "-xf")
	case COMPRESSION_GZIP:
		args = append(args, "-zxf")
	case COMPRESSION_BZ2:
		args = append(args, "--jxf")
	case COMPRESSION_LZMA:
		args = append(args, "--lzma", "-xf")
	default:
		args = append(args, "-Jxf")
	}
	args = append(args, imagefname)

	output, err := exec.Command("tar", args...).CombinedOutput()
	if err != nil {
		shared.Debugf("image unpacking failed\n")
		shared.Debugf(string(output))
		return err
	}

	return nil
}
Beispiel #12
0
func deviceTaskScheduler(d *Daemon) {
	chHotplug, err := deviceMonitorProcessors()
	if err != nil {
		shared.Log.Error("scheduler: couldn't setup uevent watcher, no automatic re-balance")
		return
	}

	shared.Debugf("Scheduler: doing initial balance")
	deviceTaskBalance(d)

	for {
		select {
		case e := <-chHotplug:
			if len(e) != 2 {
				shared.Log.Error("Scheduler: received an invalid hotplug event")
				continue
			}
			shared.Debugf("Scheduler: %s is now %s: re-balancing", e[0], e[1])
			deviceTaskBalance(d)
		case e := <-deviceSchedRebalance:
			if len(e) != 3 {
				shared.Log.Error("Scheduler: received an invalid rebalance event")
				continue
			}
			shared.Debugf("Scheduler: %s %s %s: re-balancing", e[0], e[1], e[2])
			deviceTaskBalance(d)
		}
	}
}
Beispiel #13
0
func (d *Daemon) verifyAdminPwd(password string) bool {
	q := "SELECT value FROM config WHERE key=\"core.trust_password\""
	value := ""
	argIn := []interface{}{}
	argOut := []interface{}{&value}
	err := dbQueryRowScan(d.db, q, argIn, argOut)

	if err != nil || value == "" {
		shared.Debugf("verifyAdminPwd: no password is set")
		return false
	}

	buff, err := hex.DecodeString(value)
	if err != nil {
		shared.Debugf("hex decode failed")
		return false
	}

	salt := buff[0:PW_SALT_BYTES]
	hash, err := scrypt.Key([]byte(password), salt, 1<<14, 8, 1, PW_HASH_BYTES)
	if err != nil {
		shared.Debugf("failed to create hash to check")
		return false
	}
	if !bytes.Equal(hash, buff[PW_SALT_BYTES:]) {
		shared.Debugf("Bad password received")
		return false
	}
	shared.Debugf("Verified the admin password")
	return true
}
Beispiel #14
0
func deviceEventListener(d *Daemon) {
	chNetlink, err := deviceNetlinkListener()
	if err != nil {
		shared.Log.Error("scheduler: couldn't setup netlink listener")
		return
	}

	for {
		select {
		case e := <-chNetlink:
			if len(e) != 3 {
				shared.Log.Error("Scheduler: received an invalid hotplug event")
				continue
			}

			if e[0] == "cpu" {
				shared.Debugf("Scheduler: %s: %s is now %s: re-balancing", e[0], e[1], e[2])
				deviceTaskBalance(d)
			}

			if e[0] == "net" && e[2] == "add" {
				shared.Debugf("Scheduler: %s: %s has been added: updating network priorities", e[0], e[1])
				deviceNetworkPriority(d, e[1])
			}
		case e := <-deviceSchedRebalance:
			if len(e) != 3 {
				shared.Log.Error("Scheduler: received an invalid rebalance event")
				continue
			}
			shared.Debugf("Scheduler: %s %s %s: re-balancing", e[0], e[1], e[2])
			deviceTaskBalance(d)
		}
	}
}
Beispiel #15
0
func pruneExpiredImages(d *Daemon) {
	shared.Debugf("Pruning expired images")
	expiry, err := d.ConfigValueGet("images.remote_cache_expiry")
	if err != nil {
		shared.Log.Error("Unable to read the images.remote_cache_expiry key")
		return
	}

	if expiry == "" {
		expiry = "10"
	}

	expiryInt, err := strconv.Atoi(expiry)
	if err != nil {
		shared.Log.Error("Invalid value for images.remote_cache_expiry", log.Ctx{"err": err})
		return
	}

	images, err := dbImagesGetExpired(d.db, expiryInt)
	if err != nil {
		shared.Log.Error("Unable to retrieve the list of expired images", log.Ctx{"err": err})
		return
	}

	for _, fp := range images {
		if err := doDeleteImage(d, fp); err != nil {
			shared.Log.Error("Error deleting image", log.Ctx{"err": err, "fp": fp})
		}
	}
	shared.Debugf("Done pruning expired images")
}
Beispiel #16
0
func containersPost(d *Daemon, r *http.Request) Response {
	shared.Debugf("Responding to container create")

	req := containerPostReq{}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		return BadRequest(err)
	}

	if req.Name == "" {
		req.Name = strings.ToLower(petname.Generate(2, "-"))
		shared.Debugf("No name provided, creating %s", req.Name)
	}

	if strings.Contains(req.Name, shared.SnapshotDelimiter) {
		return BadRequest(fmt.Errorf("Invalid container name: '%s' is reserved for snapshots", shared.SnapshotDelimiter))
	}

	switch req.Source.Type {
	case "image":
		return createFromImage(d, &req)
	case "none":
		return createFromNone(d, &req)
	case "migration":
		return createFromMigration(d, &req)
	case "copy":
		return createFromCopy(d, &req)
	default:
		return BadRequest(fmt.Errorf("unknown source type %s", req.Source.Type))
	}

}
Beispiel #17
0
func containersPost(d *Daemon, r *http.Request) Response {
	shared.Debugf("responding to create")

	if d.IdmapSet == nil {
		return BadRequest(fmt.Errorf("shared's user has no subuids"))
	}

	req := containerPostReq{}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		return BadRequest(err)
	}

	if req.Name == "" {
		req.Name = strings.ToLower(petname.Generate(2, "-"))
		shared.Debugf("no name provided, creating %s", req.Name)
	}

	switch req.Source.Type {
	case "image":
		return createFromImage(d, &req)
	case "none":
		return createFromNone(d, &req)
	case "migration":
		return createFromMigration(d, &req)
	case "copy":
		return createFromCopy(d, &req)
	default:
		return BadRequest(fmt.Errorf("unknown source type %s", req.Source.Type))
	}

}
Beispiel #18
0
func imageDelete(d *Daemon, r *http.Request) Response {
	fingerprint := mux.Vars(r)["fingerprint"]

	imgInfo, err := dbImageGet(d.db, fingerprint, false)
	if err != nil {
		return SmartError(err)
	}

	fname := shared.VarPath("images", imgInfo.Fingerprint)
	err = os.Remove(fname)
	if err != nil {
		shared.Debugf("Error deleting image file %s: %s\n", fname, err)
	}

	fmetaname := shared.VarPath("images", imgInfo.Fingerprint+".rootfs")
	if shared.PathExists(fmetaname) {
		err = os.Remove(fmetaname)
		if err != nil {
			shared.Debugf("Error deleting image file %s: %s\n", fmetaname, err)
		}
	}

	vgname, vgnameIsSet, err := getServerConfigValue(d, "core.lvm_vg_name")
	if err != nil {
		return InternalError(fmt.Errorf("Error checking server config: %v", err))
	}

	if vgnameIsSet {
		err = shared.LVMRemoveLV(vgname, imgInfo.Fingerprint)
		if err != nil {
			return InternalError(fmt.Errorf("Failed to remove deleted image LV: %v", err))
		}

		lvsymlink := fmt.Sprintf("%s.lv", fname)
		err = os.Remove(lvsymlink)
		if err != nil {
			return InternalError(fmt.Errorf("Failed to remove symlink to deleted image LV: '%s': %v", lvsymlink, err))
		}
	} else if d.BackingFs == "btrfs" {
		subvol := fmt.Sprintf("%s.btrfs", fname)
		btrfsDeleteSubvol(subvol)
	}

	tx, err := dbBegin(d.db)
	if err != nil {
		return InternalError(err)
	}

	_, _ = tx.Exec("DELETE FROM images_aliases WHERE image_id=?", imgInfo.Id)
	_, _ = tx.Exec("DELETE FROM images_properties WHERE image_id?", imgInfo.Id)
	_, _ = tx.Exec("DELETE FROM images WHERE id=?", imgInfo.Id)

	if err := txCommit(tx); err != nil {
		return InternalError(err)
	}

	return EmptySyncResponse
}
Beispiel #19
0
/*
 * Export the container to a unshifted tarfile containing:
 * dir/
 *     metadata.yaml
 *     rootfs/
 */
func (c *containerLXD) ExportToTar(snap string, w io.Writer) error {
	if snap == "" && c.IsRunning() {
		return fmt.Errorf("Cannot export a running container as image")
	}

	idmap, err := c.LastIdmapSetGet()
	if err != nil {
		return err
	}

	if idmap != nil {
		if err := idmap.UnshiftRootfs(c.RootfsPathGet()); err != nil {
			return err
		}

		defer idmap.ShiftRootfs(c.RootfsPathGet())
	}

	tw := tar.NewWriter(w)

	// keep track of the first path we saw for each path with nlink>1
	linkmap := map[uint64]string{}

	cDir := c.PathGet("")

	// Path inside the tar image is the pathname starting after cDir
	offset := len(cDir) + 1

	writeToTar := func(path string, fi os.FileInfo, err error) error {
		if err := c.tarStoreFile(linkmap, offset, tw, path, fi); err != nil {
			shared.Debugf("Error tarring up %s: %s", path, err)
			return err
		}
		return nil
	}

	fnam := filepath.Join(cDir, "metadata.yaml")
	if shared.PathExists(fnam) {
		fi, err := os.Lstat(fnam)
		if err != nil {
			shared.Debugf("Error statting %s during exportToTar", fnam)
			tw.Close()
			return err
		}
		if err := c.tarStoreFile(linkmap, offset, tw, fnam, fi); err != nil {
			shared.Debugf("Error writing to tarfile: %s", err)
			tw.Close()
			return err
		}
	}
	fnam = filepath.Join(cDir, "rootfs")
	filepath.Walk(fnam, writeToTar)
	fnam = filepath.Join(cDir, "templates")
	if shared.PathExists(fnam) {
		filepath.Walk(fnam, writeToTar)
	}
	return tw.Close()
}
Beispiel #20
0
func activateIfNeeded() error {
	// Don't start a full daemon, we just need DB access
	d := &Daemon{
		IsMock:                false,
		imagesDownloading:     map[string]chan bool{},
		imagesDownloadingLock: sync.RWMutex{},
	}

	err := initializeDbObject(d, shared.VarPath("lxd.db"))
	if err != nil {
		return err
	}

	// Look for network socket
	value, err := d.ConfigValueGet("core.https_address")
	if err != nil {
		return err
	}

	if value != "" {
		shared.Debugf("Daemon has core.https_address set, activating...")
		_, err := lxd.NewClient(&lxd.DefaultConfig, "local")
		return err
	}

	// Look for auto-started or previously started containers
	d.IdmapSet, err = shared.DefaultIdmapSet()
	if err != nil {
		return err
	}

	result, err := dbContainersList(d.db, cTypeRegular)
	if err != nil {
		return err
	}

	for _, name := range result {
		c, err := containerLoadByName(d, name)
		if err != nil {
			return err
		}

		config := c.ExpandedConfig()
		lastState := config["volatile.last_state.power"]
		autoStart := config["boot.autostart"]

		if lastState == "RUNNING" || lastState == "Running" || autoStart == "true" {
			shared.Debugf("Daemon has auto-started containers, activating...")
			_, err := lxd.NewClient(&lxd.DefaultConfig, "local")
			return err
		}
	}

	shared.Debugf("No need to start the daemon now.")
	return nil
}
Beispiel #21
0
func (c *Client) Finger() error {
	shared.Debugf("Fingering the daemon")
	_, err := c.GetServerConfig()
	if err != nil {
		return err
	}

	shared.Debugf("Pong received")
	return nil
}
Beispiel #22
0
func (d *Daemon) CheckTrustState(cert x509.Certificate) bool {
	for k, v := range d.clientCerts {
		if bytes.Compare(cert.Raw, v.Raw) == 0 {
			shared.Debugf("found cert for %s", k)
			return true
		}
		shared.Debugf("client cert != key for %s", k)
	}
	return false
}
Beispiel #23
0
func containerReplaceConfig(d *Daemon, ct *lxdContainer, name string, newConfig containerConfigReq) error {

	/* check to see that the config actually applies to the container
	 * successfully before saving it. in particular, raw.lxc and
	 * raw.apparmor need to be parsed once to make sure they make sense.
	 */
	if err := ct.applyConfig(newConfig.Config, false); err != nil {
		return err
	}

	tx, err := shared.DbBegin(d.db)
	if err != nil {
		return err
	}

	/* Update config or profiles */
	if err = dbClearContainerConfig(tx, ct.id); err != nil {
		shared.Debugf("Error clearing configuration for container %s\n", name)
		tx.Rollback()
		return err
	}

	if err = dbInsertContainerConfig(tx, ct.id, newConfig.Config); err != nil {
		shared.Debugf("Error inserting configuration for container %s\n", name)
		tx.Rollback()
		return err
	}

	/* handle profiles */
	if emptyProfile(newConfig.Profiles) {
		_, err := tx.Exec("DELETE from containers_profiles where container_id=?", ct.id)
		if err != nil {
			tx.Rollback()
			return err
		}
	} else {
		if err := dbInsertProfiles(tx, ct.id, newConfig.Profiles); err != nil {

			tx.Rollback()
			return err
		}
	}

	err = AddDevices(tx, "container", ct.id, newConfig.Devices)
	if err != nil {
		tx.Rollback()
		return err
	}

	return shared.TxCommit(tx)
}
Beispiel #24
0
func btrfsDeleteSubvol(subvol string) error {
	if err := btrfsCmdIsInstalled(); err != nil {
		return err
	}

	output, err := exec.Command("btrfs", "subvolume", "delete", subvol).CombinedOutput()
	if err != nil {
		shared.Debugf("btrfs subvolume delete %s failed\n", subvol)
		shared.Debugf(string(output))
		return err
	}

	return nil
}
Beispiel #25
0
func (op *operation) Run() (chan error, error) {
	if op.status != shared.Pending {
		return nil, fmt.Errorf("Only pending operations can be started")
	}

	chanRun := make(chan error, 1)

	op.lock.Lock()
	op.status = shared.Running

	if op.onRun != nil {
		go func(op *operation, chanRun chan error) {
			err := op.onRun(op)
			if err != nil {
				op.lock.Lock()
				op.status = shared.Failure
				op.err = SmartError(err).String()
				op.lock.Unlock()
				op.done()
				chanRun <- err

				shared.Debugf("Failure for %s operation: %s: %s", op.class.String(), op.id, err)

				_, md, _ := op.Render()
				eventSend("operation", md)
				return
			}

			op.lock.Lock()
			op.status = shared.Success
			op.lock.Unlock()
			op.done()
			chanRun <- nil

			op.lock.Lock()
			shared.Debugf("Success for %s operation: %s", op.class.String(), op.id)
			_, md, _ := op.Render()
			eventSend("operation", md)
			op.lock.Unlock()
		}(op, chanRun)
	}
	op.lock.Unlock()

	shared.Debugf("Started %s operation: %s", op.class.String(), op.id)
	_, md, _ := op.Render()
	eventSend("operation", md)

	return chanRun, nil
}
Beispiel #26
0
func txCommit(tx *sql.Tx) error {
	for {
		err := tx.Commit()
		if err == nil {
			return nil
		}
		if !isDbLockedError(err) {
			shared.Debugf("Txcommit: error %q\n", err)
			return err
		}
		shared.Debugf("Txcommit: db was locked\n")
		shared.PrintStack()
		time.Sleep(1 * time.Second)
	}
}
Beispiel #27
0
func makeBtrfsSubvol(imagefname, subvol string) error {
	output, err := exec.Command("btrfs", "subvolume", "create", subvol).CombinedOutput()
	if err != nil {
		shared.Debugf("btrfs subvolume creation failed\n")
		shared.Debugf(string(output))
		return err
	}

	err = untarImage(imagefname, subvol)
	if err != nil {
		return err
	}

	return nil
}
Beispiel #28
0
func dbQueryRowScan(db *sql.DB, q string, args []interface{}, outargs []interface{}) error {
	for {
		err := db.QueryRow(q, args...).Scan(outargs...)
		if err == nil {
			return nil
		}
		if !isDbLockedError(err) {
			shared.Debugf("DbQuery: query %q error %q\n", q, err)
			return err
		}
		shared.Debugf("DbQueryRowScan: query %q args %q, DB was locked\n", q, args)
		shared.PrintStack()
		time.Sleep(1 * time.Second)
	}
}
Beispiel #29
0
/*
 * . q is the database query
 * . inargs is an array of interfaces containing the query arguments
 * . outfmt is an array of interfaces containing the right types of output
 *   arguments, i.e.
 *      var arg1 string
 *      var arg2 int
 *      outfmt := {}interface{}{arg1, arg2}
 *
 * The result will be an array (one per output row) of arrays (one per output argument)
 * of interfaces, containing pointers to the actual output arguments.
 */
func dbQueryScan(db *sql.DB, q string, inargs []interface{}, outfmt []interface{}) ([][]interface{}, error) {
	for {
		result, err := doDbQueryScan(db, q, inargs, outfmt)
		if err == nil {
			return result, nil
		}
		if !isDbLockedError(err) {
			shared.Debugf("DbQuery: query %q error %q\n", q, err)
			return nil, err
		}
		shared.Debugf("DbQueryscan: query %q inargs %q, DB was locked\n", q, inargs)
		shared.PrintStack()
		time.Sleep(1 * time.Second)
	}
}
Beispiel #30
0
func dbExec(db *sql.DB, q string, args ...interface{}) (sql.Result, error) {
	for {
		result, err := db.Exec(q, args...)
		if err == nil {
			return result, nil
		}
		if !isDbLockedError(err) {
			shared.Debugf("DbExec: query %q error %q\n", q, err)
			return nil, err
		}
		shared.Debugf("DbExec: query %q args %q, DB was locked\n", q, args)
		shared.PrintStack()
		time.Sleep(1 * time.Second)
	}
}