Beispiel #1
0
/*
 * load the server cert from disk
 */
func (c *Client) loadServerCert() {
	cert, err := shared.ReadCert(c.Config.ServerCertPath(c.Name))
	if err != nil {
		shared.Debugf("Error reading the server certificate for %s: %v", c.Name, err)
		return
	}

	c.scert = cert
}
Beispiel #2
0
// NewClient returns a new LXD client.
func NewClient(config *Config, remote string) (*Client, error) {
	if remote == "" {
		return nil, fmt.Errorf("A remote name must be provided.")
	}

	r, ok := config.Remotes[remote]
	if !ok {
		return nil, fmt.Errorf("unknown remote name: %q", remote)
	}
	info := ConnectInfo{
		Name:         remote,
		RemoteConfig: r,
	}

	if strings.HasPrefix(r.Addr, "unix:") {
		// replace "unix://" with the official "unix:/var/lib/lxd/unix.socket"
		if info.RemoteConfig.Addr == "unix://" {
			info.RemoteConfig.Addr = fmt.Sprintf("unix:%s", shared.VarPath("unix.socket"))
		}
	} else {
		certf, keyf, err := ensureMyCert(config.ConfigDir)
		if err != nil {
			return nil, err
		}
		certBytes, err := ioutil.ReadFile(certf)
		if err != nil {
			return nil, err
		}
		keyBytes, err := ioutil.ReadFile(keyf)
		if err != nil {
			return nil, err
		}
		info.ClientPEMCert = string(certBytes)
		info.ClientPEMKey = string(keyBytes)
		serverCertPath := config.ServerCertPath(remote)
		if shared.PathExists(serverCertPath) {
			cert, err := shared.ReadCert(serverCertPath)
			if err != nil {
				return nil, err
			}

			info.ServerPEMCert = string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}))
		}
	}
	c, err := NewClientFromInfo(info)
	if err != nil {
		return nil, err
	}
	c.Config = *config

	return c, nil
}
Beispiel #3
0
func (c *configCmd) run(config *lxd.Config, args []string) error {
	if len(args) < 1 {
		return errArgs
	}

	switch args[0] {

	case "unset":
		if len(args) < 2 {
			return errArgs
		}

		// 2 args means we're unsetting a server key
		if len(args) == 2 {
			key := args[1]
			c, err := lxd.NewClient(config, config.DefaultRemote)
			if err != nil {
				return err
			}
			_, err = c.SetServerConfig(key, "")
			return err
		}

		// 3 args is a container config key
		args = append(args, "")
		return doSet(config, args)

	case "set":
		if len(args) < 3 {
			return errArgs
		}

		// 3 args means we're setting a server key
		if len(args) == 3 {
			key := args[1]
			c, err := lxd.NewClient(config, config.DefaultRemote)
			if err != nil {
				return err
			}
			_, err = c.SetServerConfig(key, args[2])
			return err
		}

		// 4 args is a container config key
		return doSet(config, args)

	case "trust":
		if len(args) < 2 {
			return errArgs
		}

		switch args[1] {
		case "list":
			var remote string
			if len(args) == 3 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			trust, err := d.CertificateList()
			if err != nil {
				return err
			}

			data := [][]string{}
			for _, cert := range trust {
				fp := cert.Fingerprint[0:12]

				certBlock, _ := pem.Decode([]byte(cert.Certificate))
				cert, err := x509.ParseCertificate(certBlock.Bytes)
				if err != nil {
					return err
				}

				const layout = "Jan 2, 2006 at 3:04pm (MST)"
				issue := cert.NotBefore.Format(layout)
				expiry := cert.NotAfter.Format(layout)
				data = append(data, []string{fp, cert.Subject.CommonName, issue, expiry})
			}

			table := tablewriter.NewWriter(os.Stdout)
			table.SetHeader([]string{"FINGERPRINT", "COMMON NAME", "ISSUE DATE", "EXPIRY DATE"})

			for _, v := range data {
				table.Append(v)
			}
			table.Render()

			return nil
		case "add":
			var remote string
			if len(args) < 3 {
				return fmt.Errorf(gettext.Gettext("No cert provided to add"))
			} else if len(args) == 4 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			fname := args[len(args)-1]
			cert, err := shared.ReadCert(fname)
			if err != nil {
				return err
			}

			name, _ := shared.SplitExt(fname)
			return d.CertificateAdd(cert, name)
		case "remove":
			var remote string
			if len(args) < 3 {
				return fmt.Errorf(gettext.Gettext("No fingerprint specified."))
			} else if len(args) == 4 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			return d.CertificateRemove(args[len(args)-1])
		default:
			return fmt.Errorf(gettext.Gettext("Unkonwn config trust command %s"), args[1])
		}

	case "show":
		remote := config.DefaultRemote
		container := ""
		if len(args) > 1 {
			remote, container = config.ParseRemoteAndContainer(args[1])
		}

		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		var data []byte

		if len(args) == 1 || container == "" {
			config, err := d.ServerStatus()
			if err != nil {
				return err
			}

			brief := config.BriefState()
			data, err = yaml.Marshal(&brief)
		} else {
			config, err := d.ContainerStatus(container, false)
			if err != nil {
				return err
			}

			brief := config.BriefState()
			data, err = yaml.Marshal(&brief)
		}

		fmt.Printf("%s", data)

		return nil

	case "get":
		if len(args) != 3 {
			return errArgs
		}

		remote, container := config.ParseRemoteAndContainer(args[1])
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		resp, err := d.ContainerStatus(container, false)
		if err != nil {
			return err
		}
		fmt.Printf("%s: %s\n", args[2], resp.Config[args[2]])
		return nil

	case "profile":
	case "device":
		if len(args) < 2 {
			return errArgs
		}
		switch args[1] {
		case "list":
			return deviceList(config, "container", args)
		case "add":
			return deviceAdd(config, "container", args)
		case "remove":
			return deviceRm(config, "container", args)
		case "show":
			return deviceShow(config, "container", args)
		default:
			return errArgs
		}

	case "edit":
		if len(args) != 2 {
			return errArgs
		}

		remote, container := config.ParseRemoteAndContainer(args[1])
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		return doConfigEdit(d, container)

	default:
		return errArgs
	}

	return errArgs
}
Beispiel #4
0
func (c *configCmd) run(config *lxd.Config, args []string) error {
	if len(args) < 1 {
		return errArgs
	}

	switch args[0] {

	case "unset":
		if len(args) < 2 {
			return errArgs
		}

		// 2 args means we're unsetting a server key
		if len(args) == 2 {
			key := args[1]
			c, err := lxd.NewClient(config, "")
			if err != nil {
				return err
			}
			_, err = c.SetServerConfig(key, "")
			return err
		}

		// 3 args is a container config key
		args = append(args, "")
		return doSet(config, args)

	case "set":
		if len(args) < 3 {
			return errArgs
		}

		// 3 args means we're setting a server key
		if len(args) == 3 {
			key := args[1]
			c, err := lxd.NewClient(config, "")
			if err != nil {
				return err
			}
			_, err = c.SetServerConfig(key, args[2])
			return err
		}

		// 4 args is a container config key
		return doSet(config, args)

	case "trust":
		if len(args) < 2 {
			return errArgs
		}

		switch args[1] {
		case "list":
			var remote string
			if len(args) == 3 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			trust, err := d.CertificateList()
			if err != nil {
				return err
			}

			for _, fingerprint := range trust {
				fmt.Println(fmt.Sprintf("%s", fingerprint))
			}

			return nil
		case "add":
			var remote string
			if len(args) < 3 {
				return fmt.Errorf(gettext.Gettext("No cert provided to add"))
			} else if len(args) == 4 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			fname := args[len(args)-1]
			cert, err := shared.ReadCert(fname)
			if err != nil {
				return err
			}

			name, _ := shared.SplitExt(fname)
			return d.CertificateAdd(cert, name)
		case "remove":
			var remote string
			if len(args) < 3 {
				return fmt.Errorf(gettext.Gettext("No fingerprint specified."))
			} else if len(args) == 4 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			return d.CertificateRemove(args[len(args)-1])
		default:
			return fmt.Errorf(gettext.Gettext("Unkonwn config trust command %s"), args[1])
		}

	case "show":
		remote := ""
		container := ""
		if len(args) > 1 {
			remote, container = config.ParseRemoteAndContainer(args[1])
			if container == "" {
				return fmt.Errorf(gettext.Gettext("Show for remotes is not yet supported\n"))
			}
		}

		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		var data []byte

		if len(args) == 1 || container == "" {
			config, err := d.ServerStatus()
			if err != nil {
				return err
			}

			brief := config.BriefState()
			data, err = yaml.Marshal(&brief)
		} else {
			config, err := d.ContainerStatus(container, false)
			if err != nil {
				return err
			}

			brief := config.BriefState()
			data, err = yaml.Marshal(&brief)
		}

		fmt.Printf("%s", data)

		return nil

	case "get":
		if len(args) != 3 {
			return errArgs
		}

		remote, container := config.ParseRemoteAndContainer(args[1])
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		resp, err := d.ContainerStatus(container, false)
		if err != nil {
			return err
		}
		fmt.Printf("%s: %s\n", args[2], resp.Config[args[2]])
		return nil

	case "profile":
	case "device":
		if len(args) < 2 {
			return errArgs
		}
		switch args[1] {
		case "list":
			return deviceList(config, "container", args)
		case "add":
			return deviceAdd(config, "container", args)
		case "remove":
			return deviceRm(config, "container", args)
		case "show":
			return deviceShow(config, "container", args)
		default:
			return errArgs
		}

	case "edit":
		if len(args) != 2 {
			return errArgs
		}

		remote, container := config.ParseRemoteAndContainer(args[1])
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		return doConfigEdit(d, container)

	default:
		return errArgs
	}

	return errArgs
}
Beispiel #5
0
func (d *Daemon) Init() error {
	/* Initialize some variables */
	d.imagesDownloading = map[string]chan bool{}

	d.readyChan = make(chan bool)
	d.shutdownChan = make(chan bool)

	/* Set the executable path */
	/* Set the LVM environment */
	err := os.Setenv("LVM_SUPPRESS_FD_WARNINGS", "1")
	if err != nil {
		return err
	}

	/* Setup logging if that wasn't done before */
	if shared.Log == nil {
		shared.Log, err = logging.GetLogger("", "", true, true, nil)
		if err != nil {
			return err
		}
	}

	/* Print welcome message */
	if d.MockMode {
		shared.LogInfo("LXD is starting in mock mode",
			log.Ctx{"path": shared.VarPath("")})
	} else if d.SetupMode {
		shared.LogInfo("LXD is starting in setup mode",
			log.Ctx{"path": shared.VarPath("")})
	} else {
		shared.LogInfo("LXD is starting in normal mode",
			log.Ctx{"path": shared.VarPath("")})
	}

	/* Detect user namespaces */
	runningInUserns = shared.RunningInUserNS()

	/* Detect AppArmor support */
	if aaAvailable && os.Getenv("LXD_SECURITY_APPARMOR") == "false" {
		aaAvailable = false
		aaAdmin = false
		shared.LogWarnf("AppArmor support has been manually disabled")
	}

	if aaAvailable && !shared.IsDir("/sys/kernel/security/apparmor") {
		aaAvailable = false
		aaAdmin = false
		shared.LogWarnf("AppArmor support has been disabled because of lack of kernel support")
	}

	_, err = exec.LookPath("apparmor_parser")
	if aaAvailable && err != nil {
		aaAvailable = false
		aaAdmin = false
		shared.LogWarnf("AppArmor support has been disabled because 'apparmor_parser' couldn't be found")
	}

	/* Detect AppArmor admin support */
	if aaAdmin && !haveMacAdmin() {
		aaAdmin = false
		shared.LogWarnf("Per-container AppArmor profiles are disabled because the mac_admin capability is missing.")
	}

	if aaAdmin && runningInUserns {
		aaAdmin = false
		shared.LogWarnf("Per-container AppArmor profiles are disabled because LXD is running in an unprivileged container.")
	}

	/* Detect AppArmor confinment */
	if !aaConfined {
		profile := aaProfile()
		if profile != "unconfined" && profile != "" {
			aaConfined = true
			shared.LogWarnf("Per-container AppArmor profiles are disabled because LXD is already protected by AppArmor.")
		}
	}

	if aaAvailable {
		canStack := func() bool {
			contentBytes, err := ioutil.ReadFile("/sys/kernel/security/apparmor/features/domain/stack")
			if err != nil {
				return false
			}

			if string(contentBytes) != "yes\n" {
				return false
			}

			contentBytes, err = ioutil.ReadFile("/sys/kernel/security/apparmor/features/domain/version")
			if err != nil {
				return false
			}

			content := string(contentBytes)

			parts := strings.Split(strings.TrimSpace(content), ".")

			if len(parts) == 0 {
				shared.LogWarn("unknown apparmor domain version", log.Ctx{"version": content})
				return false
			}

			major, err := strconv.Atoi(parts[0])
			if err != nil {
				shared.LogWarn("unknown apparmor domain version", log.Ctx{"version": content})
				return false
			}

			minor := 0
			if len(parts) == 2 {
				minor, err = strconv.Atoi(parts[1])
				if err != nil {
					shared.LogWarn("unknown apparmor domain version", log.Ctx{"version": content})
					return false
				}
			}

			return major >= 1 && minor >= 2
		}

		aaStacking = canStack()
	}

	/* Detect CGroup support */
	cgBlkioController = shared.PathExists("/sys/fs/cgroup/blkio/")
	if !cgBlkioController {
		shared.LogWarnf("Couldn't find the CGroup blkio controller, I/O limits will be ignored.")
	}

	cgCpuController = shared.PathExists("/sys/fs/cgroup/cpu/")
	if !cgCpuController {
		shared.LogWarnf("Couldn't find the CGroup CPU controller, CPU time limits will be ignored.")
	}

	cgCpuacctController = shared.PathExists("/sys/fs/cgroup/cpuacct/")
	if !cgCpuacctController {
		shared.LogWarnf("Couldn't find the CGroup CPUacct controller, CPU accounting will not be available.")
	}

	cgCpusetController = shared.PathExists("/sys/fs/cgroup/cpuset/")
	if !cgCpusetController {
		shared.LogWarnf("Couldn't find the CGroup CPUset controller, CPU pinning will be ignored.")
	}

	cgDevicesController = shared.PathExists("/sys/fs/cgroup/devices/")
	if !cgDevicesController {
		shared.LogWarnf("Couldn't find the CGroup devices controller, device access control won't work.")
	}

	cgMemoryController = shared.PathExists("/sys/fs/cgroup/memory/")
	if !cgMemoryController {
		shared.LogWarnf("Couldn't find the CGroup memory controller, memory limits will be ignored.")
	}

	cgNetPrioController = shared.PathExists("/sys/fs/cgroup/net_prio/")
	if !cgNetPrioController {
		shared.LogWarnf("Couldn't find the CGroup network class controller, network limits will be ignored.")
	}

	cgPidsController = shared.PathExists("/sys/fs/cgroup/pids/")
	if !cgPidsController {
		shared.LogWarnf("Couldn't find the CGroup pids controller, process limits will be ignored.")
	}

	cgSwapAccounting = shared.PathExists("/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes")
	if !cgSwapAccounting {
		shared.LogWarnf("CGroup memory swap accounting is disabled, swap limits will be ignored.")
	}

	/* Get the list of supported architectures */
	var architectures = []int{}

	architectureName, err := shared.ArchitectureGetLocal()
	if err != nil {
		return err
	}

	architecture, err := shared.ArchitectureId(architectureName)
	if err != nil {
		return err
	}
	architectures = append(architectures, architecture)

	personalities, err := shared.ArchitecturePersonalities(architecture)
	if err != nil {
		return err
	}
	for _, personality := range personalities {
		architectures = append(architectures, personality)
	}
	d.architectures = architectures

	/* Set container path */
	d.lxcpath = shared.VarPath("containers")

	/* Make sure all our directories are available */
	if err := os.MkdirAll(shared.CachePath(), 0700); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.VarPath("containers"), 0711); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.VarPath("devices"), 0711); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.VarPath("devlxd"), 0755); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.VarPath("images"), 0700); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.LogPath(), 0700); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.VarPath("security"), 0700); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.VarPath("shmounts"), 0711); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.VarPath("snapshots"), 0700); err != nil {
		return err
	}

	/* Detect the filesystem */
	d.BackingFs, err = filesystemDetect(d.lxcpath)
	if err != nil {
		shared.LogError("Error detecting backing fs", log.Ctx{"err": err})
	}

	/* Read the uid/gid allocation */
	d.IdmapSet, err = shared.DefaultIdmapSet()
	if err != nil {
		shared.LogWarn("Error reading idmap", log.Ctx{"err": err.Error()})
		shared.LogWarnf("Only privileged containers will be able to run")
	} else {
		shared.LogInfof("Default uid/gid map:")
		for _, lxcmap := range d.IdmapSet.ToLxcString() {
			shared.LogInfof(strings.TrimRight(" - "+lxcmap, "\n"))
		}
	}

	/* Initialize the database */
	err = initializeDbObject(d, shared.VarPath("lxd.db"))
	if err != nil {
		return err
	}

	/* Load all config values from the database */
	err = daemonConfigInit(d.db)
	if err != nil {
		return err
	}

	if !d.MockMode {
		/* Setup the storage driver */
		err = d.SetupStorageDriver()
		if err != nil {
			return fmt.Errorf("Failed to setup storage: %s", err)
		}

		/* Apply all patches */
		err = patchesApplyAll(d)
		if err != nil {
			return err
		}

		/* Setup the networks */
		err = networkStartup(d)
		if err != nil {
			return err
		}

		/* Restore simplestreams cache */
		err = imageLoadStreamCache(d)
		if err != nil {
			return err
		}
	}

	/* Log expiry */
	go func() {
		t := time.NewTicker(24 * time.Hour)
		for {
			shared.LogInfof("Expiring log files")

			err := d.ExpireLogs()
			if err != nil {
				shared.LogError("Failed to expire logs", log.Ctx{"err": err})
			}

			shared.LogInfof("Done expiring log files")
			<-t.C
		}
	}()

	/* set the initial proxy function based on config values in the DB */
	d.proxy = shared.ProxyFromConfig(
		daemonConfig["core.proxy_https"].Get(),
		daemonConfig["core.proxy_http"].Get(),
		daemonConfig["core.proxy_ignore_hosts"].Get(),
	)

	/* Setup /dev/lxd */
	shared.LogInfof("Starting /dev/lxd handler")
	d.devlxd, err = createAndBindDevLxd()
	if err != nil {
		return err
	}

	if !d.MockMode {
		/* Start the scheduler */
		go deviceEventListener(d)

		/* Setup the TLS authentication */
		certf, keyf, err := readMyCert()
		if err != nil {
			return err
		}

		cert, err := tls.LoadX509KeyPair(certf, keyf)
		if err != nil {
			return err
		}

		tlsConfig := &tls.Config{
			InsecureSkipVerify: true,
			ClientAuth:         tls.RequestClientCert,
			Certificates:       []tls.Certificate{cert},
			MinVersion:         tls.VersionTLS12,
			MaxVersion:         tls.VersionTLS12,
			CipherSuites: []uint16{
				tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
				tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
			PreferServerCipherSuites: true,
		}

		if shared.PathExists(shared.VarPath("server.ca")) {
			ca, err := shared.ReadCert(shared.VarPath("server.ca"))
			if err != nil {
				return err
			}

			caPool := x509.NewCertPool()
			caPool.AddCert(ca)
			tlsConfig.RootCAs = caPool
			tlsConfig.ClientCAs = caPool

			shared.LogInfof("LXD is in CA mode, only CA-signed certificates will be allowed")
		}

		tlsConfig.BuildNameToCertificate()

		d.tlsConfig = tlsConfig

		readSavedClientCAList(d)
	}

	/* Setup the web server */
	d.mux = mux.NewRouter()
	d.mux.StrictSlash(false)

	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)
	}

	for _, c := range apiInternal {
		d.createCmd("internal", c)
	}

	d.mux.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		shared.LogInfo("Sending top level 404", log.Ctx{"url": r.URL})
		w.Header().Set("Content-Type", "application/json")
		NotFound.Render(w)
	})

	listeners := d.GetListeners()
	if len(listeners) > 0 {
		shared.LogInfof("LXD is socket activated")

		for _, listener := range listeners {
			if shared.PathExists(listener.Addr().String()) {
				d.UnixSocket = &Socket{Socket: listener, CloseOnExit: false}
			} else {
				tlsListener := tls.NewListener(listener, d.tlsConfig)
				d.TCPSocket = &Socket{Socket: tlsListener, CloseOnExit: false}
			}
		}
	} else {
		shared.LogInfof("LXD isn't socket activated")

		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 shared.PathExists(localSocketPath) {
			_, err := lxd.NewClient(&lxd.DefaultConfig, "local")
			if err != nil {
				shared.LogDebugf("Detected stale unix socket, deleting")
				// Connecting failed, so let's delete the socket and
				// listen on it ourselves.
				err = os.Remove(localSocketPath)
				if err != nil {
					return err
				}
			} else {
				return fmt.Errorf("LXD is already running.")
			}
		}

		unixAddr, err := net.ResolveUnixAddr("unix", localSocketPath)
		if err != nil {
			return fmt.Errorf("cannot resolve unix socket address: %v", err)
		}

		unixl, err := net.ListenUnix("unix", unixAddr)
		if err != nil {
			return fmt.Errorf("cannot listen on unix socket: %v", err)
		}

		if err := os.Chmod(localSocketPath, 0660); err != nil {
			return err
		}

		var gid int
		if d.group != "" {
			gid, err = shared.GroupId(d.group)
			if err != nil {
				return err
			}
		} else {
			gid = os.Getgid()
		}

		if err := os.Chown(localSocketPath, os.Getuid(), gid); err != nil {
			return err
		}

		d.UnixSocket = &Socket{Socket: unixl, CloseOnExit: true}
	}

	listenAddr := daemonConfig["core.https_address"].Get()
	if listenAddr != "" {
		_, _, err := net.SplitHostPort(listenAddr)
		if err != nil {
			listenAddr = fmt.Sprintf("%s:%s", listenAddr, shared.DefaultPort)
		}

		tcpl, err := tls.Listen("tcp", listenAddr, d.tlsConfig)
		if err != nil {
			shared.LogError("cannot listen on https socket, skipping...", log.Ctx{"err": err})
		} else {
			if d.TCPSocket != nil {
				shared.LogInfof("Replacing inherited TCP socket with configured one")
				d.TCPSocket.Socket.Close()
			}
			d.TCPSocket = &Socket{Socket: tcpl, CloseOnExit: true}
		}
	}

	d.tomb.Go(func() error {
		shared.LogInfof("REST API daemon:")
		if d.UnixSocket != nil {
			shared.LogInfo(" - binding Unix socket", log.Ctx{"socket": d.UnixSocket.Socket.Addr()})
			d.tomb.Go(func() error { return http.Serve(d.UnixSocket.Socket, &lxdHttpServer{d.mux, d}) })
		}

		if d.TCPSocket != nil {
			shared.LogInfo(" - binding TCP socket", log.Ctx{"socket": d.TCPSocket.Socket.Addr()})
			d.tomb.Go(func() error { return http.Serve(d.TCPSocket.Socket, &lxdHttpServer{d.mux, d}) })
		}

		d.tomb.Go(func() error {
			server := devLxdServer(d)
			return server.Serve(d.devlxd)
		})
		return nil
	})

	if !d.MockMode && !d.SetupMode {
		err := d.Ready()
		if err != nil {
			return err
		}
	}

	return nil
}
Beispiel #6
0
func (c *configCmd) run(config *lxd.Config, args []string) error {
	if len(args) < 1 {
		return errArgs
	}

	switch args[0] {

	case "unset":
		if len(args) < 2 {
			return errArgs
		}

		// Deal with local server
		if len(args) == 2 {
			c, err := lxd.NewClient(config, config.DefaultRemote)
			if err != nil {
				return err
			}

			ss, err := c.ServerStatus()
			if err != nil {
				return err
			}

			_, ok := ss.Config[args[1]]
			if !ok {
				return fmt.Errorf(i18n.G("Can't unset key '%s', it's not currently set."), args[1])
			}

			_, err = c.SetServerConfig(args[1], "")
			return err
		}

		// Deal with remote server
		remote, container := config.ParseRemoteAndContainer(args[1])
		if container == "" {
			c, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			ss, err := c.ServerStatus()
			if err != nil {
				return err
			}

			_, ok := ss.Config[args[1]]
			if !ok {
				return fmt.Errorf(i18n.G("Can't unset key '%s', it's not currently set."), args[1])
			}

			_, err = c.SetServerConfig(args[2], "")
			return err
		}

		// Deal with container
		args = append(args, "")
		return c.doSet(config, args, true)

	case "set":
		if len(args) < 3 {
			return errArgs
		}

		// Deal with local server
		if len(args) == 3 {
			c, err := lxd.NewClient(config, config.DefaultRemote)
			if err != nil {
				return err
			}

			_, err = c.SetServerConfig(args[1], args[2])
			return err
		}

		// Deal with remote server
		remote, container := config.ParseRemoteAndContainer(args[1])
		if container == "" {
			c, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			_, err = c.SetServerConfig(args[2], args[3])
			return err
		}

		// Deal with container
		return c.doSet(config, args, false)

	case "trust":
		if len(args) < 2 {
			return errArgs
		}

		switch args[1] {
		case "list":
			var remote string
			if len(args) == 3 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			trust, err := d.CertificateList()
			if err != nil {
				return err
			}

			data := [][]string{}
			for _, cert := range trust {
				fp := cert.Fingerprint[0:12]

				certBlock, _ := pem.Decode([]byte(cert.Certificate))
				if certBlock == nil {
					return fmt.Errorf(i18n.G("Invalid certificate"))
				}

				cert, err := x509.ParseCertificate(certBlock.Bytes)
				if err != nil {
					return err
				}

				const layout = "Jan 2, 2006 at 3:04pm (MST)"
				issue := cert.NotBefore.Format(layout)
				expiry := cert.NotAfter.Format(layout)
				data = append(data, []string{fp, cert.Subject.CommonName, issue, expiry})
			}

			table := tablewriter.NewWriter(os.Stdout)
			table.SetAutoWrapText(false)
			table.SetAlignment(tablewriter.ALIGN_LEFT)
			table.SetRowLine(true)
			table.SetHeader([]string{
				i18n.G("FINGERPRINT"),
				i18n.G("COMMON NAME"),
				i18n.G("ISSUE DATE"),
				i18n.G("EXPIRY DATE")})
			sort.Sort(SortImage(data))
			table.AppendBulk(data)
			table.Render()

			return nil
		case "add":
			var remote string
			if len(args) < 3 {
				return fmt.Errorf(i18n.G("No certificate provided to add"))
			} else if len(args) == 4 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			fname := args[len(args)-1]
			cert, err := shared.ReadCert(fname)
			if err != nil {
				return err
			}

			name, _ := shared.SplitExt(fname)
			return d.CertificateAdd(cert, name)
		case "remove":
			var remote string
			if len(args) < 3 {
				return fmt.Errorf(i18n.G("No fingerprint specified."))
			} else if len(args) == 4 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			return d.CertificateRemove(args[len(args)-1])
		default:
			return errArgs
		}

	case "show":
		remote := config.DefaultRemote
		container := ""
		if len(args) > 1 {
			remote, container = config.ParseRemoteAndContainer(args[1])
		}

		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		var data []byte

		if len(args) == 1 || container == "" {
			config, err := d.ServerStatus()
			if err != nil {
				return err
			}

			brief := config.Brief()
			data, err = yaml.Marshal(&brief)
		} else {
			var brief shared.BriefContainerInfo
			if shared.IsSnapshot(container) {
				config, err := d.SnapshotInfo(container)
				if err != nil {
					return err
				}

				brief = shared.BriefContainerInfo{
					Profiles:  config.Profiles,
					Config:    config.Config,
					Devices:   config.Devices,
					Ephemeral: config.Ephemeral,
				}
				if c.expanded {
					brief = shared.BriefContainerInfo{
						Profiles:  config.Profiles,
						Config:    config.ExpandedConfig,
						Devices:   config.ExpandedDevices,
						Ephemeral: config.Ephemeral,
					}
				}
			} else {
				config, err := d.ContainerInfo(container)
				if err != nil {
					return err
				}

				brief = config.Brief()
				if c.expanded {
					brief = config.BriefExpanded()
				}
			}

			data, err = yaml.Marshal(&brief)
			if err != nil {
				return err
			}
		}

		fmt.Printf("%s", data)

		return nil

	case "get":
		if len(args) > 3 || len(args) < 2 {
			return errArgs
		}

		remote := config.DefaultRemote
		container := ""
		key := args[1]
		if len(args) > 2 {
			remote, container = config.ParseRemoteAndContainer(args[1])
			key = args[2]
		}

		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		if container != "" {
			resp, err := d.ContainerInfo(container)
			if err != nil {
				return err
			}
			fmt.Println(resp.Config[key])
		} else {
			resp, err := d.ServerStatus()
			if err != nil {
				return err
			}

			value := resp.Config[key]
			if value == nil {
				value = ""
			} else if value == true {
				value = "true"
			} else if value == false {
				value = "false"
			}

			fmt.Println(value)
		}
		return nil

	case "profile":
	case "device":
		if len(args) < 2 {
			return errArgs
		}
		switch args[1] {
		case "list":
			return c.deviceList(config, "container", args)
		case "add":
			return c.deviceAdd(config, "container", args)
		case "remove":
			return c.deviceRm(config, "container", args)
		case "get":
			return c.deviceGet(config, "container", args)
		case "set":
			return c.deviceSet(config, "container", args)
		case "unset":
			return c.deviceUnset(config, "container", args)
		case "show":
			return c.deviceShow(config, "container", args)
		default:
			return errArgs
		}

	case "edit":
		if len(args) < 1 {
			return errArgs
		}

		remote := config.DefaultRemote
		container := ""
		if len(args) > 1 {
			remote, container = config.ParseRemoteAndContainer(args[1])
		}

		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		if len(args) == 1 || container == "" {
			return c.doDaemonConfigEdit(d)
		}

		return c.doContainerConfigEdit(d, container)

	default:
		return errArgs
	}

	return errArgs
}
Beispiel #7
0
func (c *configCmd) run(config *lxd.Config, args []string) error {
	if len(args) < 1 {
		return errArgs
	}

	switch args[0] {

	case "unset":
		if len(args) < 2 {
			return errArgs
		}

		// Deal with local server
		if len(args) == 2 {
			c, err := lxd.NewClient(config, config.DefaultRemote)
			if err != nil {
				return err
			}

			_, err = c.SetServerConfig(args[1], "")
			return err
		}

		// Deal with remote server
		remote, container := config.ParseRemoteAndContainer(args[1])
		if container == "" {
			c, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			_, err = c.SetServerConfig(args[2], "")
			return err
		}

		// Deal with container
		args = append(args, "")
		return doSet(config, args)

	case "set":
		if len(args) < 3 {
			return errArgs
		}

		// Deal with local server
		if len(args) == 3 {
			c, err := lxd.NewClient(config, config.DefaultRemote)
			if err != nil {
				return err
			}

			_, err = c.SetServerConfig(args[1], args[2])
			return err
		}

		// Deal with remote server
		remote, container := config.ParseRemoteAndContainer(args[1])
		if container == "" {
			c, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			_, err = c.SetServerConfig(args[2], args[3])
			return err
		}

		// Deal with container
		return doSet(config, args)

	case "trust":
		if len(args) < 2 {
			return errArgs
		}

		switch args[1] {
		case "list":
			var remote string
			if len(args) == 3 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			trust, err := d.CertificateList()
			if err != nil {
				return err
			}

			data := [][]string{}
			for _, cert := range trust {
				fp := cert.Fingerprint[0:12]

				certBlock, _ := pem.Decode([]byte(cert.Certificate))
				cert, err := x509.ParseCertificate(certBlock.Bytes)
				if err != nil {
					return err
				}

				const layout = "Jan 2, 2006 at 3:04pm (MST)"
				issue := cert.NotBefore.Format(layout)
				expiry := cert.NotAfter.Format(layout)
				data = append(data, []string{fp, cert.Subject.CommonName, issue, expiry})
			}

			table := tablewriter.NewWriter(os.Stdout)
			table.SetHeader([]string{
				i18n.G("FINGERPRINT"),
				i18n.G("COMMON NAME"),
				i18n.G("ISSUE DATE"),
				i18n.G("EXPIRY DATE")})

			for _, v := range data {
				table.Append(v)
			}
			table.Render()

			return nil
		case "add":
			var remote string
			if len(args) < 3 {
				return fmt.Errorf(i18n.G("No certificate provided to add"))
			} else if len(args) == 4 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			fname := args[len(args)-1]
			cert, err := shared.ReadCert(fname)
			if err != nil {
				return err
			}

			name, _ := shared.SplitExt(fname)
			return d.CertificateAdd(cert, name)
		case "remove":
			var remote string
			if len(args) < 3 {
				return fmt.Errorf(i18n.G("No fingerprint specified."))
			} else if len(args) == 4 {
				remote = config.ParseRemote(args[2])
			} else {
				remote = config.DefaultRemote
			}

			d, err := lxd.NewClient(config, remote)
			if err != nil {
				return err
			}

			return d.CertificateRemove(args[len(args)-1])
		default:
			return errArgs
		}

	case "show":
		remote := config.DefaultRemote
		container := ""
		if len(args) > 1 {
			remote, container = config.ParseRemoteAndContainer(args[1])
		}

		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		var data []byte

		if len(args) == 1 || container == "" {
			config, err := d.ServerStatus()
			if err != nil {
				return err
			}

			brief := config.BriefState()
			data, err = yaml.Marshal(&brief)
		} else {
			config, err := d.ContainerStatus(container)
			if err != nil {
				return err
			}

			brief := config.BriefState()
			if expanded {
				brief = config.BriefStateExpanded()
			}
			data, err = yaml.Marshal(&brief)
		}

		fmt.Printf("%s", data)

		return nil

	case "get":
		if len(args) > 3 || len(args) < 2 {
			return errArgs
		}

		remote := config.DefaultRemote
		container := ""
		key := args[1]
		if len(args) > 2 {
			remote, container = config.ParseRemoteAndContainer(args[1])
			key = args[2]
		}

		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		if container != "" {
			resp, err := d.ContainerStatus(container)
			if err != nil {
				return err
			}
			fmt.Printf("%s: %s\n", key, resp.Config[key])
		} else {
			resp, err := d.ServerStatus()
			if err != nil {
				return err
			}

			value := resp.Config[key]
			if value == nil {
				value = ""
			} else if value == true {
				value = "true"
			} else if value == false {
				value = "false"
			}

			fmt.Printf("%s: %s\n", key, value)
		}
		return nil

	case "profile":
	case "device":
		if len(args) < 2 {
			return errArgs
		}
		switch args[1] {
		case "list":
			return deviceList(config, "container", args)
		case "add":
			return deviceAdd(config, "container", args)
		case "remove":
			return deviceRm(config, "container", args)
		case "show":
			return deviceShow(config, "container", args)
		default:
			return errArgs
		}

	case "edit":
		if len(args) != 2 {
			return errArgs
		}

		remote, container := config.ParseRemoteAndContainer(args[1])
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		return doConfigEdit(d, container)

	default:
		return errArgs
	}

	return errArgs
}