func doImageGet(d *Daemon, fingerprint string, public bool) (shared.ImageInfo, Response) { imgInfo, err := dbImageGet(d.db, fingerprint, public) if err != nil { return shared.ImageInfo{}, SmartError(err) } q := "SELECT key, value FROM images_properties where image_id=?" var key, value, name, desc string inargs := []interface{}{imgInfo.Id} outfmt := []interface{}{key, value} results, err := shared.DbQueryScan(d.db, q, inargs, outfmt) if err != nil { return shared.ImageInfo{}, SmartError(err) } properties := map[string]string{} for _, r := range results { key = r[0].(string) value = r[1].(string) properties[key] = value } q = "SELECT name, description FROM images_aliases WHERE image_id=?" inargs = []interface{}{imgInfo.Id} outfmt = []interface{}{name, desc} results, err = shared.DbQueryScan(d.db, q, inargs, outfmt) if err != nil { return shared.ImageInfo{}, InternalError(err) } aliases := shared.ImageAliases{} for _, r := range results { name = r[0].(string) desc = r[0].(string) a := shared.ImageAlias{Name: name, Description: desc} aliases = append(aliases, a) } info := shared.ImageInfo{Fingerprint: imgInfo.Fingerprint, Filename: imgInfo.Filename, Properties: properties, Aliases: aliases, Public: imgInfo.Public, Size: imgInfo.Size, Architecture: imgInfo.Architecture, CreationDate: imgInfo.CreationDate, ExpiryDate: imgInfo.ExpiryDate, UploadDate: imgInfo.UploadDate} return info, nil }
/* * Note, the code below doesn't deal with snapshots of snapshots. * To do that, we'll need to weed out based on # slashes in names */ func nextSnapshot(d *Daemon, name string) int { base := fmt.Sprintf("%s/snap", name) length := len(base) q := fmt.Sprintf("SELECT MAX(name) FROM containers WHERE type=? AND SUBSTR(name,1,?)=?") var numstr string inargs := []interface{}{cTypeSnapshot, length, base} outfmt := []interface{}{numstr} results, err := shared.DbQueryScan(d.db, q, inargs, outfmt) if err != nil { return 0 } max := 0 for _, r := range results { numstr = r[0].(string) if len(numstr) <= length { continue } substr := numstr[length:] var num int count, err := fmt.Sscanf(substr, "%d", &num) if err != nil || count != 1 { continue } if num >= max { max = num + 1 } } return max }
func containersWatch(d *Daemon) error { q := fmt.Sprintf("SELECT name FROM containers WHERE type=?") inargs := []interface{}{cTypeRegular} var name string outfmt := []interface{}{name} result, err := shared.DbQueryScan(d.db, q, inargs, outfmt) if err != nil { return err } for _, r := range result { container, err := newLxdContainer(string(r[0].(string)), d) if err != nil { return err } if container.ephemeral == true && container.c.State() != lxc.STOPPED { containerWatchEphemeral(container) } } /* * force collect the containers we created above; see comment in * daemon.go:createCmd. */ runtime.GC() return nil }
// Get a list of profiles for a given container id. func dbGetProfiles(db *sql.DB, containerId int) ([]string, error) { var name string var profiles []string query := ` SELECT name FROM containers_profiles JOIN profiles ON containers_profiles.profile_id=profiles.id WHERE container_id=? ORDER BY containers_profiles.apply_order` inargs := []interface{}{containerId} outfmt := []interface{}{name} results, err := shared.DbQueryScan(db, query, inargs, outfmt) if err != nil { return nil, err } for _, r := range results { name = r[0].(string) profiles = append(profiles, name) } return profiles, nil }
func dbGetDeviceConfig(db *sql.DB, id int, isprofile bool) (shared.Device, error) { var query string var key, value string newdev := shared.Device{} // That's a map[string]string inargs := []interface{}{id} outfmt := []interface{}{key, value} if isprofile { query = `SELECT key, value FROM profiles_devices_config WHERE profile_device_id=?` } else { query = `SELECT key, value FROM containers_devices_config WHERE container_device_id=?` } results, err := shared.DbQueryScan(db, query, inargs, outfmt) if err != nil { return newdev, err } for _, r := range results { key = r[0].(string) value = r[1].(string) newdev[key] = value } return newdev, nil }
func containersRestart(d *Daemon) error { q := fmt.Sprintf("SELECT name FROM containers WHERE type=? AND power_state=1") inargs := []interface{}{cTypeRegular} var name string outfmt := []interface{}{name} result, err := shared.DbQueryScan(d.db, q, inargs, outfmt) if err != nil { return err } _, err = shared.DbExec(d.db, "UPDATE containers SET power_state=0") if err != nil { return err } for _, r := range result { container, err := newLxdContainer(string(r[0].(string)), d) if err != nil { return err } err = templateApply(container, "start") if err != nil { return err } container.c.Start() } return nil }
func aliasesGet(d *Daemon, r *http.Request) Response { recursion := d.isRecursionRequest(r) q := "SELECT name FROM images_aliases" var name string inargs := []interface{}{} outfmt := []interface{}{name} results, err := shared.DbQueryScan(d.db, q, inargs, outfmt) if err != nil { return BadRequest(err) } response_str := make([]string, 0) response_map := make([]shared.ImageAlias, 0) for _, res := range results { name = res[0].(string) if !recursion { url := fmt.Sprintf("/%s/images/aliases/%s", shared.APIVersion, name) response_str = append(response_str, url) } else { alias, err := doAliasGet(d, name, d.isTrustedClient(r)) if err != nil { continue } response_map = append(response_map, alias) } } if !recursion { return SyncResponse(true, response_str) } else { return SyncResponse(true, response_map) } }
// Get the profile configuration map from the DB func dbGetProfileConfig(db *sql.DB, name string) (map[string]string, error) { var key, value string query := ` SELECT key, value FROM profiles_config JOIN profiles ON profiles_config.profile_id=profiles.id WHERE name=?` inargs := []interface{}{name} outfmt := []interface{}{key, value} results, err := shared.DbQueryScan(db, query, inargs, outfmt) if err != nil { return nil, err } if len(results) == 0 { /* * If we didn't get any rows here, let's check to make sure the * profile really exists; if it doesn't, let's send back a 404. */ query := "SELECT id FROM profiles WHERE name=?" var id int results, err := shared.DbQueryScan(db, query, []interface{}{name}, []interface{}{id}) if err != nil { return nil, err } if len(results) == 0 { return nil, NoSuchObjectError } } config := map[string]string{} for _, r := range results { key = r[0].(string) value = r[1].(string) config[key] = value } return config, nil }
func containerSnapshotsGet(d *Daemon, r *http.Request) Response { recursion_str := r.FormValue("recursion") recursion, err := strconv.Atoi(recursion_str) if err != nil { recursion = 0 } cname := mux.Vars(r)["name"] c, err := newLxdContainer(cname, d) if err != nil { return SmartError(err) } regexp := fmt.Sprintf("%s/", cname) length := len(regexp) q := "SELECT name FROM containers WHERE type=? AND SUBSTR(name,1,?)=?" var name string inargs := []interface{}{cTypeSnapshot, length, regexp} outfmt := []interface{}{name} results, err := shared.DbQueryScan(d.db, q, inargs, outfmt) if err != nil { return SmartError(err) } var result_string []string var result_map []shared.Jmap for _, r := range results { name = r[0].(string) if recursion == 0 { url := fmt.Sprintf("/%s/containers/%s/snapshots/%s", shared.APIVersion, cname, name) result_string = append(result_string, url) } else { _, err := os.Stat(snapshotStateDir(c, name)) body := shared.Jmap{"name": name, "stateful": err == nil} result_map = append(result_map, body) } } if recursion == 0 { return SyncResponse(true, result_string) } else { return SyncResponse(true, result_map) } }
func dbListContainers(d *Daemon) ([]string, error) { q := fmt.Sprintf("SELECT name FROM containers WHERE type=? ORDER BY name") inargs := []interface{}{cTypeRegular} var container string outfmt := []interface{}{container} result, err := shared.DbQueryScan(d.db, q, inargs, outfmt) if err != nil { return nil, err } ret := make([]string, 0) for _, container := range result { ret = append(ret, container[0].(string)) } return ret, nil }
func profilesGet(d *Daemon, r *http.Request) Response { q := fmt.Sprintf("SELECT name FROM profiles") inargs := []interface{}{} var name string outfmt := []interface{}{name} result, err := shared.DbQueryScan(d.db, q, inargs, outfmt) if err != nil { return SmartError(err) } response := []string{} for _, r := range result { name := r[0].(string) url := fmt.Sprintf("/%s/profiles/%s", shared.APIVersion, name) response = append(response, url) } return SyncResponse(true, response) }
func containerDeleteSnapshots(d *Daemon, cname string) error { prefix := fmt.Sprintf("%s/", cname) length := len(prefix) q := "SELECT name, id FROM containers WHERE type=? AND SUBSTR(name,1,?)=?" var id int var sname string inargs := []interface{}{cTypeSnapshot, length, prefix} outfmt := []interface{}{sname, id} results, err := shared.DbQueryScan(d.db, q, inargs, outfmt) if err != nil { return err } var ids []int backing_fs, err := shared.GetFilesystem(shared.VarPath("lxc", cname)) if err != nil && !os.IsNotExist(err) { shared.Debugf("Error cleaning up snapshots: %s\n", err) return err } for _, r := range results { sname = r[0].(string) id = r[1].(int) ids = append(ids, id) cdir := shared.VarPath("lxc", cname, "snapshots", sname) if backing_fs == "btrfs" { exec.Command("btrfs", "subvolume", "delete", cdir).Run() } os.RemoveAll(cdir) } for _, id := range ids { _, err = shared.DbExec(d.db, "DELETE FROM containers WHERE id=?", id) if err != nil { return err } } return nil }
func doContainerGet(d *Daemon, cname string) (shared.ContainerInfo, Response) { _, err := dbGetContainerId(d.db, cname) if err != nil { return shared.ContainerInfo{}, SmartError(err) } c, err := newLxdContainer(cname, d) if err != nil { return shared.ContainerInfo{}, SmartError(err) } var name string regexp := fmt.Sprintf("%s/", cname) length := len(regexp) q := "SELECT name FROM containers WHERE type=? AND SUBSTR(name,1,?)=?" inargs := []interface{}{cTypeSnapshot, length, regexp} outfmt := []interface{}{name} results, err := shared.DbQueryScan(d.db, q, inargs, outfmt) if err != nil { return shared.ContainerInfo{}, SmartError(err) } var body []string for _, r := range results { name = r[0].(string) url := fmt.Sprintf("/%s/containers/%s/snapshots/%s", shared.APIVersion, cname, name) body = append(body, url) } cts, err := c.RenderState() if err != nil { return shared.ContainerInfo{}, SmartError(err) } containerinfo := shared.ContainerInfo{State: *cts, Snaps: body} return containerinfo, nil }
func dbGetDevices(db *sql.DB, qName string, isprofile bool) (shared.Devices, error) { var q string if isprofile { q = `SELECT profiles_devices.id, profiles_devices.name, profiles_devices.type FROM profiles_devices JOIN profiles ON profiles_devices.profile_id = profiles.id WHERE profiles.name=?` } else { q = `SELECT containers_devices.id, containers_devices.name, containers_devices.type FROM containers_devices JOIN containers ON containers_devices.container_id = containers.id WHERE containers.name=?` } var id int var name, dtype string inargs := []interface{}{qName} outfmt := []interface{}{id, name, dtype} results, err := shared.DbQueryScan(db, q, inargs, outfmt) if err != nil { return nil, err } devices := shared.Devices{} for _, r := range results { id = r[0].(int) name = r[1].(string) dtype = r[2].(string) newdev, err := dbGetDeviceConfig(db, id, isprofile) if err != nil { return nil, err } newdev["type"] = dtype devices[name] = newdev } return devices, nil }
func containersShutdown(d *Daemon) error { q := fmt.Sprintf("SELECT name FROM containers WHERE type=?") inargs := []interface{}{cTypeRegular} var name string outfmt := []interface{}{name} result, err := shared.DbQueryScan(d.db, q, inargs, outfmt) if err != nil { return err } var wg sync.WaitGroup for _, r := range result { container, err := newLxdContainer(string(r[0].(string)), d) if err != nil { return err } _, err = shared.DbExec(d.db, "UPDATE containers SET power_state=1 WHERE name=?", container.name) if err != nil { return err } if container.c.State() != lxc.STOPPED { wg.Add(1) go func() { container.c.Shutdown(time.Second * 30) container.c.Stop() wg.Done() }() } wg.Wait() } return nil }
func doImagesGet(d *Daemon, recursion bool, public bool) (interface{}, error) { result_string := make([]string, 0) result_map := make([]shared.ImageInfo, 0) q := "SELECT fingerprint FROM images" var name string if public == true { q = "SELECT fingerprint FROM images WHERE public=1" } inargs := []interface{}{} outfmt := []interface{}{name} results, err := shared.DbQueryScan(d.db, q, inargs, outfmt) if err != nil { return []string{}, err } for _, r := range results { name = r[0].(string) if !recursion { url := fmt.Sprintf("/%s/images/%s", shared.APIVersion, name) result_string = append(result_string, url) } else { image, response := doImageGet(d, name, public) if response != nil { continue } result_map = append(result_map, image) } } if !recursion { return result_string, nil } else { return result_map, nil } }
// Get the container configuration map from the DB func dbGetConfig(db *sql.DB, containerId int) (map[string]string, error) { var key, value string q := `SELECT key, value FROM containers_config WHERE container_id=?` inargs := []interface{}{containerId} outfmt := []interface{}{key, value} // Results is already a slice here, not db Rows anymore. results, err := shared.DbQueryScan(db, q, inargs, outfmt) if err != nil { return nil, err //SmartError will wrap this and make "not found" errors pretty } config := map[string]string{} for _, r := range results { key = r[0].(string) value = r[1].(string) config[key] = value } return config, nil }