func getSeccompProfileContent(c container) (string, error) { config := c.ExpandedConfig() raw := config["raw.seccomp"] if raw != "" { return raw, nil } policy := SECCOMP_HEADER whitelist := config["security.syscalls.whitelist"] if whitelist != "" { policy += "whitelist\n[all]\n" policy += whitelist return policy, nil } policy += "blacklist\n" default_, ok := config["security.syscalls.blacklist_default"] if !ok || shared.IsTrue(default_) { policy += DEFAULT_SECCOMP_POLICY } compat := config["security.syscalls.blacklist_compat"] if shared.IsTrue(compat) { arch, err := shared.ArchitectureName(c.Architecture()) if err != nil { return "", err } policy += fmt.Sprintf(COMPAT_BLOCKING_POLICY, arch) } return policy, nil }
func showImages(images []shared.ImageInfo) error { data := [][]string{} for _, image := range images { shortest := shortestAlias(image.Aliases) if len(image.Aliases) > 1 { shortest = fmt.Sprintf(gettext.Gettext("%s (%d more)"), shortest, len(image.Aliases)-1) } fp := image.Fingerprint[0:12] public := gettext.Gettext("no") description := findDescription(image.Properties) if shared.InterfaceToBool(image.Public) { public = gettext.Gettext("yes") } const layout = "Jan 2, 2006 at 3:04pm (MST)" uploaded := time.Unix(image.UploadDate, 0).Format(layout) arch, _ := shared.ArchitectureName(image.Architecture) data = append(data, []string{shortest, fp, public, description, arch, uploaded}) } table := tablewriter.NewWriter(os.Stdout) table.SetColWidth(50) table.SetHeader([]string{ gettext.Gettext("ALIAS"), gettext.Gettext("FINGERPRINT"), gettext.Gettext("PUBLIC"), gettext.Gettext("DESCRIPTION"), gettext.Gettext("ARCH"), gettext.Gettext("UPLOAD DATE")}) sort.Sort(ByName(data)) table.AppendBulk(data) table.Render() return nil }
func showImages(images []shared.ImageInfo) error { data := [][]string{} for _, image := range images { shortest := shortestAlias(image.Aliases) if len(image.Aliases) > 1 { shortest = fmt.Sprintf("%s (%d more)", shortest, len(image.Aliases)-1) } fp := image.Fingerprint[0:12] public := "no" description := findDescription(image.Properties) if image.Public == 1 { public = "yes" } const layout = "Jan 2, 2006 at 3:04pm (MST)" uploaded := time.Unix(image.UploadDate, 0).Format(layout) arch, _ := shared.ArchitectureName(image.Architecture) data = append(data, []string{shortest, fp, public, description, arch, uploaded}) } table := tablewriter.NewWriter(os.Stdout) table.SetColWidth(50) table.SetHeader([]string{"ALIAS", "FINGERPRINT", "PUBLIC", "DESCRIPTION", "ARCH", "UPLOAD DATE"}) for _, v := range data { table.Append(v) } table.Render() return nil }
func newInstanceSummary(info *shared.ContainerState) InstanceSummary { archStr, _ := shared.ArchitectureName(info.Architecture) archStr = arch.NormaliseArch(archStr) var numCores uint = 0 // default to all if raw := info.Config["limits.cpus"]; raw != "" { fmt.Sscanf(raw, "%d", &numCores) } var mem uint = 0 // default to all if raw := info.Config["limits.memory"]; raw != "" { fmt.Sscanf(raw, "%d", &mem) } var addrs []network.Address for _, info := range info.Status.Ips { addr := network.NewAddress(info.Address) // Ignore loopback devices. // TODO(ericsnow) Move the loopback test to a network.Address method? ip := net.ParseIP(addr.Value) if ip != nil && ip.IsLoopback() { continue } addrs = append(addrs, addr) } // TODO(ericsnow) Factor this out into a function. statusStr := info.Status.Status for status, code := range allStatuses { if info.Status.StatusCode == code { statusStr = status break } } metadata := extractMetadata(info.Config) return InstanceSummary{ Name: info.Name, Status: statusStr, Metadata: metadata, Addresses: addrs, Hardware: InstanceHardware{ Architecture: archStr, NumCores: numCores, MemoryMB: mem, }, } }
func (s *instanceSuite) TestNewInstanceSummaryTemplate(c *gc.C) { archStr, err := lxdshared.ArchitectureName(lxdshared.ARCH_64BIT_INTEL_X86) c.Assert(err, jc.ErrorIsNil) c.Check(templateContainerInfo.Architecture, gc.Equals, archStr) summary := lxdclient.NewInstanceSummary(&templateContainerInfo) c.Check(summary.Name, gc.Equals, "container-name") c.Check(summary.Status, gc.Equals, lxdclient.StatusStarting) c.Check(summary.Hardware.Architecture, gc.Equals, "amd64") c.Check(summary.Hardware.NumCores, gc.Equals, uint(2)) c.Check(summary.Hardware.MemoryMB, gc.Equals, uint(256)) // NotImplemented yet c.Check(summary.Hardware.RootDiskMB, gc.Equals, uint64(0)) c.Check(summary.Metadata, gc.DeepEquals, map[string]string{"something": "something value"}) }
func showImages(images []shared.ImageInfo, filters []string) error { data := [][]string{} for _, image := range images { if !imageShouldShow(filters, &image) { continue } shortest := shortestAlias(image.Aliases) if len(image.Aliases) > 1 { shortest = fmt.Sprintf(i18n.G("%s (%d more)"), shortest, len(image.Aliases)-1) } fp := image.Fingerprint[0:12] public := i18n.G("no") description := findDescription(image.Properties) // FIXME: InterfaceToBool is there for backward compatibility if shared.InterfaceToBool(image.Public) { public = i18n.G("yes") } const layout = "Jan 2, 2006 at 3:04pm (MST)" uploaded := time.Unix(image.UploadDate, 0).Format(layout) arch, _ := shared.ArchitectureName(image.Architecture) size := fmt.Sprintf("%.2fMB", float64(image.Size)/1024.0/1024.0) data = append(data, []string{shortest, fp, public, description, arch, size, uploaded}) } table := tablewriter.NewWriter(os.Stdout) table.SetColWidth(50) table.SetHeader([]string{ i18n.G("ALIAS"), i18n.G("FINGERPRINT"), i18n.G("PUBLIC"), i18n.G("DESCRIPTION"), i18n.G("ARCH"), i18n.G("SIZE"), i18n.G("UPLOAD DATE")}) sort.Sort(ByName(data)) table.AppendBulk(data) table.Render() return nil }
// dbImageGet gets an ImageBaseInfo object from the database. // The argument fingerprint will be queried with a LIKE query, means you can // pass a shortform and will get the full fingerprint. // There can never be more than one image with a given fingerprint, as it is // enforced by a UNIQUE constraint in the schema. func dbImageGet(db *sql.DB, fingerprint string, public bool, strictMatching bool) (int, *shared.ImageInfo, error) { var err error var create, expire, used, upload *time.Time // These hold the db-returned times // The object we'll actually return image := shared.ImageInfo{} id := -1 arch := -1 // These two humongous things will be filled by the call to DbQueryRowScan outfmt := []interface{}{&id, &image.Fingerprint, &image.Filename, &image.Size, &image.Cached, &image.Public, &image.AutoUpdate, &arch, &create, &expire, &used, &upload} var query string var inargs []interface{} if strictMatching { inargs = []interface{}{fingerprint} query = ` SELECT id, fingerprint, filename, size, cached, public, auto_update, architecture, creation_date, expiry_date, last_use_date, upload_date FROM images WHERE fingerprint = ?` } else { inargs = []interface{}{fingerprint + "%"} query = ` SELECT id, fingerprint, filename, size, cached, public, auto_update, architecture, creation_date, expiry_date, last_use_date, upload_date FROM images WHERE fingerprint LIKE ?` } if public { query = query + " AND public=1" } err = dbQueryRowScan(db, query, inargs, outfmt) if err != nil { return -1, nil, err // Likely: there are no rows for this fingerprint } // Some of the dates can be nil in the DB, let's process them. if create != nil { image.CreationDate = *create } else { image.CreationDate = time.Time{} } if expire != nil { image.ExpiryDate = *expire } else { image.ExpiryDate = time.Time{} } if used != nil { image.LastUsedDate = *used } else { image.LastUsedDate = time.Time{} } image.Architecture, _ = shared.ArchitectureName(arch) // The upload date is enforced by NOT NULL in the schema, so it can never be nil. image.UploadDate = *upload // Get the properties q := "SELECT key, value FROM images_properties where image_id=?" var key, value, name, desc string inargs = []interface{}{id} outfmt = []interface{}{key, value} results, err := dbQueryScan(db, q, inargs, outfmt) if err != nil { return -1, nil, err } properties := map[string]string{} for _, r := range results { key = r[0].(string) value = r[1].(string) properties[key] = value } image.Properties = properties // Get the aliases q = "SELECT name, description FROM images_aliases WHERE image_id=?" inargs = []interface{}{id} outfmt = []interface{}{name, desc} results, err = dbQueryScan(db, q, inargs, outfmt) if err != nil { return -1, nil, err } aliases := []shared.ImageAlias{} for _, r := range results { name = r[0].(string) desc = r[0].(string) a := shared.ImageAlias{Name: name, Description: desc} aliases = append(aliases, a) } image.Aliases = aliases _, source, err := dbImageSourceGet(db, id) if err == nil { image.Source = &source } return id, &image, nil }
func (c *imageCmd) run(config *lxd.Config, args []string) error { var remote string if len(args) < 1 { return errArgs } switch args[0] { case "alias": if len(args) < 2 { return errArgs } return doImageAlias(config, args) case "copy": /* copy [<remote>:]<image> [<rmeote>:]<image> */ if len(args) != 3 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } destRemote, outName := config.ParseRemoteAndContainer(args[2]) if outName != "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } dest, err := lxd.NewClient(config, destRemote) if err != nil { return err } image := dereferenceAlias(d, inName) return d.CopyImage(image, dest, copyAliases, addAliases, publicImage) case "delete": /* delete [<remote>:]<image> */ if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) err = d.DeleteImage(image) return err case "info": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) info, err := d.GetImageInfo(image) if err != nil { return err } fmt.Printf(gettext.Gettext("Fingerprint: %s")+"\n", info.Fingerprint) public := gettext.Gettext("no") if shared.InterfaceToBool(info) { public = gettext.Gettext("yes") } fmt.Printf(gettext.Gettext("Size: %.2vMB")+"\n", float64(info.Size)/1024.0/1024.0) arch, _ := shared.ArchitectureName(info.Architecture) fmt.Printf(gettext.Gettext("Architecture: %s")+"\n", arch) fmt.Printf(gettext.Gettext("Public: %s")+"\n", public) fmt.Printf(gettext.Gettext("Timestamps:") + "\n") const layout = "2006/01/02 15:04 UTC" if info.CreationDate != 0 { fmt.Printf(" "+gettext.Gettext("Created: %s")+"\n", time.Unix(info.CreationDate, 0).UTC().Format(layout)) } fmt.Printf(" "+gettext.Gettext("Uploaded: %s")+"\n", time.Unix(info.UploadDate, 0).UTC().Format(layout)) if info.ExpiryDate != 0 { fmt.Printf(" "+gettext.Gettext("Expires: %s")+"\n", time.Unix(info.ExpiryDate, 0).UTC().Format(layout)) } else { fmt.Printf(" " + gettext.Gettext("Expires: never") + "\n") } fmt.Println(gettext.Gettext("Properties:")) for key, value := range info.Properties { fmt.Printf(" %s: %s\n", key, value) } fmt.Println(gettext.Gettext("Aliases:")) for _, alias := range info.Aliases { fmt.Printf(" - %s\n", alias.Name) } return nil case "import": if len(args) < 2 { return errArgs } var imageFile string var rootfsFile string var properties []string var remote string for _, arg := range args[1:] { split := strings.Split(arg, "=") if len(split) == 1 || shared.PathExists(arg) { if strings.HasSuffix(arg, ":") { remote = config.ParseRemote(arg) } else { if imageFile == "" { imageFile = args[1] } else { rootfsFile = arg } } } else { properties = append(properties, arg) } } if imageFile == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } fingerprint, err := d.PostImage(imageFile, rootfsFile, properties, publicImage, addAliases) if err != nil { return err } fmt.Printf(gettext.Gettext("Image imported with fingerprint: %s")+"\n", fingerprint) return nil case "list": if len(args) > 1 { remote, _ = config.ParseRemoteAndContainer(args[1]) } else { remote, _ = config.ParseRemoteAndContainer("") } d, err := lxd.NewClient(config, remote) if err != nil { return err } images, err := d.ListImages() if err != nil { return err } return showImages(images) case "edit": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) if image == "" { image = inName } if !terminal.IsTerminal(syscall.Stdin) { contents, err := ioutil.ReadAll(os.Stdin) if err != nil { return err } newdata := shared.BriefImageInfo{} err = yaml.Unmarshal(contents, &newdata) if err != nil { return err } return d.PutImageInfo(image, newdata) } info, err := d.GetImageInfo(image) if err != nil { return err } properties := info.BriefInfo() editor := os.Getenv("VISUAL") if editor == "" { editor = os.Getenv("EDITOR") if editor == "" { editor = "vi" } } data, err := yaml.Marshal(&properties) f, err := ioutil.TempFile("", "lxd_lxc_image_") if err != nil { return err } fname := f.Name() if err = f.Chmod(0600); err != nil { f.Close() os.Remove(fname) return err } f.Write([]byte(imageEditHelp + "\n")) f.Write(data) f.Close() defer os.Remove(fname) for { cmdParts := strings.Fields(editor) cmd := exec.Command(cmdParts[0], append(cmdParts[1:], fname)...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err = cmd.Run() if err != nil { return err } contents, err := ioutil.ReadFile(fname) if err != nil { return err } newdata := shared.BriefImageInfo{} err = yaml.Unmarshal(contents, &newdata) if err != nil { fmt.Fprintf(os.Stderr, gettext.Gettext("YAML parse error %v")+"\n", err) fmt.Println(gettext.Gettext("Press enter to open the editor again")) _, err := os.Stdin.Read(make([]byte, 1)) if err != nil { return err } continue } err = d.PutImageInfo(image, newdata) break } return err case "export": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) target := "." if len(args) > 2 { target = args[2] } _, outfile, err := d.ExportImage(image, target) if err != nil { return err } if target != "-" { fmt.Printf(gettext.Gettext("Output is in %s")+"\n", outfile) } return nil case "show": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) info, err := d.GetImageInfo(image) if err != nil { return err } properties := info.BriefInfo() data, err := yaml.Marshal(&properties) fmt.Printf("%s", data) return err default: return fmt.Errorf(gettext.Gettext("Unknown image command %s"), args[0]) } }
func containerCreateInternal(d *Daemon, args containerArgs) (container, error) { // Set default values if args.Profiles == nil { args.Profiles = []string{"default"} } if args.Config == nil { args.Config = map[string]string{} } if args.BaseImage != "" { args.Config["volatile.base_image"] = args.BaseImage } if args.Devices == nil { args.Devices = shared.Devices{} } if args.Architecture == 0 { args.Architecture = d.architectures[0] } // Validate container name if args.Ctype == cTypeRegular { err := containerValidName(args.Name) if err != nil { return nil, err } } // Validate container config err := containerValidConfig(d, args.Config, false, false) if err != nil { return nil, err } // Validate container devices err = containerValidDevices(args.Devices, false, false) if err != nil { return nil, err } // Validate architecture _, err = shared.ArchitectureName(args.Architecture) if err != nil { return nil, err } // Validate profiles profiles, err := dbProfiles(d.db) if err != nil { return nil, err } for _, profile := range args.Profiles { if !shared.StringInSlice(profile, profiles) { return nil, fmt.Errorf("Requested profile '%s' doesn't exist", profile) } } path := containerPath(args.Name, args.Ctype == cTypeSnapshot) if shared.PathExists(path) { if shared.IsSnapshot(args.Name) { return nil, fmt.Errorf("Snapshot '%s' already exists", args.Name) } return nil, fmt.Errorf("The container already exists") } // Wipe any existing log for this container name os.RemoveAll(shared.LogPath(args.Name)) // Create the container entry id, err := dbContainerCreate(d.db, args) if err != nil { return nil, err } args.Id = id // Read the timestamp from the database dbArgs, err := dbContainerGet(d.db, args.Name) if err != nil { return nil, err } args.CreationDate = dbArgs.CreationDate args.LastUsedDate = dbArgs.LastUsedDate return containerLXCCreate(d, args) }
func (c *imageCmd) run(config *lxd.Config, args []string) error { var remote string if len(args) < 1 { return errArgs } switch args[0] { case "alias": if len(args) < 2 { return errArgs } return doImageAlias(config, args) case "copy": /* copy [<remote>:]<image> [<rmeote>:]<image> */ if len(args) != 3 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } destRemote, outName := config.ParseRemoteAndContainer(args[2]) if outName != "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } dest, err := lxd.NewClient(config, destRemote) if err != nil { return err } image := dereferenceAlias(d, inName) progressHandler := func(progress string) { fmt.Printf(i18n.G("Copying the image: %s")+"\r", progress) } return d.CopyImage(image, dest, copyAliases, addAliases, publicImage, progressHandler) case "delete": /* delete [<remote>:]<image> */ if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) err = d.DeleteImage(image) return err case "info": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) info, err := d.GetImageInfo(image) if err != nil { return err } fmt.Printf(i18n.G("Fingerprint: %s")+"\n", info.Fingerprint) public := i18n.G("no") // FIXME: InterfaceToBool is there for backward compatibility if shared.InterfaceToBool(info) { public = i18n.G("yes") } fmt.Printf(i18n.G("Size: %.2fMB")+"\n", float64(info.Size)/1024.0/1024.0) arch, _ := shared.ArchitectureName(info.Architecture) fmt.Printf(i18n.G("Architecture: %s")+"\n", arch) fmt.Printf(i18n.G("Public: %s")+"\n", public) fmt.Printf(i18n.G("Timestamps:") + "\n") const layout = "2006/01/02 15:04 UTC" if info.CreationDate != 0 { fmt.Printf(" "+i18n.G("Created: %s")+"\n", time.Unix(info.CreationDate, 0).UTC().Format(layout)) } fmt.Printf(" "+i18n.G("Uploaded: %s")+"\n", time.Unix(info.UploadDate, 0).UTC().Format(layout)) if info.ExpiryDate != 0 { fmt.Printf(" "+i18n.G("Expires: %s")+"\n", time.Unix(info.ExpiryDate, 0).UTC().Format(layout)) } else { fmt.Printf(" " + i18n.G("Expires: never") + "\n") } fmt.Println(i18n.G("Properties:")) for key, value := range info.Properties { fmt.Printf(" %s: %s\n", key, value) } fmt.Println(i18n.G("Aliases:")) for _, alias := range info.Aliases { fmt.Printf(" - %s\n", alias.Name) } return nil case "import": if len(args) < 2 { return errArgs } var fingerprint string var imageFile string var rootfsFile string var properties []string var remote string for _, arg := range args[1:] { split := strings.Split(arg, "=") if len(split) == 1 || shared.PathExists(arg) { if strings.HasSuffix(arg, ":") { remote = config.ParseRemote(arg) } else { if imageFile == "" { imageFile = args[1] } else { rootfsFile = arg } } } else { properties = append(properties, arg) } } if remote == "" { remote = config.DefaultRemote } if imageFile == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } if strings.HasPrefix(imageFile, "https://") { fingerprint, err = d.PostImageURL(imageFile, publicImage, addAliases) } else if strings.HasPrefix(imageFile, "http://") { return fmt.Errorf(i18n.G("Only https:// is supported for remote image import.")) } else { fingerprint, err = d.PostImage(imageFile, rootfsFile, properties, publicImage, addAliases) } if err != nil { return err } fmt.Printf(i18n.G("Image imported with fingerprint: %s")+"\n", fingerprint) return nil case "list": filters := []string{} if len(args) > 1 { result := strings.SplitN(args[1], ":", 2) if len(result) == 1 { filters = append(filters, args[1]) remote, _ = config.ParseRemoteAndContainer("") } else { remote, _ = config.ParseRemoteAndContainer(args[1]) } } else { remote, _ = config.ParseRemoteAndContainer("") } if len(args) > 2 { for _, filter := range args[2:] { filters = append(filters, filter) } } d, err := lxd.NewClient(config, remote) if err != nil { return err } images, err := d.ListImages() if err != nil { return err } return showImages(images, filters) case "edit": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) if image == "" { image = inName } return doImageEdit(d, image) case "export": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) target := "." if len(args) > 2 { target = args[2] } _, outfile, err := d.ExportImage(image, target) if err != nil { return err } if target != "-" { fmt.Printf(i18n.G("Output is in %s")+"\n", outfile) } return nil case "show": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) info, err := d.GetImageInfo(image) if err != nil { return err } properties := info.BriefInfo() data, err := yaml.Marshal(&properties) fmt.Printf("%s", data) return err default: return errArgs } }
func (c *containerLXD) TemplateApply(trigger string) error { fname := path.Join(c.PathGet(""), "metadata.yaml") if !shared.PathExists(fname) { return nil } content, err := ioutil.ReadFile(fname) if err != nil { return err } metadata := new(imageMetadata) err = yaml.Unmarshal(content, &metadata) if err != nil { return fmt.Errorf("Could not parse %s: %v", fname, err) } for filepath, template := range metadata.Templates { var w *os.File found := false for _, tplTrigger := range template.When { if tplTrigger == trigger { found = true break } } if !found { continue } fullpath := shared.VarPath("containers", c.name, "rootfs", strings.TrimLeft(filepath, "/")) if shared.PathExists(fullpath) { w, err = os.Create(fullpath) if err != nil { return err } } else { uid := 0 gid := 0 if !c.IsPrivileged() { uid, gid = c.idmapset.ShiftIntoNs(0, 0) } shared.MkdirAllOwner(path.Dir(fullpath), 0755, uid, gid) w, err = os.Create(fullpath) if err != nil { return err } if !c.IsPrivileged() { w.Chown(uid, gid) } w.Chmod(0644) } tplString, err := ioutil.ReadFile(shared.VarPath("containers", c.name, "templates", template.Template)) if err != nil { return err } tpl, err := pongo2.FromString("{% autoescape off %}" + string(tplString) + "{% endautoescape %}") if err != nil { return err } containerMeta := make(map[string]string) containerMeta["name"] = c.name containerMeta["architecture"], _ = shared.ArchitectureName(c.architecture) if c.ephemeral { containerMeta["ephemeral"] = "true" } else { containerMeta["ephemeral"] = "false" } if c.IsPrivileged() { containerMeta["privileged"] = "true" } else { containerMeta["privileged"] = "false" } configGet := func(confKey, confDefault *pongo2.Value) *pongo2.Value { val, ok := c.config[confKey.String()] if !ok { return confDefault } return pongo2.AsValue(strings.TrimRight(val, "\r\n")) } tpl.ExecuteWriter(pongo2.Context{"trigger": trigger, "path": filepath, "container": containerMeta, "config": c.config, "devices": c.devices, "properties": template.Properties, "config_get": configGet}, w) } return nil }
/* * This function takes a container or snapshot from the local image server and * exports it as an image. */ func imgPostContInfo(d *Daemon, r *http.Request, req imagePostReq, builddir string) (info shared.ImageInfo, err error) { info.Properties = map[string]string{} name := req.Source["name"] ctype := req.Source["type"] if ctype == "" || name == "" { return info, fmt.Errorf("No source provided") } switch ctype { case "snapshot": if !shared.IsSnapshot(name) { return info, fmt.Errorf("Not a snapshot") } case "container": if shared.IsSnapshot(name) { return info, fmt.Errorf("This is a snapshot") } default: return info, fmt.Errorf("Bad type") } info.Filename = req.Filename switch req.Public { case true: info.Public = true case false: info.Public = false } c, err := containerLoadByName(d, name) if err != nil { return info, err } // Build the actual image file tarfile, err := ioutil.TempFile(builddir, "lxd_build_tar_") if err != nil { return info, err } defer os.Remove(tarfile.Name()) if err := c.Export(tarfile, req.Properties); err != nil { tarfile.Close() return info, err } tarfile.Close() var compressedPath string var compress string if req.CompressionAlgorithm != "" { compress = req.CompressionAlgorithm } else { compress = daemonConfig["images.compression_algorithm"].Get() } if compress != "none" { compressedPath, err = compressFile(tarfile.Name(), compress) if err != nil { return info, err } } else { compressedPath = tarfile.Name() } defer os.Remove(compressedPath) sha256 := sha256.New() tarf, err := os.Open(compressedPath) if err != nil { return info, err } info.Size, err = io.Copy(sha256, tarf) tarf.Close() if err != nil { return info, err } info.Fingerprint = fmt.Sprintf("%x", sha256.Sum(nil)) _, _, err = dbImageGet(d.db, info.Fingerprint, false, true) if err == nil { return info, fmt.Errorf("The image already exists: %s", info.Fingerprint) } /* rename the the file to the expected name so our caller can use it */ finalName := shared.VarPath("images", info.Fingerprint) err = shared.FileMove(compressedPath, finalName) if err != nil { return info, err } info.Architecture, _ = shared.ArchitectureName(c.Architecture()) info.Properties = req.Properties return info, nil }
func api10Get(d *Daemon, r *http.Request) Response { body := shared.Jmap{ "api_extensions": []string{}, "api_status": "development", "api_version": shared.APIVersion, } if d.isTrustedClient(r) { body["auth"] = "trusted" /* * Based on: https://groups.google.com/forum/#!topic/golang-nuts/Jel8Bb-YwX8 * there is really no better way to do this, which is * unfortunate. Also, we ditch the more accepted CharsToString * version in that thread, since it doesn't seem as portable, * viz. github issue #206. */ uname := syscall.Utsname{} if err := syscall.Uname(&uname); err != nil { return InternalError(err) } kernel := "" for _, c := range uname.Sysname { if c == 0 { break } kernel += string(byte(c)) } kernelVersion := "" for _, c := range uname.Release { if c == 0 { break } kernelVersion += string(byte(c)) } kernelArchitecture := "" for _, c := range uname.Machine { if c == 0 { break } kernelArchitecture += string(byte(c)) } addresses, err := d.ListenAddresses() if err != nil { return InternalError(err) } var certificate string if len(d.tlsConfig.Certificates) != 0 { certificate = string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: d.tlsConfig.Certificates[0].Certificate[0]})) } architectures := []string{} for _, architecture := range d.architectures { architectureName, err := shared.ArchitectureName(architecture) if err != nil { return InternalError(err) } architectures = append(architectures, architectureName) } env := shared.Jmap{ "addresses": addresses, "architectures": architectures, "certificate": certificate, "driver": "lxc", "driver_version": lxc.Version(), "kernel": kernel, "kernel_architecture": kernelArchitecture, "kernel_version": kernelVersion, "storage": d.Storage.GetStorageTypeName(), "storage_version": d.Storage.GetStorageTypeVersion(), "server": "lxd", "server_pid": os.Getpid(), "server_version": shared.Version} body["environment"] = env body["public"] = false serverConfig, err := d.ConfigValuesGet() if err != nil { return InternalError(err) } config := shared.Jmap{} for key, value := range serverConfig { if key == "core.trust_password" { config[key] = true } else { config[key] = value } } body["config"] = config } else { body["auth"] = "untrusted" body["public"] = false } return SyncResponse(true, body) }
func templateApply(c *lxdContainer, trigger string) error { fname := shared.VarPath("lxc", c.name, "metadata.yaml") if _, err := os.Stat(fname); err != nil { return nil } content, err := ioutil.ReadFile(fname) if err != nil { return err } metadata := new(imageMetadata) err = yaml.Unmarshal(content, &metadata) if err != nil { return fmt.Errorf("Could not parse %s: %v", fname, err) } for path, template := range metadata.Templates { var w *os.File found := false for _, tplTrigger := range template.When { if tplTrigger == trigger { found = true break } } if !found { continue } fpath := shared.VarPath("lxc", c.name, "rootfs", strings.TrimLeft(path, "/")) if _, err := os.Stat(fpath); err == nil { w, err = os.Create(fpath) if err != nil { return err } } else { w, err = os.Create(fpath) if err != nil { return err } uid, gid := c.idmapset.ShiftIntoNs(0, 0) w.Chown(uid, gid) w.Chmod(0644) } tpl, err := pongo2.FromFile(shared.VarPath("lxc", c.name, "templates", template.Template)) if err != nil { return err } container_meta := make(map[string]string) container_meta["name"] = c.name container_meta["architecture"], _ = shared.ArchitectureName(c.architecture) if c.ephemeral { container_meta["ephemeral"] = "true" } else { container_meta["ephemeral"] = "false" } if c.isPrivileged() { container_meta["privileged"] = "true" } else { container_meta["privileged"] = "false" } tpl.ExecuteWriter(pongo2.Context{"trigger": trigger, "path": path, "container": container_meta, "config": c.config, "devices": c.devices, "properties": template.Properties}, w) } return nil }
func infoWithArchitecture(arch int) *lxdshared.ContainerInfo { info := templateContainerInfo info.Architecture, _ = lxdshared.ArchitectureName(arch) return &info }
func api10Get(d *Daemon, r *http.Request) Response { body := shared.Jmap{ /* List of API extensions in the order they were added. * * The following kind of changes require an addition to api_extensions: * - New configuration key * - New valid values for a configuration key * - New REST API endpoint * - New argument inside an existing REST API call * - New HTTPs authentication mechanisms or protocols */ "api_extensions": []string{ "storage_zfs_remove_snapshots", "container_host_shutdown_timeout", "container_syscall_filtering", "auth_pki", "container_last_used_at", "etag", "patch", "usb_devices", "https_allowed_credentials", "image_compression_algorithm", "directory_manipulation", "container_cpu_time", "storage_zfs_use_refquota", "storage_lvm_mount_options", "network", "profile_usedby", "container_push", "container_exec_recording", "certificate_update", "container_exec_signal_handling", "gpu_devices", "container_image_properties", "migration_progress", "id_map", }, "api_status": "stable", "api_version": shared.APIVersion, } if d.isTrustedClient(r) { body["auth"] = "trusted" /* * Based on: https://groups.google.com/forum/#!topic/golang-nuts/Jel8Bb-YwX8 * there is really no better way to do this, which is * unfortunate. Also, we ditch the more accepted CharsToString * version in that thread, since it doesn't seem as portable, * viz. github issue #206. */ uname := syscall.Utsname{} if err := syscall.Uname(&uname); err != nil { return InternalError(err) } kernel := "" for _, c := range uname.Sysname { if c == 0 { break } kernel += string(byte(c)) } kernelVersion := "" for _, c := range uname.Release { if c == 0 { break } kernelVersion += string(byte(c)) } kernelArchitecture := "" for _, c := range uname.Machine { if c == 0 { break } kernelArchitecture += string(byte(c)) } addresses, err := d.ListenAddresses() if err != nil { return InternalError(err) } var certificate string if len(d.tlsConfig.Certificates) != 0 { certificate = string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: d.tlsConfig.Certificates[0].Certificate[0]})) } architectures := []string{} for _, architecture := range d.architectures { architectureName, err := shared.ArchitectureName(architecture) if err != nil { return InternalError(err) } architectures = append(architectures, architectureName) } env := shared.Jmap{ "addresses": addresses, "architectures": architectures, "certificate": certificate, "driver": "lxc", "driver_version": lxc.Version(), "kernel": kernel, "kernel_architecture": kernelArchitecture, "kernel_version": kernelVersion, "storage": d.Storage.GetStorageTypeName(), "storage_version": d.Storage.GetStorageTypeVersion(), "server": "lxd", "server_pid": os.Getpid(), "server_version": shared.Version} body["environment"] = env body["public"] = false body["config"] = daemonConfigRender() } else { body["auth"] = "untrusted" body["public"] = false } return SyncResponseETag(true, body, body["config"]) }