/* * 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 }
// 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 }
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 }
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 }
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 }
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 }
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 }