func (d *Daemon) SetupStorageDriver() error { vgName, err := d.ConfigValueGet("core.lvm_vg_name") if err != nil { return fmt.Errorf("Couldn't read config: %s", err) } if vgName != "" { d.Storage, err = newStorage(d, storageTypeLvm) if err != nil { shared.Logf("Could not initialize storage type LVM: %s - falling back to dir", err) } else { return nil } } else if d.BackingFs == "btrfs" { d.Storage, err = newStorage(d, storageTypeBtrfs) if err != nil { shared.Logf("Could not initialize storage type btrfs: %s - falling back to dir", err) } else { return nil } } d.Storage, err = newStorage(d, storageTypeDir) return err }
func (s *storageLvm) ImageCreate(fingerprint string) error { finalName := shared.VarPath("images", fingerprint) lvpath, err := s.createThinLV(fingerprint) if err != nil { s.log.Error("LVMCreateThinLV", log.Ctx{"err": err}) return fmt.Errorf("Error Creating LVM LV for new image: %v", err) } dst := shared.VarPath("images", fmt.Sprintf("%s.lv", fingerprint)) err = os.Symlink(lvpath, dst) if err != nil { return err } tempLVMountPoint, err := ioutil.TempDir(shared.VarPath("images"), "tmp_lv_mnt") if err != nil { return err } defer func() { if err := os.RemoveAll(tempLVMountPoint); err != nil { s.log.Error("Deleting temporary LVM mount point", log.Ctx{"err": err}) } }() var fstype string fstype, err = s.d.ConfigValueGet("storage.lvm_fstype") if err != nil { return fmt.Errorf("Error checking server config, err=%v", err) } if fstype == "" { fstype = "ext4" } err = s.tryMount(lvpath, tempLVMountPoint, fstype, 0, "discard") if err != nil { shared.Logf("Error mounting image LV for untarring: %v", err) return fmt.Errorf("Error mounting image LV: %v", err) } untarErr := untarImage(finalName, tempLVMountPoint) err = s.tryUnmount(tempLVMountPoint, 0) if err != nil { s.log.Warn("could not unmount LV. Will not remove", log.Ctx{"lvpath": lvpath, "mountpoint": tempLVMountPoint, "err": err}) if untarErr == nil { return err } return fmt.Errorf( "Error unmounting '%s' during cleanup of error %v", tempLVMountPoint, untarErr) } return untarErr }
func readSavedClientCAList(d *Daemon) { d.clientCerts = []x509.Certificate{} dbCerts, err := dbCertsGet(d.db) if err != nil { shared.Logf("Error reading certificates from database: %s", err) return } for _, dbCert := range dbCerts { certBlock, _ := pem.Decode([]byte(dbCert.Certificate)) cert, err := x509.ParseCertificate(certBlock.Bytes) if err != nil { shared.Logf("Error reading certificate for %s: %s", dbCert.Name, err) continue } d.clientCerts = append(d.clientCerts, *cert) } }
func (s *storageLvm) ImageCreate(fingerprint string) error { finalName := shared.VarPath("images", fingerprint) lvpath, err := s.createThinLV(fingerprint) if err != nil { s.log.Error("LVMCreateThinLV", log.Ctx{"err": err}) return fmt.Errorf("Error Creating LVM LV for new image: %v", err) } dst := shared.VarPath("images", fmt.Sprintf("%s.lv", fingerprint)) err = os.Symlink(lvpath, dst) if err != nil { return err } tempLVMountPoint, err := ioutil.TempDir(shared.VarPath("images"), "tmp_lv_mnt") if err != nil { return err } defer func() { if err := os.RemoveAll(tempLVMountPoint); err != nil { s.log.Error("Deleting temporary LVM mount point", log.Ctx{"err": err}) } }() output, err := exec.Command( "mount", "-o", "discard", lvpath, tempLVMountPoint).CombinedOutput() if err != nil { shared.Logf("Error mounting image LV for untarring: '%s'", string(output)) return fmt.Errorf("Error mounting image LV: %v", err) } untarErr := untarImage(finalName, tempLVMountPoint) output, err = exec.Command("umount", tempLVMountPoint).CombinedOutput() if err != nil { s.log.Warn("could not unmount LV. Will not remove", log.Ctx{"lvpath": lvpath, "mountpoint": tempLVMountPoint, "err": err}) if untarErr == nil { return err } return fmt.Errorf( "Error unmounting '%s' during cleanup of error %v", tempLVMountPoint, untarErr) } return untarErr }
func readSavedClientCAList(d *Daemon) { d.clientCerts = []x509.Certificate{} rows, err := dbQuery(d.db, "SELECT fingerprint, type, name, certificate FROM certificates") if err != nil { shared.Logf("Error reading certificates from database: %s\n", err) return } defer rows.Close() for rows.Next() { var fp string var t int var name string var cf []byte rows.Scan(&fp, &t, &name, &cf) cert_block, _ := pem.Decode(cf) cert, err := x509.ParseCertificate(cert_block.Bytes) if err != nil { shared.Logf("Error reading certificate for %s: %s\n", name, err) continue } d.clientCerts = append(d.clientCerts, *cert) } }
func containersShutdown(d *Daemon) error { q := fmt.Sprintf("SELECT name FROM containers WHERE type=?") inargs := []interface{}{cTypeRegular} var name string outfmt := []interface{}{name} result, err := dbQueryScan(d.db, q, inargs, outfmt) if err != nil { return err } var wg sync.WaitGroup for _, r := range result { container, err := newLxdContainer(string(r[0].(string)), d) if err != nil { return err } if container.c.State() != lxc.STOPPED { _, err = dbExec(d.db, "UPDATE containers SET power_state=1 WHERE name=?", container.name) if err != nil { return err } wg.Add(1) go func() { container.c.Shutdown(time.Second * 30) container.c.Stop() if err = deactivateStorage(d, container); err != nil { shared.Logf("Error deactivating storage after container stop: %v", err) } wg.Done() }() } wg.Wait() } return nil }
func extractImage(hash string, name string, d *Daemon) error { /* * We want to use archive/tar for this, but that doesn't appear * to be working for us (see lxd/images.go) */ dpath := shared.VarPath("lxc", name) imagefile := shared.VarPath("images", hash) compression, _, err := detectCompression(imagefile) if err != nil { shared.Logf("Unkown compression type: %s", err) removeContainer(d, name) return err } args := []string{"-C", dpath, "--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, imagefile) output, err := exec.Command("tar", args...).Output() if err != nil { shared.Debugf("Untar of image: Output %s\nError %s\n", output, err) removeContainer(d, name) return err } return nil }
func (s *storageLvm) ImageCreate(fingerprint string) error { finalName := shared.VarPath("images", fingerprint) poolname, err := s.d.ConfigValueGet("core.lvm_thinpool_name") if err != nil { return fmt.Errorf("Error checking server config, err=%v", err) } if poolname == "" { poolname, err = s.createDefaultThinPool() if err != nil { return fmt.Errorf("Error creating LVM thin pool: %v", err) } err = storageLVMSetThinPoolNameConfig(s.d, poolname) if err != nil { s.log.Error("Setting thin pool name", log.Ctx{"err": err}) return fmt.Errorf("Error setting LVM thin pool config: %v", err) } } lvpath, err := s.createThinLV(fingerprint, poolname) if err != nil { s.log.Error("LVMCreateThinLV", log.Ctx{"err": err}) return fmt.Errorf("Error Creating LVM LV for new image: %v", err) } dst := shared.VarPath("images", fmt.Sprintf("%s.lv", fingerprint)) err = os.Symlink(lvpath, dst) if err != nil { return err } output, err := exec.Command( "mkfs.ext4", "-E", "nodiscard,lazy_itable_init=0,lazy_journal_init=0", lvpath).CombinedOutput() if err != nil { s.log.Error("mkfs.ext4", log.Ctx{"output": output}) return fmt.Errorf("Error making filesystem on image LV: %v", err) } tempLVMountPoint, err := ioutil.TempDir(shared.VarPath("images"), "tmp_lv_mnt") if err != nil { return err } defer func() { if err := os.RemoveAll(tempLVMountPoint); err != nil { s.log.Error("Deleting temporary LVM mount point", log.Ctx{"err": err}) } }() output, err = exec.Command( "mount", "-o", "discard", lvpath, tempLVMountPoint).CombinedOutput() if err != nil { shared.Logf("Error mounting image LV for untarring: '%s'", output) return fmt.Errorf("Error mounting image LV: %v", err) } untarErr := untarImage(finalName, tempLVMountPoint) output, err = exec.Command("umount", tempLVMountPoint).CombinedOutput() if err != nil { s.log.Warn("could not unmount LV. Will not remove", log.Ctx{"lvpath": lvpath, "mountpoint": tempLVMountPoint, "err": err}) if untarErr == nil { return err } return fmt.Errorf( "Error unmounting '%s' during cleanup of error %v", tempLVMountPoint, untarErr) } return untarErr }
func createImageLV(d *Daemon, builddir string, fingerprint string, vgname string) error { imagefname := filepath.Join(builddir, fingerprint) poolname, poolnameIsSet, err := getServerConfigValue(d, "core.lvm_thinpool_name") if err != nil { return fmt.Errorf("Error checking server config: %v", err) } if !poolnameIsSet { poolname, err = shared.LVMCreateDefaultThinPool(vgname) if err != nil { return fmt.Errorf("Error creating LVM thin pool: %v", err) } err = setLVMThinPoolNameConfig(d, poolname) if err != nil { shared.Debugf("Error setting thin pool name: '%s'", err) return fmt.Errorf("Error setting LVM thin pool config: %v", err) } } lvpath, err := shared.LVMCreateThinLV(fingerprint, poolname, vgname) if err != nil { shared.Logf("Error from LVMCreateThinLV: '%v'", err) return fmt.Errorf("Error Creating LVM LV for new image: %v", err) } err = os.Symlink(lvpath, fmt.Sprintf("%s.lv", imagefname)) if err != nil { return err } output, err := exec.Command("mkfs.ext4", "-E", "nodiscard,lazy_itable_init=0,lazy_journal_init=0", lvpath).CombinedOutput() if err != nil { shared.Logf("Error output from mkfs.ext4: '%s'", output) return fmt.Errorf("Error making filesystem on image LV: %v", err) } tempLVMountPoint, err := ioutil.TempDir(builddir, "tmp_lv_mnt") if err != nil { return err } output, err = exec.Command("mount", "-o", "discard", lvpath, tempLVMountPoint).CombinedOutput() if err != nil { shared.Logf("Error mounting image LV for untarring: '%s'", output) return fmt.Errorf("Error mounting image LV: %v", err) } untar_err := untarImage(imagefname, tempLVMountPoint) output, err = exec.Command("umount", tempLVMountPoint).CombinedOutput() if err != nil { shared.Logf("WARNING: could not unmount LV '%s' from '%s'. Will not remove. Error: %v", lvpath, tempLVMountPoint, err) if untar_err == nil { return err } else { return fmt.Errorf("Error unmounting '%s' during cleanup of error %v", tempLVMountPoint, untar_err) } } return untar_err }
// StartDaemon starts the shared daemon with the provided configuration. func StartDaemon(listenAddr string) (*Daemon, error) { d := &Daemon{} d.lxcpath = shared.VarPath("lxc") err := os.MkdirAll(shared.VarPath("/"), 0755) if err != nil { return nil, err } err = os.MkdirAll(d.lxcpath, 0755) if err != nil { return nil, err } d.BackingFs, err = shared.GetFilesystem(d.lxcpath) if err != nil { shared.Debugf("Error detecting backing fs: %s\n", err) } certf, keyf, err := readMyCert() if err != nil { return nil, err } d.certf = certf d.keyf = keyf err = initDb(d) if err != nil { return nil, err } readSavedClientCAList(d) d.mux = mux.NewRouter() d.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") SyncResponse(true, []string{"/1.0"}).Render(w) }) for _, c := range api10 { d.createCmd("1.0", c) } d.mux.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { shared.Debugf("sending top level 404: %s", r.URL) w.Header().Set("Content-Type", "application/json") NotFound.Render(w) }) d.IdmapSet, err = shared.DefaultIdmapSet() if err != nil { shared.Logf("error reading idmap: %s", err.Error()) shared.Logf("operations requiring idmap will not be available") } else { shared.Debugf("Default uid/gid map:") for _, lxcmap := range d.IdmapSet.ToLxcString() { shared.Debugf(" - " + lxcmap) } } tlsConfig, err := shared.GetTLSConfig(d.certf, d.keyf) if err != nil { return nil, err } listeners, err := activation.Listeners(false) if err != nil { return nil, err } var localSockets []net.Listener var remoteSockets []net.Listener if len(listeners) > 0 { shared.Debugf("LXD is socket activated.\n") for _, listener := range listeners { if _, err := os.Stat(listener.Addr().String()); err == nil { localSockets = append(localSockets, listener) } else { tlsListener := tls.NewListener(listener, tlsConfig) remoteSockets = append(remoteSockets, tlsListener) } } } else { shared.Debugf("LXD isn't socket activated.\n") localSocketPath := shared.VarPath("unix.socket") // If the socket exists, let's try to connect to it and see if there's // a lxd running. if _, err := os.Stat(localSocketPath); err == nil { c := &lxd.Config{Remotes: map[string]lxd.RemoteConfig{}} _, err := lxd.NewClient(c, "") if err != nil { shared.Debugf("Detected old but dead unix socket, deleting it...") // Connecting failed, so let's delete the socket and // listen on it ourselves. err = os.Remove(localSocketPath) if err != nil { return nil, err } } } unixAddr, err := net.ResolveUnixAddr("unix", localSocketPath) if err != nil { return nil, fmt.Errorf("cannot resolve unix socket address: %v", err) } unixl, err := net.ListenUnix("unix", unixAddr) if err != nil { return nil, fmt.Errorf("cannot listen on unix socket: %v", err) } if err := os.Chmod(localSocketPath, 0660); err != nil { return nil, err } gid, err := shared.GroupId(*group) if err != nil { return nil, err } if err := os.Chown(localSocketPath, os.Getuid(), gid); err != nil { return nil, err } localSockets = append(localSockets, unixl) if listenAddr != "" { tcpl, err := tls.Listen("tcp", listenAddr, tlsConfig) if err != nil { return nil, fmt.Errorf("cannot listen on unix socket: %v", err) } remoteSockets = append(remoteSockets, tcpl) } } d.localSockets = localSockets d.remoteSockets = remoteSockets d.devlxd, err = createAndBindDevLxd() if err != nil { return nil, err } containersRestart(d) containersWatch(d) d.tomb.Go(func() error { for _, socket := range d.localSockets { shared.Debugf(" - binding local socket: %s\n", socket.Addr()) d.tomb.Go(func() error { return http.Serve(socket, d.mux) }) } for _, socket := range d.remoteSockets { shared.Debugf(" - binding remote socket: %s\n", socket.Addr()) d.tomb.Go(func() error { return http.Serve(socket, d.mux) }) } d.tomb.Go(func() error { server := devLxdServer(d) return server.Serve(d.devlxd) }) return nil }) return d, nil }
func createAndBindDevLxd() (*net.UnixListener, error) { shared.Logf("WARNING: devlxd not supported under gccgo") return nil, nil }