func ConfigGetInt64(cluster *db.Cluster, key string) (int64, error) {
	config, err := configGet(cluster)
	if err != nil {
		return 0, err
	}
	return config.m.GetInt64(key), nil
}

func ConfigGetInt64 ( cluster * db . Cluster , key string ) ( int64 , error ) { config , err := configGet ( cluster ) if err != nil { return 0 , err } return config . m . GetInt64 ( key ) , nil }

// ConfigGetInt64 is a convenience for loading the cluster configuration and
// returning the value of a particular key.
//
// It's a deprecated API meant to be used by call sites that are not
// interacting with the database in a transactional way.

ConfigGetInt64 is a convenience for loading the cluster configuration and returning the value of a particular key . It s a deprecated API meant to be used by call sites that are not interacting with the database in a transactional way .


func (e *Endpoints) ClusterAddress() string {
	e.mu.RLock()
	defer e.mu.RUnlock()

	listener := e.listeners[cluster]
	if listener == nil {
		return ""
	}
	return listener.Addr().String()
}

func ( e * Endpoints ) ClusterAddress ( ) string { e . mu . RLock ( ) defer e . mu . RUnlock ( ) listener := e . listeners [ cluster ] if listener == nil { return " " } return listener . Addr ( ) . String ( ) }

// ClusterAddress returns the cluster addresss of the cluster endpoint, or an
// empty string if there's no cluster endpoint.

ClusterAddress returns the cluster addresss of the cluster endpoint or an empty string if there s no cluster endpoint .


func Debug(msg string, ctx ...interface{}) {
	if Log != nil {
		pc, fn, line, _ := runtime.Caller(1)
		msg := fmt.Sprintf("%s: %d: %s: %s", fn, line, runtime.FuncForPC(pc).Name(), msg)
		Log.Debug(msg, ctx...)
	}
}

func Debug ( msg string , ctx ... interface { } ) { if Log != nil { pc , fn , line , _ := runtime . Caller ( 1 ) msg := fmt . Sprintf ( " " , fn , line , runtime . FuncForPC ( pc ) . Name ( ) , msg ) Log . Debug ( msg , ctx ... ) } }

// General wrappers around Logger interface functions.

General wrappers around Logger interface functions .


func RestServer(d *Daemon) *http.Server {
	/* Setup the web server */
	mux := mux.NewRouter()
	mux.StrictSlash(false)

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		SyncResponse(true, []string{"/1.0"}).Render(w)
	})

	for endpoint, f := range d.gateway.HandlerFuncs() {
		mux.HandleFunc(endpoint, f)
	}

	for _, c := range api10 {
		d.createCmd(mux, "1.0", c)
	}

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

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

	return &http.Server{Handler: &lxdHttpServer{r: mux, d: d}}
}

func
RestServer
(
d
*
Daemon
)
*
http
.
Server
{
/* Setup the web server */
mux
:=
mux
.
NewRouter
(
)
mux
.
StrictSlash
(
false
)
mux
.
HandleFunc
(
"
"
,
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
w
.
Header
(
)
.
Set
(
"
"
,
"
"
)
SyncResponse
(
true
,
[
]
string
{
"
"
}
)
.
Render
(
w
)
}
)
for
endpoint
,
f
:=
range
d
.
gateway
.
HandlerFuncs
(
)
{
mux
.
HandleFunc
(
endpoint
,
f
)
}
for
_
,
c
:=
range
api10
{
d
.
createCmd
(
mux
,
"
"
,
c
)
}
for
_
,
c
:=
range
apiInternal
{
d
.
createCmd
(
mux
,
"
"
,
c
)
}
mux
.
NotFoundHandler
=
http
.
HandlerFunc
(
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
logger
.
Info
(
"
"
,
log
.
Ctx
{
"
"
:
r
.
URL
}
)
w
.
Header
(
)
.
Set
(
"
"
,
"
"
)
NotFound
(
)
.
Render
(
w
)
}
)
return
&
http
.
Server
{
Handler
:
&
lxdHttpServer
{
r
:
mux
,
d
:
d
}
}
}

// RestServer creates an http.Server capable of handling requests against the LXD REST
// API endpoint.

RestServer creates an http . Server capable of handling requests against the LXD REST API endpoint .


func projectParam(request *http.Request) string {
	project := queryParam(request, "project")
	if project == "" {
		project = "default"
	}
	return project
}

func projectParam ( request * http . Request ) string { project := queryParam ( request , " " ) if project == " " { project = " " } return project }

// Extract the project query parameter from the given request.

Extract the project query parameter from the given request .


func queryParam(request *http.Request, key string) string {
	var values url.Values
	var err error

	if request.URL != nil {
		values, err = url.ParseQuery(request.URL.RawQuery)
		if err != nil {
			logger.Warnf("Failed to parse query string %q: %v", request.URL.RawQuery, err)
			return ""
		}
	}

	if values == nil {
		values = make(url.Values)
	}

	return values.Get(key)
}

func queryParam ( request * http . Request , key string ) string { var values url . Values var err error if request . URL != nil { values , err = url . ParseQuery ( request . URL . RawQuery ) if err != nil { logger . Warnf ( " " , request . URL . RawQuery , err ) return " " } } if values == nil { values = make ( url . Values ) } return values . Get ( key ) }

// Extract the given query parameter directly from the URL, never from an
// encoded body.

Extract the given query parameter directly from the URL never from an encoded body .


func newDb() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "db [sub-command]",
		Short: "Database-related code generation.",
		RunE: func(cmd *cobra.Command, args []string) error {
			return fmt.Errorf("Not implemented")
		},
	}

	cmd.AddCommand(newDbSchema())
	cmd.AddCommand(newDbMapper())

	return cmd
}

func newDb ( ) * cobra . Command { cmd := & cobra . Command { Use : " " , Short : " " , RunE : func ( cmd * cobra . Command , args [ ] string ) error { return fmt . Errorf ( " " ) } , } cmd . AddCommand ( newDbSchema ( ) ) cmd . AddCommand ( newDbMapper ( ) ) return cmd }


func (t OperationType) Description() string {
	switch t {
	case OperationClusterBootstrap:
		return "Creating bootstrap node"
	case OperationClusterJoin:
		return "Joining cluster"
	case OperationBackupCreate:
		return "Backing up container"
	case OperationBackupRename:
		return "Renaming container backup"
	case OperationBackupRestore:
		return "Restoring backup"
	case OperationBackupRemove:
		return "Removing container backup"
	case OperationConsoleShow:
		return "Showing console"
	case OperationContainerCreate:
		return "Creating container"
	case OperationContainerUpdate:
		return "Updating container"
	case OperationContainerRename:
		return "Renaming container"
	case OperationContainerMigrate:
		return "Migrating container"
	case OperationContainerLiveMigrate:
		return "Live-migrating container"
	case OperationContainerFreeze:
		return "Freezing container"
	case OperationContainerUnfreeze:
		return "Unfreezing container"
	case OperationContainerDelete:
		return "Deleting container"
	case OperationContainerStart:
		return "Starting container"
	case OperationContainerStop:
		return "Stopping container"
	case OperationContainerRestart:
		return "Restarting container"
	case OperationCommandExec:
		return "Executing command"
	case OperationSnapshotCreate:
		return "Snapshotting container"
	case OperationSnapshotRename:
		return "Renaming snapshot"
	case OperationSnapshotRestore:
		return "Restoring snapshot"
	case OperationSnapshotTransfer:
		return "Transferring snapshot"
	case OperationSnapshotUpdate:
		return "Updating snapshot"
	case OperationSnapshotDelete:
		return "Deleting snapshot"
	case OperationImageDownload:
		return "Downloading image"
	case OperationImageDelete:
		return "Deleting image"
	case OperationImageToken:
		return "Image download token"
	case OperationImageRefresh:
		return "Refreshing image"
	case OperationVolumeCopy:
		return "Copying storage volume"
	case OperationVolumeCreate:
		return "Creating storage volume"
	case OperationVolumeMigrate:
		return "Migrating storage volume"
	case OperationVolumeMove:
		return "Moving storage volume"
	case OperationVolumeSnapshotCreate:
		return "Creating storage volume snapshot"
	case OperationVolumeSnapshotDelete:
		return "Deleting storage volume snapshot"
	case OperationVolumeSnapshotUpdate:
		return "Updating storage volume snapshot"
	case OperationProjectRename:
		return "Renaming project"
	case OperationImagesExpire:
		return "Cleaning up expired images"
	case OperationImagesPruneLeftover:
		return "Pruning leftover image files"
	case OperationImagesUpdate:
		return "Updating images"
	case OperationImagesSynchronize:
		return "Synchronizing images"
	case OperationLogsExpire:
		return "Expiring log files"
	case OperationInstanceTypesUpdate:
		return "Updating instance types"
	case OperationBackupsExpire:
		return "Cleaning up expired backups"
	case OperationSnapshotsExpire:
		return "Cleaning up expired snapshots"
	default:
		return "Executing operation"
	}
}

func ( t OperationType ) Description ( ) string { switch t { case OperationClusterBootstrap : return " " case OperationClusterJoin : return " " case OperationBackupCreate : return " " case OperationBackupRename : return " " case OperationBackupRestore : return " " case OperationBackupRemove : return " " case OperationConsoleShow : return " " case OperationContainerCreate : return " " case OperationContainerUpdate : return " " case OperationContainerRename : return " " case OperationContainerMigrate : return " " case OperationContainerLiveMigrate : return " " case OperationContainerFreeze : return " " case OperationContainerUnfreeze : return " " case OperationContainerDelete : return " " case OperationContainerStart : return " " case OperationContainerStop : return " " case OperationContainerRestart : return " " case OperationCommandExec : return " " case OperationSnapshotCreate : return " " case OperationSnapshotRename : return " " case OperationSnapshotRestore : return " " case OperationSnapshotTransfer : return " " case OperationSnapshotUpdate : return " " case OperationSnapshotDelete : return " " case OperationImageDownload : return " " case OperationImageDelete : return " " case OperationImageToken : return " " case OperationImageRefresh : return " " case OperationVolumeCopy : return " " case OperationVolumeCreate : return " " case OperationVolumeMigrate : return " " case OperationVolumeMove : return " " case OperationVolumeSnapshotCreate : return " " case OperationVolumeSnapshotDelete : return " " case OperationVolumeSnapshotUpdate : return " " case OperationProjectRename : return " " case OperationImagesExpire : return " " case OperationImagesPruneLeftover : return " " case OperationImagesUpdate : return " " case OperationImagesSynchronize : return " " case OperationLogsExpire : return " " case OperationInstanceTypesUpdate : return " " case OperationBackupsExpire : return " " case OperationSnapshotsExpire : return " " default : return " " } }

// Description return a human-readable description of the operation type.

Description return a human - readable description of the operation type .


func (t OperationType) Permission() string {
	switch t {
	case OperationBackupCreate:
		return "operate-containers"
	case OperationBackupRename:
		return "operate-containers"
	case OperationBackupRestore:
		return "operate-containers"
	case OperationBackupRemove:
		return "operate-containers"
	case OperationConsoleShow:
		return "operate-containers"
	case OperationContainerFreeze:
		return "operate-containers"
	case OperationContainerUnfreeze:
		return "operate-containers"
	case OperationContainerStart:
		return "operate-containers"
	case OperationContainerStop:
		return "operate-containers"
	case OperationContainerRestart:
		return "operate-containers"
	case OperationCommandExec:
		return "operate-containers"
	case OperationSnapshotCreate:
		return "operate-containers"
	case OperationSnapshotRename:
		return "operate-containers"
	case OperationSnapshotTransfer:
		return "operate-containers"
	case OperationSnapshotUpdate:
		return "operate-containers"
	case OperationSnapshotDelete:
		return "operate-containers"

	case OperationContainerCreate:
		return "manage-containers"
	case OperationContainerUpdate:
		return "manage-containers"
	case OperationContainerRename:
		return "manage-containers"
	case OperationContainerMigrate:
		return "manage-containers"
	case OperationContainerLiveMigrate:
		return "manage-containers"
	case OperationContainerDelete:
		return "manage-containers"
	case OperationSnapshotRestore:
		return "manage-containers"

	case OperationImageDownload:
		return "manage-images"
	case OperationImageDelete:
		return "manage-images"
	case OperationImageToken:
		return "manage-images"
	case OperationImageRefresh:
		return "manage-images"
	case OperationImagesUpdate:
		return "manage-images"
	case OperationImagesSynchronize:
		return "manage-images"
	}

	return ""
}

func ( t OperationType ) Permission ( ) string { switch t { case OperationBackupCreate : return " " case OperationBackupRename : return " " case OperationBackupRestore : return " " case OperationBackupRemove : return " " case OperationConsoleShow : return " " case OperationContainerFreeze : return " " case OperationContainerUnfreeze : return " " case OperationContainerStart : return " " case OperationContainerStop : return " " case OperationContainerRestart : return " " case OperationCommandExec : return " " case OperationSnapshotCreate : return " " case OperationSnapshotRename : return " " case OperationSnapshotTransfer : return " " case OperationSnapshotUpdate : return " " case OperationSnapshotDelete : return " " case OperationContainerCreate : return " " case OperationContainerUpdate : return " " case OperationContainerRename : return " " case OperationContainerMigrate : return " " case OperationContainerLiveMigrate : return " " case OperationContainerDelete : return " " case OperationSnapshotRestore : return " " case OperationImageDownload : return " " case OperationImageDelete : return " " case OperationImageToken : return " " case OperationImageRefresh : return " " case OperationImagesUpdate : return " " case OperationImagesSynchronize : return " " } return " " }

// Permission returns the needed RBAC permission to cancel the oepration


func (c *ClusterTx) OperationsUUIDs() ([]string, error) {
	stmt := "SELECT uuid FROM operations WHERE node_id=?"
	return query.SelectStrings(c.tx, stmt, c.nodeID)
}

func ( c * ClusterTx ) OperationsUUIDs ( ) ( [ ] string , error ) { stmt := " " return query . SelectStrings ( c . tx , stmt , c . nodeID ) }

// OperationsUUIDs returns the UUIDs of all operations associated with this
// node.

OperationsUUIDs returns the UUIDs of all operations associated with this node .


func (c *ClusterTx) OperationNodes(project string) ([]string, error) {
	stmt := `
SELECT DISTINCT nodes.address
  FROM operations
  LEFT OUTER JOIN projects ON projects.id = operations.project_id
  JOIN nodes ON nodes.id = operations.node_id
 WHERE projects.name = ? OR operations.project_id IS NULL
`
	return query.SelectStrings(c.tx, stmt, project)
}

// OperationNodes returns a list of nodes that have running operations


func (c *ClusterTx) OperationByUUID(uuid string) (Operation, error) {
	null := Operation{}
	operations, err := c.operations("uuid=?", uuid)
	if err != nil {
		return null, err
	}
	switch len(operations) {
	case 0:
		return null, ErrNoSuchObject
	case 1:
		return operations[0], nil
	default:
		return null, fmt.Errorf("more than one node matches")
	}
}

func ( c * ClusterTx ) OperationByUUID ( uuid string ) ( Operation , error ) { null := Operation { } operations , err := c . operations ( " " , uuid ) if err != nil { return null , err } switch len ( operations ) { case 0 : return null , ErrNoSuchObject case 1 : return operations [ 0 ] , nil default : return null , fmt . Errorf ( " " ) } }

// OperationByUUID returns the operation with the given UUID.

OperationByUUID returns the operation with the given UUID .


func (c *ClusterTx) OperationAdd(project, uuid string, typ OperationType) (int64, error) {
	var projectID interface{}

	if project != "" {
		var err error
		projectID, err = c.ProjectID(project)
		if err != nil {
			return -1, errors.Wrap(err, "Fetch project ID")
		}
	} else {
		projectID = nil
	}

	columns := []string{"uuid", "node_id", "type", "project_id"}
	values := []interface{}{uuid, c.nodeID, typ, projectID}
	return query.UpsertObject(c.tx, "operations", columns, values)
}

func ( c * ClusterTx ) OperationAdd ( project , uuid string , typ OperationType ) ( int64 , error ) { var projectID interface { } if project != " " { var err error projectID , err = c . ProjectID ( project ) if err != nil { return - 1 , errors . Wrap ( err , " " ) } } else { projectID = nil } columns := [ ] string { " " , " " , " " , " " } values := [ ] interface { } { uuid , c . nodeID , typ , projectID } return query . UpsertObject ( c . tx , " " , columns , values ) }

// OperationAdd adds a new operations to the table.

OperationAdd adds a new operations to the table .


func (c *ClusterTx) OperationRemove(uuid string) error {
	result, err := c.tx.Exec("DELETE FROM operations WHERE uuid=?", uuid)
	if err != nil {
		return err
	}
	n, err := result.RowsAffected()
	if err != nil {
		return err
	}
	if n != 1 {
		return fmt.Errorf("query deleted %d rows instead of 1", n)
	}
	return nil
}

func ( c * ClusterTx ) OperationRemove ( uuid string ) error { result , err := c . tx . Exec ( " " , uuid ) if err != nil { return err } n , err := result . RowsAffected ( ) if err != nil { return err } if n != 1 { return fmt . Errorf ( " " , n ) } return nil }

// OperationRemove removes the operation with the given UUID.

OperationRemove removes the operation with the given UUID .


func (c *ClusterTx) operations(where string, args ...interface{}) ([]Operation, error) {
	operations := []Operation{}
	dest := func(i int) []interface{} {
		operations = append(operations, Operation{})
		return []interface{}{
			&operations[i].ID,
			&operations[i].UUID,
			&operations[i].NodeAddress,
			&operations[i].Type,
		}
	}
	sql := `
SELECT operations.id, uuid, nodes.address, type FROM operations JOIN nodes ON nodes.id = node_id `
	if where != "" {
		sql += fmt.Sprintf("WHERE %s ", where)
	}
	sql += "ORDER BY operations.id"
	stmt, err := c.tx.Prepare(sql)
	if err != nil {
		return nil, err
	}
	defer stmt.Close()
	err = query.SelectObjects(stmt, dest, args...)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to fetch operations")
	}
	return operations, nil
}

// Operations returns all operations in the cluster, filtered by the given clause.

Operations returns all operations in the cluster filtered by the given clause .


func expireLogsTask(state *state.State) (task.Func, task.Schedule) {
	f := func(ctx context.Context) {
		opRun := func(op *operation) error {
			return expireLogs(ctx, state)
		}

		op, err := operationCreate(state.Cluster, "", operationClassTask, db.OperationLogsExpire, nil, nil, opRun, nil, nil)
		if err != nil {
			logger.Error("Failed to start log expiry operation", log.Ctx{"err": err})
			return
		}

		logger.Infof("Expiring log files")
		_, err = op.Run()
		if err != nil {
			logger.Error("Failed to expire logs", log.Ctx{"err": err})
		}
		logger.Infof("Done expiring log files")
	}

	return f, task.Daily()
}

func expireLogsTask ( state * state . State ) ( task . Func , task . Schedule ) { f := func ( ctx context . Context ) { opRun := func ( op * operation ) error { return expireLogs ( ctx , state ) } op , err := operationCreate ( state . Cluster , " " , operationClassTask , db . OperationLogsExpire , nil , nil , opRun , nil , nil ) if err != nil { logger . Error ( " " , log . Ctx { " " : err } ) return } logger . Infof ( " " ) _ , err = op . Run ( ) if err != nil { logger . Error ( " " , log . Ctx { " " : err } ) } logger . Infof ( " " ) } return f , task . Daily ( ) }

// This task function expires logs when executed. It's started by the Daemon
// and will run once every 24h.

This task function expires logs when executed . It s started by the Daemon and will run once every 24h .


func absPath(path string) string {
	// We expect to be called by code within the lxd package itself.
	_, filename, _, _ := runtime.Caller(1)

	elems := strings.Split(filename, string(filepath.Separator))
	for i := len(elems) - 1; i >= 0; i-- {
		if elems[i] == "lxd" {
			elems = append([]string{string(filepath.Separator)}, elems[:i]...)
			elems = append(elems, path)
			return filepath.Join(elems...)
		}
	}

	log.Fatalf("Could not found root dir of LXD tree source tree")

	return ""
}

// Given its relative path with respect to the LXD surce tree, return the full
// path of a file.

Given its relative path with respect to the LXD surce tree return the full path of a file .


func (s Schema) Keys() []string {
	keys := make([]string, len(s))
	i := 0
	for key := range s {
		keys[i] = key
		i++
	}
	sort.Strings(keys)
	return keys
}

func ( s Schema ) Keys ( ) [ ] string { keys := make ( [ ] string , len ( s ) ) i := 0 for key := range s { keys [ i ] = key i ++ } sort . Strings ( keys ) return keys }

// Keys returns all keys defined in the schema


func (s Schema) Defaults() map[string]interface{} {
	values := make(map[string]interface{}, len(s))
	for name, key := range s {
		values[name] = key.Default
	}
	return values
}

func ( s Schema ) Defaults ( ) map [ string ] interface { } { values := make ( map [ string ] interface { } , len ( s ) ) for name , key := range s { values [ name ] = key . Default } return values }

// Defaults returns a map of all key names in the schema along with their default
// values.

Defaults returns a map of all key names in the schema along with their default values .


func (s Schema) mustGetKey(name string) Key {
	key, ok := s[name]
	if !ok {
		panic(fmt.Sprintf("attempt to access unknown key '%s'", name))
	}
	return key
}

func ( s Schema ) mustGetKey ( name string ) Key { key , ok := s [ name ] if ! ok { panic ( fmt . Sprintf ( " " , name ) ) } return key }

// Get the Key associated with the given name, or panic.

Get the Key associated with the given name or panic .


func (s Schema) assertKeyType(name string, code Type) {
	key := s.mustGetKey(name)
	if key.Type != code {
		panic(fmt.Sprintf("key '%s' has type code %d, not %d", name, key.Type, code))
	}
}

func ( s Schema ) assertKeyType ( name string , code Type ) { key := s . mustGetKey ( name ) if key . Type != code { panic ( fmt . Sprintf ( " " , name , key . Type , code ) ) } }

// Assert that the Key with the given name as the given type. Panic if no Key
// with such name exists, or if it does not match the tiven type.

Assert that the Key with the given name as the given type . Panic if no Key with such name exists or if it does not match the tiven type .


func (v *Key) validate(value string) error {
	validator := v.Validator
	if validator == nil {
		// Dummy validator
		validator = func(string) error { return nil }
	}

	// Handle unsetting
	if value == "" {
		return validator(v.Default)
	}

	switch v.Type {
	case String:
	case Bool:
		if !shared.StringInSlice(strings.ToLower(value), booleans) {
			return fmt.Errorf("invalid boolean")
		}
	case Int64:
		_, err := strconv.ParseInt(value, 10, 64)
		if err != nil {
			return fmt.Errorf("invalid integer")
		}
	default:
		panic(fmt.Sprintf("unexpected value type: %d", v.Type))
	}

	if v.Deprecated != "" && value != v.Default {
		return fmt.Errorf("deprecated: %s", v.Deprecated)
	}

	// Run external validation function
	return validator(value)
}

func
(
v
*
Key
)
validate
(
value
string
)
error
{
validator
:=
v
.
Validator
if
validator
==
{
// Dummy validator
validator
=
func
(
string
)
error
{
return
}
}
// Handle unsetting
if
value
==
"
"
{
return
validator
(
v
.
Default
)
}
switch
v
.
Type
{
case
String
:
case
Bool
:
if
!
shared
.
StringInSlice
(
strings
.
ToLower
(
value
)
,
booleans
)
{
return
fmt
.
Errorf
(
"
"
)
}
case
Int64
:
_
,
err
:=
strconv
.
ParseInt
(
value
,
10
,
64
)
if
err
!=
{
return
fmt
.
Errorf
(
"
"
)
}
default
:
panic
(
fmt
.
Sprintf
(
"
"
,
v
.
Type
)
)
}
if
v
.
Deprecated
!=
"
"
&&
value
!=
v
.
Default
{
return
fmt
.
Errorf
(
"
"
,
v
.
Deprecated
)
}
// Run external validation function
return
validator
(
value
)
}

// Tells if the given value can be assigned to this particular Value instance.

Tells if the given value can be assigned to this particular Value instance .


func (r *ProtocolLXD) GetStoragePoolVolumes(pool string) ([]api.StorageVolume, error) {
	if !r.HasExtension("storage") {
		return nil, fmt.Errorf("The server is missing the required \"storage\" API extension")
	}

	volumes := []api.StorageVolume{}

	// Fetch the raw value
	_, err := r.queryStruct("GET", fmt.Sprintf("/storage-pools/%s/volumes?recursion=1", url.QueryEscape(pool)), nil, "", &volumes)
	if err != nil {
		return nil, err
	}

	return volumes, nil
}

func
(
r
*
ProtocolLXD
)
GetStoragePoolVolumes
(
pool
string
)
(
[
]
api
.
StorageVolume
,
error
)
{
if
!
r
.
HasExtension
(
"
"
)
{
return
,
fmt
.
Errorf
(
"
\"
\"
"
)
}
volumes
:=
[
]
api
.
StorageVolume
{
}
// Fetch the raw value
_
,
err
:=
r
.
queryStruct
(
"
"
,
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
pool
)
)
,
,
"
"
,
&
volumes
)
if
err
!=
{
return
,
err
}
return
volumes
,
}

// GetStoragePoolVolumes returns a list of StorageVolume entries for the provided pool


func (r *ProtocolLXD) GetStoragePoolVolume(pool string, volType string, name string) (*api.StorageVolume, string, error) {
	if !r.HasExtension("storage") {
		return nil, "", fmt.Errorf("The server is missing the required \"storage\" API extension")
	}

	volume := api.StorageVolume{}

	// Fetch the raw value
	path := fmt.Sprintf("/storage-pools/%s/volumes/%s/%s", url.QueryEscape(pool), url.QueryEscape(volType), url.QueryEscape(name))
	etag, err := r.queryStruct("GET", path, nil, "", &volume)
	if err != nil {
		return nil, "", err
	}

	return &volume, etag, nil
}

func
(
r
*
ProtocolLXD
)
GetStoragePoolVolume
(
pool
string
,
volType
string
,
name
string
)
(
*
api
.
StorageVolume
,
string
,
error
)
{
if
!
r
.
HasExtension
(
"
"
)
{
return
,
"
"
,
fmt
.
Errorf
(
"
\"
\"
"
)
}
volume
:=
api
.
StorageVolume
{
}
// Fetch the raw value
path
:=
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
pool
)
,
url
.
QueryEscape
(
volType
)
,
url
.
QueryEscape
(
name
)
)
etag
,
err
:=
r
.
queryStruct
(
"
"
,
path
,
,
"
"
,
&
volume
)
if
err
!=
{
return
,
"
"
,
err
}
return
&
volume
,
etag
,
}

// GetStoragePoolVolume returns a StorageVolume entry for the provided pool and volume name


func (r *ProtocolLXD) CreateStoragePoolVolume(pool string, volume api.StorageVolumesPost) error {
	if !r.HasExtension("storage") {
		return fmt.Errorf("The server is missing the required \"storage\" API extension")
	}

	// Send the request
	path := fmt.Sprintf("/storage-pools/%s/volumes/%s", url.QueryEscape(pool), url.QueryEscape(volume.Type))
	_, _, err := r.query("POST", path, volume, "")
	if err != nil {
		return err
	}

	return nil
}

func
(
r
*
ProtocolLXD
)
CreateStoragePoolVolume
(
pool
string
,
volume
api
.
StorageVolumesPost
)
error
{
if
!
r
.
HasExtension
(
"
"
)
{
return
fmt
.
Errorf
(
"
\"
\"
"
)
}
// Send the request
path
:=
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
pool
)
,
url
.
QueryEscape
(
volume
.
Type
)
)
_
,
_
,
err
:=
r
.
query
(
"
"
,
path
,
volume
,
"
"
)
if
err
!=
{
return
err
}
return
}

// CreateStoragePoolVolume defines a new storage volume


func (r *ProtocolLXD) CreateStoragePoolVolumeSnapshot(pool string, volumeType string, volumeName string, snapshot api.StorageVolumeSnapshotsPost) (Operation, error) {
	if !r.HasExtension("storage_api_volume_snapshots") {
		return nil, fmt.Errorf("The server is missing the required \"storage_api_volume_snapshots\" API extension")
	}

	// Send the request
	path := fmt.Sprintf("/storage-pools/%s/volumes/%s/%s/snapshots",
		url.QueryEscape(pool),
		url.QueryEscape(volumeType),
		url.QueryEscape(volumeName))
	op, _, err := r.queryOperation("POST", path, snapshot, "")
	if err != nil {
		return nil, err
	}

	return op, nil
}

func
(
r
*
ProtocolLXD
)
CreateStoragePoolVolumeSnapshot
(
pool
string
,
volumeType
string
,
volumeName
string
,
snapshot
api
.
StorageVolumeSnapshotsPost
)
(
Operation
,
error
)
{
if
!
r
.
HasExtension
(
"
"
)
{
return
,
fmt
.
Errorf
(
"
\"
\"
"
)
}
// Send the request
path
:=
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
pool
)
,
url
.
QueryEscape
(
volumeType
)
,
url
.
QueryEscape
(
volumeName
)
)
op
,
_
,
err
:=
r
.
queryOperation
(
"
"
,
path
,
snapshot
,
"
"
)
if
err
!=
{
return
,
err
}
return
op
,
}

// CreateStoragePoolVolumeSnapshot defines a new storage volume


func (r *ProtocolLXD) GetStoragePoolVolumeSnapshots(pool string, volumeType string, volumeName string) ([]api.StorageVolumeSnapshot, error) {
	if !r.HasExtension("storage_api_volume_snapshots") {
		return nil, fmt.Errorf("The server is missing the required \"storage_api_volume_snapshots\" API extension")
	}

	snapshots := []api.StorageVolumeSnapshot{}

	path := fmt.Sprintf("/storage-pools/%s/volumes/%s/%s/snapshots?recursion=1",
		url.QueryEscape(pool),
		url.QueryEscape(volumeType),
		url.QueryEscape(volumeName))
	_, err := r.queryStruct("GET", path, nil, "", &snapshots)
	if err != nil {
		return nil, err
	}

	return snapshots, nil
}

func ( r * ProtocolLXD ) GetStoragePoolVolumeSnapshots ( pool string , volumeType string , volumeName string ) ( [ ] api . StorageVolumeSnapshot , error ) { if ! r . HasExtension ( " " ) { return nil , fmt . Errorf ( " \" \" " ) } snapshots := [ ] api . StorageVolumeSnapshot { } path := fmt . Sprintf ( " " , url . QueryEscape ( pool ) , url . QueryEscape ( volumeType ) , url . QueryEscape ( volumeName ) ) _ , err := r . queryStruct ( " " , path , nil , " " , & snapshots ) if err != nil { return nil , err } return snapshots , nil }

// GetStoragePoolVolumeSnapshots returns a list of snapshots for the storage
// volume

GetStoragePoolVolumeSnapshots returns a list of snapshots for the storage volume


func (r *ProtocolLXD) GetStoragePoolVolumeSnapshot(pool string, volumeType string, volumeName string, snapshotName string) (*api.StorageVolumeSnapshot, string, error) {
	if !r.HasExtension("storage_api_volume_snapshots") {
		return nil, "", fmt.Errorf("The server is missing the required \"storage_api_volume_snapshots\" API extension")
	}

	snapshot := api.StorageVolumeSnapshot{}

	path := fmt.Sprintf("/storage-pools/%s/volumes/%s/%s/snapshots/%s",
		url.QueryEscape(pool),
		url.QueryEscape(volumeType),
		url.QueryEscape(volumeName),
		url.QueryEscape(snapshotName))
	etag, err := r.queryStruct("GET", path, nil, "", &snapshot)
	if err != nil {
		return nil, "", err
	}

	return &snapshot, etag, nil
}

func ( r * ProtocolLXD ) GetStoragePoolVolumeSnapshot ( pool string , volumeType string , volumeName string , snapshotName string ) ( * api . StorageVolumeSnapshot , string , error ) { if ! r . HasExtension ( " " ) { return nil , " " , fmt . Errorf ( " \" \" " ) } snapshot := api . StorageVolumeSnapshot { } path := fmt . Sprintf ( " " , url . QueryEscape ( pool ) , url . QueryEscape ( volumeType ) , url . QueryEscape ( volumeName ) , url . QueryEscape ( snapshotName ) ) etag , err := r . queryStruct ( " " , path , nil , " " , & snapshot ) if err != nil { return nil , " " , err } return & snapshot , etag , nil }

// GetStoragePoolVolumeSnapshot returns a snapshots for the storage volume


func (r *ProtocolLXD) UpdateStoragePoolVolumeSnapshot(pool string, volumeType string, volumeName string, snapshotName string, volume api.StorageVolumeSnapshotPut, ETag string) error {
	if !r.HasExtension("storage_api_volume_snapshots") {
		return fmt.Errorf("The server is missing the required \"storage_api_volume_snapshots\" API extension")
	}

	// Send the request
	path := fmt.Sprintf("/storage-pools/%s/volumes/%s/%s/snapshots/%s", url.QueryEscape(pool), url.QueryEscape(volumeType), url.QueryEscape(volumeName), url.QueryEscape(snapshotName))
	_, _, err := r.queryOperation("PUT", path, volume, ETag)
	if err != nil {
		return err
	}

	return nil
}

func
(
r
*
ProtocolLXD
)
UpdateStoragePoolVolumeSnapshot
(
pool
string
,
volumeType
string
,
volumeName
string
,
snapshotName
string
,
volume
api
.
StorageVolumeSnapshotPut
,
ETag
string
)
error
{
if
!
r
.
HasExtension
(
"
"
)
{
return
fmt
.
Errorf
(
"
\"
\"
"
)
}
// Send the request
path
:=
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
pool
)
,
url
.
QueryEscape
(
volumeType
)
,
url
.
QueryEscape
(
volumeName
)
,
url
.
QueryEscape
(
snapshotName
)
)
_
,
_
,
err
:=
r
.
queryOperation
(
"
"
,
path
,
volume
,
ETag
)
if
err
!=
{
return
err
}
return
}

// UpdateStoragePoolVolumeSnapshot updates the volume to match the provided StoragePoolVolume struct


func (r *ProtocolLXD) MigrateStoragePoolVolume(pool string, volume api.StorageVolumePost) (Operation, error) {
	if !r.HasExtension("storage_api_remote_volume_handling") {
		return nil, fmt.Errorf("The server is missing the required \"storage_api_remote_volume_handling\" API extension")
	}

	// Sanity check
	if !volume.Migration {
		return nil, fmt.Errorf("Can't ask for a rename through MigrateStoragePoolVolume")
	}

	// Send the request
	path := fmt.Sprintf("/storage-pools/%s/volumes/custom/%s", url.QueryEscape(pool), volume.Name)
	op, _, err := r.queryOperation("POST", path, volume, "")
	if err != nil {
		return nil, err
	}

	return op, nil
}

func
(
r
*
ProtocolLXD
)
MigrateStoragePoolVolume
(
pool
string
,
volume
api
.
StorageVolumePost
)
(
Operation
,
error
)
{
if
!
r
.
HasExtension
(
"
"
)
{
return
,
fmt
.
Errorf
(
"
\"
\"
"
)
}
// Sanity check
if
!
volume
.
Migration
{
return
,
fmt
.
Errorf
(
"
"
)
}
// Send the request
path
:=
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
pool
)
,
volume
.
Name
)
op
,
_
,
err
:=
r
.
queryOperation
(
"
"
,
path
,
volume
,
"
"
)
if
err
!=
{
return
,
err
}
return
op
,
}

// MigrateStoragePoolVolume requests that LXD prepares for a storage volume migration


func (r *ProtocolLXD) MoveStoragePoolVolume(pool string, source ContainerServer, sourcePool string, volume api.StorageVolume, args *StoragePoolVolumeMoveArgs) (RemoteOperation, error) {
	if !r.HasExtension("storage_api_local_volume_handling") {
		return nil, fmt.Errorf("The server is missing the required \"storage_api_local_volume_handling\" API extension")
	}

	if r != source {
		return nil, fmt.Errorf("Moving storage volumes between remotes is not implemented")
	}

	req := api.StorageVolumePost{
		Name: args.Name,
		Pool: pool,
	}

	// Send the request
	op, _, err := r.queryOperation("POST", fmt.Sprintf("/storage-pools/%s/volumes/%s/%s", url.QueryEscape(sourcePool), url.QueryEscape(volume.Type), volume.Name), req, "")
	if err != nil {
		return nil, err
	}

	rop := remoteOperation{
		targetOp: op,
		chDone:   make(chan bool),
	}

	// Forward targetOp to remote op
	go func() {
		rop.err = rop.targetOp.Wait()
		close(rop.chDone)
	}()

	return &rop, nil
}

func
(
r
*
ProtocolLXD
)
MoveStoragePoolVolume
(
pool
string
,
source
ContainerServer
,
sourcePool
string
,
volume
api
.
StorageVolume
,
args
*
StoragePoolVolumeMoveArgs
)
(
RemoteOperation
,
error
)
{
if
!
r
.
HasExtension
(
"
"
)
{
return
,
fmt
.
Errorf
(
"
\"
\"
"
)
}
if
r
!=
source
{
return
,
fmt
.
Errorf
(
"
"
)
}
req
:=
api
.
StorageVolumePost
{
Name
:
args
.
Name
,
Pool
:
pool
,
}
// Send the request
op
,
_
,
err
:=
r
.
queryOperation
(
"
"
,
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
sourcePool
)
,
url
.
QueryEscape
(
volume
.
Type
)
,
volume
.
Name
)
,
req
,
"
"
)
if
err
!=
{
return
,
err
}
rop
:=
remoteOperation
{
targetOp
:
op
,
chDone
:
make
(
chan
bool
)
,
}
// Forward targetOp to remote op
go
func
(
)
{
rop
.
err
=
rop
.
targetOp
.
Wait
(
)
close
(
rop
.
chDone
)
}
(
)
return
&
rop
,
}

// MoveStoragePoolVolume renames or moves an existing storage volume


func (r *ProtocolLXD) UpdateStoragePoolVolume(pool string, volType string, name string, volume api.StorageVolumePut, ETag string) error {
	if !r.HasExtension("storage") {
		return fmt.Errorf("The server is missing the required \"storage\" API extension")
	}

	if volume.Restore != "" && !r.HasExtension("storage_api_volume_snapshots") {
		return fmt.Errorf("The server is missing the required \"storage_api_volume_snapshots\" API extension")
	}

	// Send the request
	path := fmt.Sprintf("/storage-pools/%s/volumes/%s/%s", url.QueryEscape(pool), url.QueryEscape(volType), url.QueryEscape(name))
	_, _, err := r.query("PUT", path, volume, ETag)
	if err != nil {
		return err
	}

	return nil
}

func
(
r
*
ProtocolLXD
)
UpdateStoragePoolVolume
(
pool
string
,
volType
string
,
name
string
,
volume
api
.
StorageVolumePut
,
ETag
string
)
error
{
if
!
r
.
HasExtension
(
"
"
)
{
return
fmt
.
Errorf
(
"
\"
\"
"
)
}
if
volume
.
Restore
!=
"
"
&&
!
r
.
HasExtension
(
"
"
)
{
return
fmt
.
Errorf
(
"
\"
\"
"
)
}
// Send the request
path
:=
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
pool
)
,
url
.
QueryEscape
(
volType
)
,
url
.
QueryEscape
(
name
)
)
_
,
_
,
err
:=
r
.
query
(
"
"
,
path
,
volume
,
ETag
)
if
err
!=
{
return
err
}
return
}

// UpdateStoragePoolVolume updates the volume to match the provided StoragePoolVolume struct


func (r *ProtocolLXD) DeleteStoragePoolVolume(pool string, volType string, name string) error {
	if !r.HasExtension("storage") {
		return fmt.Errorf("The server is missing the required \"storage\" API extension")
	}

	// Send the request
	path := fmt.Sprintf("/storage-pools/%s/volumes/%s/%s", url.QueryEscape(pool), url.QueryEscape(volType), url.QueryEscape(name))
	_, _, err := r.query("DELETE", path, nil, "")
	if err != nil {
		return err
	}

	return nil
}

func
(
r
*
ProtocolLXD
)
DeleteStoragePoolVolume
(
pool
string
,
volType
string
,
name
string
)
error
{
if
!
r
.
HasExtension
(
"
"
)
{
return
fmt
.
Errorf
(
"
\"
\"
"
)
}
// Send the request
path
:=
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
pool
)
,
url
.
QueryEscape
(
volType
)
,
url
.
QueryEscape
(
name
)
)
_
,
_
,
err
:=
r
.
query
(
"
"
,
path
,
,
"
"
)
if
err
!=
{
return
err
}
return
}

// DeleteStoragePoolVolume deletes a storage pool


func (r *ProtocolLXD) RenameStoragePoolVolume(pool string, volType string, name string, volume api.StorageVolumePost) error {
	if !r.HasExtension("storage_api_volume_rename") {
		return fmt.Errorf("The server is missing the required \"storage_api_volume_rename\" API extension")
	}
	path := fmt.Sprintf("/storage-pools/%s/volumes/%s/%s", url.QueryEscape(pool), url.QueryEscape(volType), url.QueryEscape(name))

	// Send the request
	_, _, err := r.query("POST", path, volume, "")
	if err != nil {
		return err
	}

	return nil
}

func
(
r
*
ProtocolLXD
)
RenameStoragePoolVolume
(
pool
string
,
volType
string
,
name
string
,
volume
api
.
StorageVolumePost
)
error
{
if
!
r
.
HasExtension
(
"
"
)
{
return
fmt
.
Errorf
(
"
\"
\"
"
)
}
path
:=
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
pool
)
,
url
.
QueryEscape
(
volType
)
,
url
.
QueryEscape
(
name
)
)
// Send the request
_
,
_
,
err
:=
r
.
query
(
"
"
,
path
,
volume
,
"
"
)
if
err
!=
{
return
err
}
return
}

// RenameStoragePoolVolume renames a storage volume


func doStoragePoolCreateInternal(state *state.State, poolName, poolDescription string, driver string, config map[string]string, isNotification bool) error {
	tryUndo := true
	s, err := storagePoolInit(state, poolName)
	if err != nil {
		return err
	}

	// If this is a clustering notification for a ceph storage, we don't
	// want this node to actually create the pool, as it's already been
	// done by the node that triggered this notification. We just need to
	// create the storage pool directory.
	if s, ok := s.(*storageCeph); ok && isNotification {
		volumeMntPoint := getStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name)
		return os.MkdirAll(volumeMntPoint, 0711)

	}
	err = s.StoragePoolCreate()
	if err != nil {
		return err
	}
	defer func() {
		if !tryUndo {
			return
		}
		s.StoragePoolDelete()
	}()

	// In case the storage pool config was changed during the pool creation,
	// we need to update the database to reflect this change. This can e.g.
	// happen, when we create a loop file image. This means we append ".img"
	// to the path the user gave us and update the config in the storage
	// callback. So diff the config here to see if something like this has
	// happened.
	postCreateConfig := s.GetStoragePoolWritable().Config
	configDiff, _ := storageConfigDiff(config, postCreateConfig)
	if len(configDiff) > 0 {
		// Create the database entry for the storage pool.
		err = state.Cluster.StoragePoolUpdate(poolName, poolDescription, postCreateConfig)
		if err != nil {
			return fmt.Errorf("Error inserting %s into database: %s", poolName, err)
		}
	}

	// Success, update the closure to mark that the changes should be kept.
	tryUndo = false

	return nil
}

// This performs all non-db related work needed to create the pool.

This performs all non - db related work needed to create the pool .


func containerGetParentAndSnapshotName(name string) (string, string, bool) {
	fields := strings.SplitN(name, shared.SnapshotDelimiter, 2)
	if len(fields) == 1 {
		return name, "", false
	}

	return fields[0], fields[1], true
}

func containerGetParentAndSnapshotName ( name string ) ( string , string , bool ) { fields := strings . SplitN ( name , shared . SnapshotDelimiter , 2 ) if len ( fields ) == 1 { return name , " " , false } return fields [ 0 ] , fields [ 1 ] , true }

// Helper functions
// Returns the parent container name, snapshot name, and whether it actually was
// a snapshot name.

Helper functions Returns the parent container name snapshot name and whether it actually was a snapshot name .


func containerLoadFromAllProjects(s *state.State) ([]container, error) {
	var projects []string

	err := s.Cluster.Transaction(func(tx *db.ClusterTx) error {
		var err error
		projects, err = tx.ProjectNames()
		return err
	})
	if err != nil {
		return nil, err
	}

	containers := []container{}
	for _, project := range projects {
		projectContainers, err := containerLoadByProject(s, project)
		if err != nil {
			return nil, errors.Wrapf(nil, "Load containers in project %s", project)
		}
		containers = append(containers, projectContainers...)
	}

	return containers, nil
}

func containerLoadFromAllProjects ( s * state . State ) ( [ ] container , error ) { var projects [ ] string err := s . Cluster . Transaction ( func ( tx * db . ClusterTx ) error { var err error projects , err = tx . ProjectNames ( ) return err } ) if err != nil { return nil , err } containers := [ ] container { } for _ , project := range projects { projectContainers , err := containerLoadByProject ( s , project ) if err != nil { return nil , errors . Wrapf ( nil , " " , project ) } containers = append ( containers , projectContainers ... ) } return containers , nil }

// Load all containers across all projects.

Load all containers across all projects .


func containerLoadNodeAll(s *state.State) ([]container, error) {
	// Get all the container arguments
	var cts []db.Container
	err := s.Cluster.Transaction(func(tx *db.ClusterTx) error {
		var err error
		cts, err = tx.ContainerNodeList()
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return nil, err
	}

	return containerLoadAllInternal(cts, s)
}

func
containerLoadNodeAll
(
s
*
state
.
State
)
(
[
]
container
,
error
)
{
// Get all the container arguments
var
cts
[
]
db
.
Container
err
:=
s
.
Cluster
.
Transaction
(
func
(
tx
*
db
.
ClusterTx
)
error
{
var
err
error
cts
,
err
=
tx
.
ContainerNodeList
(
)
if
err
!=
{
return
err
}
return
}
)
if
err
!=
{
return
,
err
}
return
containerLoadAllInternal
(
cts
,
s
)
}


func containerLoadNodeProjectAll(s *state.State, project string) ([]container, error) {
	// Get all the container arguments
	var cts []db.Container
	err := s.Cluster.Transaction(func(tx *db.ClusterTx) error {
		var err error
		cts, err = tx.ContainerNodeProjectList(project)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return nil, err
	}

	return containerLoadAllInternal(cts, s)
}

func
containerLoadNodeProjectAll
(
s
*
state
.
State
,
project
string
)
(
[
]
container
,
error
)
{
// Get all the container arguments
var
cts
[
]
db
.
Container
err
:=
s
.
Cluster
.
Transaction
(
func
(
tx
*
db
.
ClusterTx
)
error
{
var
err
error
cts
,
err
=
tx
.
ContainerNodeProjectList
(
project
)
if
err
!=
{
return
err
}
return
}
)
if
err
!=
{
return
,
err
}
return
containerLoadAllInternal
(
cts
,
s
)
}

// Load all containers of this nodes under the given project.

Load all containers of this nodes under the given project .


func heartbeatNode(taskCtx context.Context, address string, cert *shared.CertInfo, raftNodes []db.RaftNode) error {
	logger.Debugf("Sending heartbeat request to %s", address)

	config, err := tlsClientConfig(cert)
	if err != nil {
		return err
	}
	url := fmt.Sprintf("https://%s%s", address, databaseEndpoint)
	client := &http.Client{Transport: &http.Transport{TLSClientConfig: config}}

	buffer := bytes.Buffer{}
	err = json.NewEncoder(&buffer).Encode(raftNodes)
	if err != nil {
		return err
	}

	request, err := http.NewRequest("PUT", url, bytes.NewReader(buffer.Bytes()))
	if err != nil {
		return err
	}
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()
	request = request.WithContext(ctx)
	request.Close = true // Immediately close the connection after the request is done

	// Perform the request asynchronously, so we can abort it if the task context is done.
	errCh := make(chan error)
	go func() {
		response, err := client.Do(request)
		if err != nil {
			errCh <- errors.Wrap(err, "failed to send HTTP request")
			return
		}
		defer response.Body.Close()
		if response.StatusCode != http.StatusOK {
			errCh <- fmt.Errorf("HTTP request failed: %s", response.Status)
			return
		}
		errCh <- nil
	}()

	select {
	case err := <-errCh:
		return err
	case <-taskCtx.Done():
		return taskCtx.Err()
	}
}

// Perform a single heartbeat request against the node with the given address.

Perform a single heartbeat request against the node with the given address .


func (c *cmdList) dotPrefixMatch(short string, full string) bool {
	fullMembs := strings.Split(full, ".")
	shortMembs := strings.Split(short, ".")

	if len(fullMembs) != len(shortMembs) {
		return false
	}

	for i := range fullMembs {
		if !strings.HasPrefix(fullMembs[i], shortMembs[i]) {
			return false
		}
	}

	return true
}

func ( c * cmdList ) dotPrefixMatch ( short string , full string ) bool { fullMembs := strings . Split ( full , " " ) shortMembs := strings . Split ( short , " " ) if len ( fullMembs ) != len ( shortMembs ) { return false } for i := range fullMembs { if ! strings . HasPrefix ( fullMembs [ i ] , shortMembs [ i ] ) { return false } } return true }


func (s *storageZfs) ContainerMount(c container) (bool, error) {
	return s.doContainerMount(c.Project(), c.Name(), c.IsPrivileged())
}

func ( s * storageZfs ) ContainerMount ( c container ) ( bool , error ) { return s . doContainerMount ( c . Project ( ) , c . Name ( ) , c . IsPrivileged ( ) ) }


func (s *storageZfs) ContainerStorageReady(container container) bool {
	volumeName := projectPrefix(container.Project(), container.Name())
	fs := fmt.Sprintf("containers/%s", volumeName)
	return zfsFilesystemEntityExists(s.getOnDiskPoolName(), fs)
}

func ( s * storageZfs ) ContainerStorageReady ( container container ) bool { volumeName := projectPrefix ( container . Project ( ) , container . Name ( ) ) fs := fmt . Sprintf ( " " , volumeName ) return zfsFilesystemEntityExists ( s . getOnDiskPoolName ( ) , fs ) }


func AskChoice(question string, choices []string, defaultAnswer string) string {
	for {
		answer := askQuestion(question, defaultAnswer)

		if shared.StringInSlice(answer, choices) {
			return answer
		}

		invalidInput()
	}
}

func AskChoice ( question string , choices [ ] string , defaultAnswer string ) string { for { answer := askQuestion ( question , defaultAnswer ) if shared . StringInSlice ( answer , choices ) { return answer } invalidInput ( ) } }

// AskChoice asks the user to select one of multiple options


func AskInt(question string, min int64, max int64, defaultAnswer string) int64 {
	for {
		answer := askQuestion(question, defaultAnswer)

		result, err := strconv.ParseInt(answer, 10, 64)

		if err == nil && (min == -1 || result >= min) && (max == -1 || result <= max) {
			return result
		}

		invalidInput()
	}
}

func AskInt ( question string , min int64 , max int64 , defaultAnswer string ) int64 { for { answer := askQuestion ( question , defaultAnswer ) result , err := strconv . ParseInt ( answer , 10 , 64 ) if err == nil && ( min == - 1 || result >= min ) && ( max == - 1 || result <= max ) { return result } invalidInput ( ) } }

// AskInt asks the user to enter an integer between a min and max value


func AskString(question string, defaultAnswer string, validate func(string) error) string {
	for {
		answer := askQuestion(question, defaultAnswer)

		if validate != nil {
			error := validate(answer)
			if error != nil {
				fmt.Fprintf(os.Stderr, "Invalid input: %s\n\n", error)
				continue
			}

			return answer
		}

		if len(answer) != 0 {
			return answer
		}

		invalidInput()
	}
}

func AskString ( question string , defaultAnswer string , validate func ( string ) error ) string { for { answer := askQuestion ( question , defaultAnswer ) if validate != nil { error := validate ( answer ) if error != nil { fmt . Fprintf ( os . Stderr , " \n \n " , error ) continue } return answer } if len ( answer ) != 0 { return answer } invalidInput ( ) } }

// AskString asks the user to enter a string, which optionally
// conforms to a validation function.

AskString asks the user to enter a string which optionally conforms to a validation function .


func AskPassword(question string) string {
	for {
		fmt.Printf(question)

		pwd, _ := terminal.ReadPassword(0)
		fmt.Println("")
		inFirst := string(pwd)
		inFirst = strings.TrimSuffix(inFirst, "\n")

		fmt.Printf("Again: ")
		pwd, _ = terminal.ReadPassword(0)
		fmt.Println("")
		inSecond := string(pwd)
		inSecond = strings.TrimSuffix(inSecond, "\n")

		if inFirst == inSecond {
			return inFirst
		}

		invalidInput()
	}
}

func AskPassword ( question string ) string { for { fmt . Printf ( question ) pwd , _ := terminal . ReadPassword ( 0 ) fmt . Println ( " " ) inFirst := string ( pwd ) inFirst = strings . TrimSuffix ( inFirst , " \n " ) fmt . Printf ( " " ) pwd , _ = terminal . ReadPassword ( 0 ) fmt . Println ( " " ) inSecond := string ( pwd ) inSecond = strings . TrimSuffix ( inSecond , " \n " ) if inFirst == inSecond { return inFirst } invalidInput ( ) } }

// AskPassword asks the user to enter a password.

AskPassword asks the user to enter a password .


func AskPasswordOnce(question string) string {
	fmt.Printf(question)
	pwd, _ := terminal.ReadPassword(0)
	fmt.Println("")

	return string(pwd)
}

func AskPasswordOnce ( question string ) string { fmt . Printf ( question ) pwd , _ := terminal . ReadPassword ( 0 ) fmt . Println ( " " ) return string ( pwd ) }

// AskPasswordOnce asks the user to enter a password.
//
// It's the same as AskPassword, but it won't ask to enter it again.

AskPasswordOnce asks the user to enter a password . It s the same as AskPassword but it won t ask to enter it again .


func askQuestion(question, defaultAnswer string) string {
	fmt.Printf(question)

	return readAnswer(defaultAnswer)
}

func askQuestion ( question , defaultAnswer string ) string { fmt . Printf ( question ) return readAnswer ( defaultAnswer ) }

// Ask a question on the output stream and read the answer from the input stream


func readAnswer(defaultAnswer string) string {
	answer, _ := stdin.ReadString('\n')
	answer = strings.TrimSuffix(answer, "\n")
	answer = strings.TrimSpace(answer)
	if answer == "" {
		answer = defaultAnswer
	}

	return answer
}

func readAnswer ( defaultAnswer string ) string { answer , _ := stdin . ReadString ( '\n' ) answer = strings . TrimSuffix ( answer , " \n " ) answer = strings . TrimSpace ( answer ) if answer == " " { answer = defaultAnswer } return answer }

// Read the user's answer from the input stream, trimming newline and providing a default.

Read the user s answer from the input stream trimming newline and providing a default .


func profilePost(d *Daemon, r *http.Request) Response {
	project := projectParam(r)
	name := mux.Vars(r)["name"]

	if name == "default" {
		return Forbidden(errors.New("The 'default' profile cannot be renamed"))
	}

	req := api.ProfilePost{}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		return BadRequest(err)
	}

	// Sanity checks
	if req.Name == "" {
		return BadRequest(fmt.Errorf("No name provided"))
	}

	if strings.Contains(req.Name, "/") {
		return BadRequest(fmt.Errorf("Profile names may not contain slashes"))
	}

	if shared.StringInSlice(req.Name, []string{".", ".."}) {
		return BadRequest(fmt.Errorf("Invalid profile name '%s'", req.Name))
	}

	err := d.cluster.Transaction(func(tx *db.ClusterTx) error {
		hasProfiles, err := tx.ProjectHasProfiles(project)
		if err != nil {
			return errors.Wrap(err, "Check project features")
		}

		if !hasProfiles {
			project = "default"
		}

		// Check that the name isn't already in use
		_, err = tx.ProfileGet(project, req.Name)
		if err == nil {
			return fmt.Errorf("Name '%s' already in use", req.Name)
		}

		return tx.ProfileRename(project, name, req.Name)
	})
	if err != nil {
		return SmartError(err)
	}

	return SyncResponseLocation(true, nil, fmt.Sprintf("/%s/profiles/%s", version.APIVersion, req.Name))
}


func profileDelete(d *Daemon, r *http.Request) Response {
	project := projectParam(r)
	name := mux.Vars(r)["name"]

	if name == "default" {
		return Forbidden(errors.New("The 'default' profile cannot be deleted"))
	}

	err := d.cluster.Transaction(func(tx *db.ClusterTx) error {
		hasProfiles, err := tx.ProjectHasProfiles(project)
		if err != nil {
			return errors.Wrap(err, "Check project features")
		}

		if !hasProfiles {
			project = "default"
		}

		profile, err := tx.ProfileGet(project, name)
		if err != nil {
			return err
		}
		if len(profile.UsedBy) > 0 {
			return fmt.Errorf("Profile is currently in use")
		}

		return tx.ProfileDelete(project, name)
	})
	if err != nil {
		return SmartError(err)
	}

	return EmptySyncResponse
}

func profileDelete ( d * Daemon , r * http . Request ) Response { project := projectParam ( r ) name := mux . Vars ( r ) [ " " ] if name == " " { return Forbidden ( errors . New ( " " ) ) } err := d . cluster . Transaction ( func ( tx * db . ClusterTx ) error { hasProfiles , err := tx . ProjectHasProfiles ( project ) if err != nil { return errors . Wrap ( err , " " ) } if ! hasProfiles { project = " " } profile , err := tx . ProfileGet ( project , name ) if err != nil { return err } if len ( profile . UsedBy ) > 0 { return fmt . Errorf ( " " ) } return tx . ProfileDelete ( project , name ) } ) if err != nil { return SmartError ( err ) } return EmptySyncResponse }

// The handler for the delete operation.


func IsRootDiskDevice(device map[string]string) bool {
	if device["type"] == "disk" && device["path"] == "/" && device["source"] == "" {
		return true
	}

	return false
}

func IsRootDiskDevice ( device map [ string ] string ) bool { if device [ " " ] == " " && device [ " " ] == " " && device [ " " ] == " " { return true } return false }

// IsRootDiskDevice returns true if the given device representation is
// configured as root disk for a container. It typically get passed a specific
// entry of api.Container.Devices.

IsRootDiskDevice returns true if the given device representation is configured as root disk for a container . It typically get passed a specific entry of api . Container . Devices .


func GetRootDiskDevice(devices map[string]map[string]string) (string, map[string]string, error) {
	var devName string
	var dev map[string]string

	for n, d := range devices {
		if IsRootDiskDevice(d) {
			if devName != "" {
				return "", nil, fmt.Errorf("More than one root device found")
			}

			devName = n
			dev = d
		}
	}

	if devName != "" {
		return devName, dev, nil
	}

	return "", nil, fmt.Errorf("No root device could be found")
}

func GetRootDiskDevice ( devices map [ string ] map [ string ] string ) ( string , map [ string ] string , error ) { var devName string var dev map [ string ] string for n , d := range devices { if IsRootDiskDevice ( d ) { if devName != " " { return " " , nil , fmt . Errorf ( " " ) } devName = n dev = d } } if devName != " " { return devName , dev , nil } return " " , nil , fmt . Errorf ( " " ) }

// GetRootDiskDevice returns the container device that is configured as root disk


func ForwardedResponse(client lxd.ContainerServer, request *http.Request) Response {
	return &forwardedResponse{
		client:  client,
		request: request,
	}
}

func ForwardedResponse ( client lxd . ContainerServer , request * http . Request ) Response { return & forwardedResponse { client : client , request : request , } }

// ForwardedResponse takes a request directed to a node and forwards it to
// another node, writing back the response it gegs.

ForwardedResponse takes a request directed to a node and forwards it to another node writing back the response it gegs .


func ForwardedResponseIfTargetIsRemote(d *Daemon, request *http.Request) Response {
	targetNode := queryParam(request, "target")
	if targetNode == "" {
		return nil
	}

	// Figure out the address of the target node (which is possibly
	// this very same node).
	address, err := cluster.ResolveTarget(d.cluster, targetNode)
	if err != nil {
		return SmartError(err)
	}

	if address != "" {
		// Forward the response.
		cert := d.endpoints.NetworkCert()
		client, err := cluster.Connect(address, cert, false)
		if err != nil {
			return SmartError(err)
		}
		return ForwardedResponse(client, request)
	}

	return nil
}

// ForwardedResponseIfTargetIsRemote redirects a request to the request has a
// targetNode parameter pointing to a node which is not the local one.

ForwardedResponseIfTargetIsRemote redirects a request to the request has a targetNode parameter pointing to a node which is not the local one .


func ForwardedResponseIfContainerIsRemote(d *Daemon, r *http.Request, project, name string) (Response, error) {
	cert := d.endpoints.NetworkCert()
	client, err := cluster.ConnectIfContainerIsRemote(d.cluster, project, name, cert)
	if err != nil {
		return nil, err
	}
	if client == nil {
		return nil, nil
	}
	return ForwardedResponse(client, r), nil
}

func ForwardedResponseIfContainerIsRemote ( d * Daemon , r * http . Request , project , name string ) ( Response , error ) { cert := d . endpoints . NetworkCert ( ) client , err := cluster . ConnectIfContainerIsRemote ( d . cluster , project , name , cert ) if err != nil { return nil , err } if client == nil { return nil , nil } return ForwardedResponse ( client , r ) , nil }

// ForwardedResponseIfContainerIsRemote redirects a request to the node running
// the container with the given name. If the container is local, nothing gets
// done and nil is returned.

ForwardedResponseIfContainerIsRemote redirects a request to the node running the container with the given name . If the container is local nothing gets done and nil is returned .


func ForwardedOperationResponse(project string, op *api.Operation) Response {
	return &forwardedOperationResponse{
		op:      op,
		project: project,
	}
}

func ForwardedOperationResponse ( project string , op * api . Operation ) Response { return & forwardedOperationResponse { op : op , project : project , } }

// ForwardedOperationResponse creates a response that forwards the metadata of
// an operation created on another node.

ForwardedOperationResponse creates a response that forwards the metadata of an operation created on another node .


func (p *ProgressRenderer) Done(msg string) {
	// Acquire rendering lock
	p.lock.Lock()
	defer p.lock.Unlock()

	// Check if we're already done
	if p.done {
		return
	}

	// Mark this renderer as done
	p.done = true

	// Handle quiet mode
	if p.Quiet {
		msg = ""
	}

	// Truncate msg to terminal length
	msg = p.truncate(msg)

	// If we're not printing a completion message and nothing was printed before just return
	if msg == "" && p.maxLength == 0 {
		return
	}

	// Print the new message
	if msg != "" {
		msg += "\n"
	}

	if len(msg) > p.maxLength {
		p.maxLength = len(msg)
	} else {
		fmt.Printf("\r%s", strings.Repeat(" ", p.maxLength))
	}

	fmt.Print("\r")
	fmt.Print(msg)
}

// Done prints the final status and prevents any update


func (p *ProgressRenderer) Update(status string) {
	// Wait if needed
	timeout := p.wait.Sub(time.Now())
	if timeout.Seconds() > 0 {
		time.Sleep(timeout)
	}

	// Acquire rendering lock
	p.lock.Lock()
	defer p.lock.Unlock()

	// Check if we're already done
	if p.done {
		return
	}

	// Handle quiet mode
	if p.Quiet {
		return
	}

	// Skip status updates when not dealing with a terminal
	if p.terminal == 0 {
		if !termios.IsTerminal(int(os.Stdout.Fd())) {
			p.terminal = -1
		}

		p.terminal = 1
	}

	if p.terminal != 1 {
		return
	}

	// Print the new message
	msg := "%s"
	if p.Format != "" {
		msg = p.Format
	}

	msg = fmt.Sprintf(msg, status)

	// Truncate msg to terminal length
	msg = "\r" + p.truncate(msg)

	// Don't print if empty and never printed
	if len(msg) == 1 && p.maxLength == 0 {
		return
	}

	if len(msg) > p.maxLength {
		p.maxLength = len(msg)
	} else {
		fmt.Printf("\r%s", strings.Repeat(" ", p.maxLength))
	}

	fmt.Print(msg)
}

// Update changes the status message to the provided string


func (p *ProgressRenderer) Warn(status string, timeout time.Duration) {
	// Acquire rendering lock
	p.lock.Lock()
	defer p.lock.Unlock()

	// Check if we're already done
	if p.done {
		return
	}

	// Render the new message
	p.wait = time.Now().Add(timeout)
	msg := fmt.Sprintf("%s", status)

	// Truncate msg to terminal length
	msg = "\r" + p.truncate(msg)

	// Don't print if empty and never printed
	if len(msg) == 1 && p.maxLength == 0 {
		return
	}

	if len(msg) > p.maxLength {
		p.maxLength = len(msg)
	} else {
		fmt.Printf("\r%s", strings.Repeat(" ", p.maxLength))
	}

	fmt.Print(msg)
}

// Warn shows a temporary message instead of the status


func (p *ProgressRenderer) UpdateProgress(progress ioprogress.ProgressData) {
	p.Update(progress.Text)
}

func ( p * ProgressRenderer ) UpdateProgress ( progress ioprogress . ProgressData ) { p . Update ( progress . Text ) }

// UpdateProgress is a helper to update the status using an iopgress instance


func (p *ProgressRenderer) UpdateOp(op api.Operation) {
	if op.Metadata == nil {
		return
	}

	for key, value := range op.Metadata {
		if !strings.HasSuffix(key, "_progress") {
			continue
		}

		p.Update(value.(string))
		break
	}
}

func ( p * ProgressRenderer ) UpdateOp ( op api . Operation ) { if op . Metadata == nil { return } for key , value := range op . Metadata { if ! strings . HasSuffix ( key , " " ) { continue } p . Update ( value . ( string ) ) break } }

// UpdateOp is a helper to update the status using a LXD API operation


func updateFromV6(tx *sql.Tx) error {
	// Fetch the IDs of all existing nodes.
	nodeIDs, err := query.SelectIntegers(tx, "SELECT id FROM nodes")
	if err != nil {
		return errors.Wrap(err, "failed to get IDs of current nodes")
	}

	// Fetch the IDs of all existing zfs pools.
	poolIDs, err := query.SelectIntegers(tx, `
SELECT id FROM storage_pools WHERE driver='zfs'
`)
	if err != nil {
		return errors.Wrap(err, "failed to get IDs of current zfs pools")
	}

	for _, poolID := range poolIDs {
		// Fetch the config for this zfs pool and check if it has the zfs.pool_name key
		config, err := query.SelectConfig(
			tx, "storage_pools_config", "storage_pool_id=? AND node_id IS NULL", poolID)
		if err != nil {
			return errors.Wrap(err, "failed to fetch of zfs pool config")
		}
		poolName, ok := config["zfs.pool_name"]
		if !ok {
			continue // This zfs storage pool does not have a zfs.pool_name config
		}

		// Delete the current zfs.pool_name key
		_, err = tx.Exec(`
DELETE FROM storage_pools_config WHERE key='zfs.pool_name' AND storage_pool_id=? AND node_id IS NULL
`, poolID)
		if err != nil {
			return errors.Wrap(err, "failed to delete zfs.pool_name config")
		}

		// Add zfs.pool_name config entry for each node
		for _, nodeID := range nodeIDs {
			_, err := tx.Exec(`
INSERT INTO storage_pools_config(storage_pool_id, node_id, key, value)
  VALUES(?, ?, 'zfs.pool_name', ?)
`, poolID, nodeID, poolName)
			if err != nil {
				return errors.Wrap(err, "failed to create zfs.pool_name node config")
			}
		}
	}

	return nil
}

// The zfs.pool_name config key is node-specific, and needs to be linked to
// nodes.

The zfs . pool_name config key is node - specific and needs to be linked to nodes .


func localCreateListener(path string, group string) (net.Listener, error) {
	err := CheckAlreadyRunning(path)
	if err != nil {
		return nil, err
	}

	err = socketUnixRemoveStale(path)
	if err != nil {
		return nil, err
	}

	listener, err := socketUnixListen(path)
	if err != nil {
		return nil, err
	}

	err = localSetAccess(path, group)
	if err != nil {
		listener.Close()
		return nil, err
	}

	return listener, nil
}

func localCreateListener ( path string , group string ) ( net . Listener , error ) { err := CheckAlreadyRunning ( path ) if err != nil { return nil , err } err = socketUnixRemoveStale ( path ) if err != nil { return nil , err } listener , err := socketUnixListen ( path ) if err != nil { return nil , err } err = localSetAccess ( path , group ) if err != nil { listener . Close ( ) return nil , err } return listener , nil }

// Create a new net.Listener bound to the unix socket of the local endpoint.

Create a new net . Listener bound to the unix socket of the local endpoint .


func NewStmt(database, pkg, entity, kind string, config map[string]string) (*Stmt, error) {
	packages, err := Packages()
	if err != nil {
		return nil, err
	}

	stmt := &Stmt{
		db:       database,
		pkg:      pkg,
		entity:   entity,
		kind:     kind,
		config:   config,
		packages: packages,
	}

	return stmt, nil
}

func NewStmt ( database , pkg , entity , kind string , config map [ string ] string ) ( * Stmt , error ) { packages , err := Packages ( ) if err != nil { return nil , err } stmt := & Stmt { db : database , pkg : pkg , entity : entity , kind : kind , config : config , packages : packages , } return stmt , nil }

// NewStmt return a new statement code snippet for running the given kind of
// query against the given database entity.

NewStmt return a new statement code snippet for running the given kind of query against the given database entity .


func (s *Stmt) Generate(buf *file.Buffer) error {
	if strings.HasPrefix(s.kind, "objects") {
		return s.objects(buf)
	}

	if strings.HasPrefix(s.kind, "create") && strings.HasSuffix(s.kind, "-ref") {
		return s.createRef(buf)
	}

	if strings.HasSuffix(s.kind, "-ref") || strings.Contains(s.kind, "-ref-by-") {
		return s.ref(buf)
	}

	if strings.HasPrefix(s.kind, "names") {
		return s.names(buf)
	}

	switch s.kind {
	case "create":
		return s.create(buf)
	case "id":
		return s.id(buf)
	case "rename":
		return s.rename(buf)
	case "update":
		return s.update(buf)
	case "delete":
		return s.delete(buf)
	default:
		return fmt.Errorf("Unknown statement '%s'", s.kind)
	}
}

func ( s * Stmt ) Generate ( buf * file . Buffer ) error { if strings . HasPrefix ( s . kind , " " ) { return s . objects ( buf ) } if strings . HasPrefix ( s . kind , " " ) && strings . HasSuffix ( s . kind , " " ) { return s . createRef ( buf ) } if strings . HasSuffix ( s . kind , " " ) || strings . Contains ( s . kind , " " ) { return s . ref ( buf ) } if strings . HasPrefix ( s . kind , " " ) { return s . names ( buf ) } switch s . kind { case " " : return s . create ( buf ) case " " : return s . id ( buf ) case " " : return s . rename ( buf ) case " " : return s . update ( buf ) case " " : return s . delete ( buf ) default : return fmt . Errorf ( " " , s . kind ) } }

// Generate plumbing and wiring code for the desired statement.

Generate plumbing and wiring code for the desired statement .


func (s *Stmt) register(buf *file.Buffer, sql string, filters ...string) {
	kind := strings.Replace(s.kind, "-", "_", -1)
	if kind == "id" {
		kind = "ID" // silence go lints
	}
	buf.L("var %s = %s.RegisterStmt(`\n%s\n`)", stmtCodeVar(s.entity, kind, filters...), s.db, sql)
}

func
(
s
*
Stmt
)
register
(
buf
*
file
.
Buffer
,
sql
string
,
filters
...
string
)
{
kind
:=
strings
.
Replace
(
s
.
kind
,
"
"
,
"
"
,
1
)
if
kind
==
"
"
{
kind
=
"
"
// silence go lints
}
buf
.
L
(
"
\n
\n
"
,
stmtCodeVar
(
s
.
entity
,
kind
,
filters
...
)
,
s
.
db
,
sql
)
}

// Output a line of code that registers the given statement and declares the
// associated statement code global variable.

Output a line of code that registers the given statement and declares the associated statement code global variable .


func httpsLXD(url string, args *ConnectionArgs) (ContainerServer, error) {
	// Use empty args if not specified
	if args == nil {
		args = &ConnectionArgs{}
	}

	// Initialize the client struct
	server := ProtocolLXD{
		httpCertificate:  args.TLSServerCert,
		httpHost:         url,
		httpProtocol:     "https",
		httpUserAgent:    args.UserAgent,
		bakeryInteractor: args.AuthInteractor,
	}
	if args.AuthType == "candid" {
		server.RequireAuthenticated(true)
	}

	// Setup the HTTP client
	httpClient, err := tlsHTTPClient(args.HTTPClient, args.TLSClientCert, args.TLSClientKey, args.TLSCA, args.TLSServerCert, args.InsecureSkipVerify, args.Proxy)
	if err != nil {
		return nil, err
	}

	if args.CookieJar != nil {
		httpClient.Jar = args.CookieJar
	}

	server.http = httpClient
	if args.AuthType == "candid" {
		server.setupBakeryClient()
	}

	// Test the connection and seed the server information
	if !args.SkipGetServer {
		_, _, err := server.GetServer()
		if err != nil {
			return nil, err
		}
	}
	return &server, nil
}

// Internal function called by ConnectLXD and ConnectPublicLXD


func (c Container) IsActive() bool {
	switch c.StatusCode {
	case Stopped:
		return false
	case Error:
		return false
	default:
		return true
	}
}

func ( c Container ) IsActive ( ) bool { switch c . StatusCode { case Stopped : return false case Error : return false default : return true } }

// IsActive checks whether the container state indicates the container is active


func (n *NodeTx) RaftNodeAddress(id int64) (string, error) {
	stmt := "SELECT address FROM raft_nodes WHERE id=?"
	addresses, err := query.SelectStrings(n.tx, stmt, id)
	if err != nil {
		return "", err
	}
	switch len(addresses) {
	case 0:
		return "", ErrNoSuchObject
	case 1:
		return addresses[0], nil
	default:
		// This should never happen since we have a UNIQUE constraint
		// on the raft_nodes.id column.
		return "", fmt.Errorf("more than one match found")
	}
}

// RaftNodeAddress returns the address of the LXD raft node with the given ID,
// if any matching row exists.

RaftNodeAddress returns the address of the LXD raft node with the given ID if any matching row exists .


func (n *NodeTx) RaftNodeFirst(address string) error {
	columns := []string{"id", "address"}
	values := []interface{}{int64(1), address}
	id, err := query.UpsertObject(n.tx, "raft_nodes", columns, values)
	if err != nil {
		return err
	}
	if id != 1 {
		return fmt.Errorf("could not set raft node ID to 1")
	}
	return nil
}

func ( n * NodeTx ) RaftNodeFirst ( address string ) error { columns := [ ] string { " " , " " } values := [ ] interface { } { int64 ( 1 ) , address } id , err := query . UpsertObject ( n . tx , " " , columns , values ) if err != nil { return err } if id != 1 { return fmt . Errorf ( " " ) } return nil }

// RaftNodeFirst adds a the first node of the cluster. It ensures that the
// database ID is 1, to match the server ID of first raft log entry.
//
// This method is supposed to be called when there are no rows in raft_nodes,
// and it will replace whatever existing row has ID 1.

RaftNodeFirst adds a the first node of the cluster . It ensures that the database ID is 1 to match the server ID of first raft log entry . This method is supposed to be called when there are no rows in raft_nodes and it will replace whatever existing row has ID 1 .


func (n *NodeTx) RaftNodeAdd(address string) (int64, error) {
	columns := []string{"address"}
	values := []interface{}{address}
	return query.UpsertObject(n.tx, "raft_nodes", columns, values)
}

func ( n * NodeTx ) RaftNodeAdd ( address string ) ( int64 , error ) { columns := [ ] string { " " } values := [ ] interface { } { address } return query . UpsertObject ( n . tx , " " , columns , values ) }

// RaftNodeAdd adds a node to the current list of LXD nodes that are part of the
// dqlite Raft cluster. It returns the ID of the newly inserted row.

RaftNodeAdd adds a node to the current list of LXD nodes that are part of the dqlite Raft cluster . It returns the ID of the newly inserted row .


func (n *NodeTx) RaftNodeDelete(id int64) error {
	deleted, err := query.DeleteObject(n.tx, "raft_nodes", id)
	if err != nil {
		return err
	}
	if !deleted {
		return ErrNoSuchObject
	}
	return nil
}

func ( n * NodeTx ) RaftNodeDelete ( id int64 ) error { deleted , err := query . DeleteObject ( n . tx , " " , id ) if err != nil { return err } if ! deleted { return ErrNoSuchObject } return nil }

// RaftNodeDelete removes a node from the current list of LXD nodes that are
// part of the dqlite Raft cluster.

RaftNodeDelete removes a node from the current list of LXD nodes that are part of the dqlite Raft cluster .


func (n *NodeTx) RaftNodesReplace(nodes []RaftNode) error {
	_, err := n.tx.Exec("DELETE FROM raft_nodes")
	if err != nil {
		return err
	}

	columns := []string{"id", "address"}
	for _, node := range nodes {
		values := []interface{}{node.ID, node.Address}
		_, err := query.UpsertObject(n.tx, "raft_nodes", columns, values)
		if err != nil {
			return err
		}
	}
	return nil
}

func ( n * NodeTx ) RaftNodesReplace ( nodes [ ] RaftNode ) error { _ , err := n . tx . Exec ( " " ) if err != nil { return err } columns := [ ] string { " " , " " } for _ , node := range nodes { values := [ ] interface { } { node . ID , node . Address } _ , err := query . UpsertObject ( n . tx , " " , columns , values ) if err != nil { return err } } return nil }

// RaftNodesReplace replaces the current list of raft nodes.

RaftNodesReplace replaces the current list of raft nodes .


func (s *OS) initCGroup() {
	flags := []*bool{
		&s.CGroupBlkioController,
		&s.CGroupCPUController,
		&s.CGroupCPUacctController,
		&s.CGroupCPUsetController,
		&s.CGroupDevicesController,
		&s.CGroupFreezerController,
		&s.CGroupMemoryController,
		&s.CGroupNetPrioController,
		&s.CGroupPidsController,
		&s.CGroupSwapAccounting,
	}
	for i, flag := range flags {
		*flag = shared.PathExists("/sys/fs/cgroup/" + cGroups[i].path)
		if !*flag {
			logger.Warnf(cGroups[i].warn)
		}
	}
}

func ( s * OS ) initCGroup ( ) { flags := [ ] * bool { & s . CGroupBlkioController , & s . CGroupCPUController , & s . CGroupCPUacctController , & s . CGroupCPUsetController , & s . CGroupDevicesController , & s . CGroupFreezerController , & s . CGroupMemoryController , & s . CGroupNetPrioController , & s . CGroupPidsController , & s . CGroupSwapAccounting , } for i , flag := range flags { * flag = shared . PathExists ( " " + cGroups [ i ] . path ) if ! * flag { logger . Warnf ( cGroups [ i ] . warn ) } } }


func sqliteDirectAccess(conn *sqlite3.SQLiteConn) error {
	// Ensure journal mode is set to WAL, as this is a requirement for
	// replication.
	_, err := conn.Exec("PRAGMA journal_mode=wal", nil)
	if err != nil {
		return err
	}

	// Ensure we don't truncate or checkpoint the WAL on exit, as this
	// would bork replication which must be in full control of the WAL
	// file.
	_, err = conn.Exec("PRAGMA journal_size_limit=-1", nil)
	if err != nil {
		return err
	}

	// Ensure WAL autocheckpoint is disabled, since checkpoints are
	// triggered explicitly by dqlite.
	_, err = conn.Exec("PRAGMA wal_autocheckpoint=0", nil)
	if err != nil {
		return err
	}

	return nil
}

// Configure the sqlite connection so that it's safe to access the
// dqlite-managed sqlite file, also without setting up raft.

Configure the sqlite connection so that it s safe to access the dqlite - managed sqlite file also without setting up raft .


func (c *ClusterTx) ContainerGet(project string, name string) (*Container, error) {
	filter := ContainerFilter{}
	filter.Project = project
	filter.Name = name
	filter.Type = -1

	objects, err := c.ContainerList(filter)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to fetch Container")
	}

	switch len(objects) {
	case 0:
		return nil, ErrNoSuchObject
	case 1:
		return &objects[0], nil
	default:
		return nil, fmt.Errorf("More than one container matches")
	}
}

func ( c * ClusterTx ) ContainerGet ( project string , name string ) ( * Container , error ) { filter := ContainerFilter { } filter . Project = project filter . Name = name filter . Type = - 1 objects , err := c . ContainerList ( filter ) if err != nil { return nil , errors . Wrap ( err , " " ) } switch len ( objects ) { case 0 : return nil , ErrNoSuchObject case 1 : return & objects [ 0 ] , nil default : return nil , fmt . Errorf ( " " ) } }

// ContainerGet returns the container with the given key.

ContainerGet returns the container with the given key .


func (c *ClusterTx) ContainerID(project string, name string) (int64, error) {
	stmt := c.stmt(containerID)
	rows, err := stmt.Query(project, name)
	if err != nil {
		return -1, errors.Wrap(err, "Failed to get container ID")
	}
	defer rows.Close()

	// For sanity, make sure we read one and only one row.
	if !rows.Next() {
		return -1, ErrNoSuchObject
	}
	var id int64
	err = rows.Scan(&id)
	if err != nil {
		return -1, errors.Wrap(err, "Failed to scan ID")
	}
	if rows.Next() {
		return -1, fmt.Errorf("More than one row returned")
	}
	err = rows.Err()
	if err != nil {
		return -1, errors.Wrap(err, "Result set failure")
	}

	return id, nil
}

// ContainerID return the ID of the container with the given key.

ContainerID return the ID of the container with the given key .


func (c *ClusterTx) ContainerExists(project string, name string) (bool, error) {
	_, err := c.ContainerID(project, name)
	if err != nil {
		if err == ErrNoSuchObject {
			return false, nil
		}
		return false, err
	}

	return true, nil
}

func ( c * ClusterTx ) ContainerExists ( project string , name string ) ( bool , error ) { _ , err := c . ContainerID ( project , name ) if err != nil { if err == ErrNoSuchObject { return false , nil } return false , err } return true , nil }

// ContainerExists checks if a container with the given key exists.

ContainerExists checks if a container with the given key exists .


func (m *Mapping) ContainsFields(fields []*Field) bool {
	matches := map[*Field]bool{}

	for _, field := range m.Fields {
		for _, other := range fields {
			if field.Name == other.Name && field.Type.Name == other.Type.Name {
				matches[field] = true
			}
		}
	}

	return len(matches) == len(fields)
}

func ( m * Mapping ) ContainsFields ( fields [ ] * Field ) bool { matches := map [ * Field ] bool { } for _ , field := range m . Fields { for _ , other := range fields { if field . Name == other . Name && field . Type . Name == other . Type . Name { matches [ field ] = true } } } return len ( matches ) == len ( fields ) }

// ContainsFields checks that the mapping contains fields with the same type
// and name of given ones.

ContainsFields checks that the mapping contains fields with the same type and name of given ones .


func (m *Mapping) FieldByName(name string) *Field {
	for _, field := range m.Fields {
		if field.Name == name {
			return field
		}
	}

	return nil
}

func ( m * Mapping ) FieldByName ( name string ) * Field { for _ , field := range m . Fields { if field . Name == name { return field } } return nil }

// FieldByName returns the field with the given name, if any.

FieldByName returns the field with the given name if any .


func (m *Mapping) FieldColumnName(name string) string {
	field := m.FieldByName(name)
	return fmt.Sprintf("%s.%s", entityTable(m.Name), field.Column())
}

func ( m * Mapping ) FieldColumnName ( name string ) string { field := m . FieldByName ( name ) return fmt . Sprintf ( " " , entityTable ( m . Name ) , field . Column ( ) ) }

// FieldColumnName returns the column name of the field with the given name,
// prefixed with the entity's table name.

FieldColumnName returns the column name of the field with the given name prefixed with the entity s table name .


func (m *Mapping) FilterFieldByName(name string) (*Field, error) {
	field := m.FieldByName(name)
	if field == nil {
		return nil, fmt.Errorf("Unknown filter %q", name)
	}

	if field.Type.Code != TypeColumn {
		return nil, fmt.Errorf("Unknown filter %q not a column", name)
	}

	return field, nil
}

func ( m * Mapping ) FilterFieldByName ( name string ) ( * Field , error ) { field := m . FieldByName ( name ) if field == nil { return nil , fmt . Errorf ( " " , name ) } if field . Type . Code != TypeColumn { return nil , fmt . Errorf ( " " , name ) } return field , nil }

// FilterFieldByName returns the field with the given name if that field can be
// used as query filter, an error otherwise.

FilterFieldByName returns the field with the given name if that field can be used as query filter an error otherwise .


func (m *Mapping) ColumnFields(exclude ...string) []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if shared.StringInSlice(field.Name, exclude) {
			continue
		}
		if field.Type.Code == TypeColumn {
			fields = append(fields, field)
		}
	}

	return fields
}

func ( m * Mapping ) ColumnFields ( exclude ... string ) [ ] * Field { fields := [ ] * Field { } for _ , field := range m . Fields { if shared . StringInSlice ( field . Name , exclude ) { continue } if field . Type . Code == TypeColumn { fields = append ( fields , field ) } } return fields }

// ColumnFields returns the fields that map directly to a database column,
// either on this table or on a joined one.

ColumnFields returns the fields that map directly to a database column either on this table or on a joined one .


func (m *Mapping) ScalarFields() []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if field.Config.Get("join") != "" {
			fields = append(fields, field)
		}
	}

	return fields
}

func ( m * Mapping ) ScalarFields ( ) [ ] * Field { fields := [ ] * Field { } for _ , field := range m . Fields { if field . Config . Get ( " " ) != " " { fields = append ( fields , field ) } } return fields }

// ScalarFields returns the fields that map directly to a single database
// column on another table that can be joined to this one.

ScalarFields returns the fields that map directly to a single database column on another table that can be joined to this one .


func (m *Mapping) RefFields() []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if field.Type.Code == TypeSlice || field.Type.Code == TypeMap {
			fields = append(fields, field)
		}
	}

	return fields
}

func ( m * Mapping ) RefFields ( ) [ ] * Field { fields := [ ] * Field { } for _ , field := range m . Fields { if field . Type . Code == TypeSlice || field . Type . Code == TypeMap { fields = append ( fields , field ) } } return fields }

// RefFields returns the fields that are one-to-many references to other
// tables.

RefFields returns the fields that are one - to - many references to other tables .


func (f *Field) Column() string {
	if f.Type.Code != TypeColumn {
		panic("attempt to get column name of non-column field")
	}

	column := lex.Snake(f.Name)

	join := f.Config.Get("join")
	if join != "" {
		column = fmt.Sprintf("%s AS %s", join, column)

	}

	return column
}

func ( f * Field ) Column ( ) string { if f . Type . Code != TypeColumn { panic ( " " ) } column := lex . Snake ( f . Name ) join := f . Config . Get ( " " ) if join != " " { column = fmt . Sprintf ( " " , join , column ) } return column }

// Column returns the name of the database column the field maps to. The type
// code of the field must be TypeColumn.

Column returns the name of the database column the field maps to . The type code of the field must be TypeColumn .


func (f *Field) ZeroValue() string {
	if f.Type.Code != TypeColumn {
		panic("attempt to get zero value of non-column field")
	}

	switch f.Type.Name {
	case "string":
		return `""`
	case "int":
		// FIXME: we use -1 since at the moment integer criteria are
		// required to be positive.
		return "-1"
	default:
		panic("unsupported zero value")
	}
}

// ZeroValue returns the literal representing the zero value for this field. The type
// code of the field must be TypeColumn.

ZeroValue returns the literal representing the zero value for this field . The type code of the field must be TypeColumn .


func FieldColumns(fields []*Field) string {
	columns := make([]string, len(fields))

	for i, field := range fields {
		columns[i] = field.Column()
	}

	return strings.Join(columns, ", ")
}

func FieldColumns ( fields [ ] * Field ) string { columns := make ( [ ] string , len ( fields ) ) for i , field := range fields { columns [ i ] = field . Column ( ) } return strings . Join ( columns , " " ) }

// FieldColumns converts thegiven fields to list of column names separated
// by a comma.

FieldColumns converts thegiven fields to list of column names separated by a comma .


func FieldArgs(fields []*Field) string {
	args := make([]string, len(fields))
	for i, field := range fields {
		args[i] = fmt.Sprintf("%s %s", lex.Minuscule(field.Name), field.Type.Name)
	}

	return strings.Join(args, ", ")
}

func FieldArgs ( fields [ ] * Field ) string { args := make ( [ ] string , len ( fields ) ) for i , field := range fields { args [ i ] = fmt . Sprintf ( " " , lex . Minuscule ( field . Name ) , field . Type . Name ) } return strings . Join ( args , " " ) }

// FieldArgs converts the given fields to function arguments, rendering their
// name and type.

FieldArgs converts the given fields to function arguments rendering their name and type .


func FieldParams(fields []*Field) string {
	args := make([]string, len(fields))
	for i, field := range fields {
		args[i] = lex.Minuscule(field.Name)
	}

	return strings.Join(args, ", ")
}

func FieldParams ( fields [ ] * Field ) string { args := make ( [ ] string , len ( fields ) ) for i , field := range fields { args [ i ] = lex . Minuscule ( field . Name ) } return strings . Join ( args , " " ) }

// FieldParams converts the given fields to function parameters, rendering their
// name.

FieldParams converts the given fields to function parameters rendering their name .


func FieldCriteria(fields []*Field) string {
	criteria := make([]string, len(fields))

	for i, field := range fields {
		criteria[i] = fmt.Sprintf("%s = ?", field.Column())
	}

	return strings.Join(criteria, " AND ")
}

func FieldCriteria ( fields [ ] * Field ) string { criteria := make ( [ ] string , len ( fields ) ) for i , field := range fields { criteria [ i ] = fmt . Sprintf ( " " , field . Column ( ) ) } return strings . Join ( criteria , " " ) }

// FieldCriteria converts the given fields to AND-separated WHERE criteria.

FieldCriteria converts the given fields to AND - separated WHERE criteria .


func initDataClusterApply(d lxd.ContainerServer, config *initDataCluster) error {
	if config == nil || !config.Enabled {
		return nil
	}

	// Get the current cluster configuration
	currentCluster, etag, err := d.GetCluster()
	if err != nil {
		return errors.Wrap(err, "Failed to retrieve current cluster config")
	}

	// Check if already enabled
	if !currentCluster.Enabled {
		// Configure the cluster
		op, err := d.UpdateCluster(config.ClusterPut, etag)
		if err != nil {
			return errors.Wrap(err, "Failed to configure cluster")
		}

		err = op.Wait()
		if err != nil {
			return errors.Wrap(err, "Failed to configure cluster")
		}
	}

	return nil
}

// Helper to initialize LXD clustering.
//
// Used by the 'lxd init' command.

Helper to initialize LXD clustering . Used by the lxd init command .


func JsonFormatEx(pretty, lineSeparated bool) Format {
	jsonMarshal := json.Marshal
	if pretty {
		jsonMarshal = func(v interface{}) ([]byte, error) {
			return json.MarshalIndent(v, "", "    ")
		}
	}

	return FormatFunc(func(r *Record) []byte {
		props := make(map[string]interface{})

		props[r.KeyNames.Time] = r.Time
		props[r.KeyNames.Lvl] = r.Lvl
		props[r.KeyNames.Msg] = r.Msg

		for i := 0; i < len(r.Ctx); i += 2 {
			k, ok := r.Ctx[i].(string)
			if !ok {
				props[errorKey] = fmt.Sprintf("%+v is not a string key", r.Ctx[i])
			}
			props[k] = formatJsonValue(r.Ctx[i+1])
		}

		b, err := jsonMarshal(props)
		if err != nil {
			b, _ = jsonMarshal(map[string]string{
				errorKey: err.Error(),
			})
			return b
		}

		if lineSeparated {
			b = append(b, '\n')
		}

		return b
	})
}

func JsonFormatEx ( pretty , lineSeparated bool ) Format { jsonMarshal := json . Marshal if pretty { jsonMarshal = func ( v interface { } ) ( [ ] byte , error ) { return json . MarshalIndent ( v , " " , " " ) } } return FormatFunc ( func ( r * Record ) [ ] byte { props := make ( map [ string ] interface { } ) props [ r . KeyNames . Time ] = r . Time props [ r . KeyNames . Lvl ] = r . Lvl props [ r . KeyNames . Msg ] = r . Msg for i := 0 ; i < len ( r . Ctx ) ; i += 2 { k , ok := r . Ctx [ i ] . ( string ) if ! ok { props [ errorKey ] = fmt . Sprintf ( " " , r . Ctx [ i ] ) } props [ k ] = formatJsonValue ( r . Ctx [ i + 1 ] ) } b , err := jsonMarshal ( props ) if err != nil { b , _ = jsonMarshal ( map [ string ] string { errorKey : err . Error ( ) , } ) return b } if lineSeparated { b = append ( b , '\n' ) } return b } ) }

// JsonFormatEx formats log records as JSON objects. If pretty is true,
// records will be pretty-printed. If lineSeparated is true, records
// will be logged with a new line between each record.

JsonFormatEx formats log records as JSON objects . If pretty is true records will be pretty - printed . If lineSeparated is true records will be logged with a new line between each record .


func formatLogfmtValue(value interface{}) string {
	if value == nil {
		return "nil"
	}

	value = formatShared(value)
	switch v := value.(type) {
	case bool:
		return strconv.FormatBool(v)
	case float32:
		return strconv.FormatFloat(float64(v), floatFormat, 3, 64)
	case float64:
		return strconv.FormatFloat(v, floatFormat, 3, 64)
	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
		return fmt.Sprintf("%d", value)
	case string:
		return escapeString(v)
	default:
		return escapeString(fmt.Sprintf("%+v", value))
	}
}

func formatLogfmtValue ( value interface { } ) string { if value == nil { return " " } value = formatShared ( value ) switch v := value . ( type ) { case bool : return strconv . FormatBool ( v ) case float32 : return strconv . FormatFloat ( float64 ( v ) , floatFormat , 3 , 64 ) case float64 : return strconv . FormatFloat ( v , floatFormat , 3 , 64 ) case int , int8 , int16 , int32 , int64 , uint , uint8 , uint16 , uint32 , uint64 : return fmt . Sprintf ( " " , value ) case string : return escapeString ( v ) default : return escapeString ( fmt . Sprintf ( " " , value ) ) } }

// formatValue formats a value for serialization


func ResolveTarget(cluster *db.Cluster, target string) (string, error) {
	address := ""
	err := cluster.Transaction(func(tx *db.ClusterTx) error {
		name, err := tx.NodeName()
		if err != nil {
			return err
		}

		if target == name {
			return nil
		}

		node, err := tx.NodeByName(target)
		if err != nil {
			if err == db.ErrNoSuchObject {
				return fmt.Errorf("No cluster member called '%s'", target)
			}

			return err
		}

		if node.Name != name {
			address = node.Address
		}

		return nil
	})

	return address, err
}

func ResolveTarget ( cluster * db . Cluster , target string ) ( string , error ) { address := " " err := cluster . Transaction ( func ( tx * db . ClusterTx ) error { name , err := tx . NodeName ( ) if err != nil { return err } if target == name { return nil } node , err := tx . NodeByName ( target ) if err != nil { if err == db . ErrNoSuchObject { return fmt . Errorf ( " " , target ) } return err } if node . Name != name { address = node . Address } return nil } ) return address , err }

// ResolveTarget is a convenience for handling the value ?targetNode query
// parameter. It returns the address of the given node, or the empty string if
// the given node is the local one.

ResolveTarget is a convenience for handling the value ?targetNode query parameter . It returns the address of the given node or the empty string if the given node is the local one .


func (pt *ProgressWriter) Write(p []byte) (int, error) {
	// Do normal writer tasks
	n, err := pt.WriteCloser.Write(p)

	// Do the actual progress tracking
	if pt.Tracker != nil {
		pt.Tracker.total += int64(n)
		pt.Tracker.update(n)
	}

	return n, err
}

func
(
pt
*
ProgressWriter
)
Write
(
p
[
]
byte
)
(
int
,
error
)
{
// Do normal writer tasks
n
,
err
:=
pt
.
WriteCloser
.
Write
(
p
)
// Do the actual progress tracking
if
pt
.
Tracker
!=
{
pt
.
Tracker
.
total
+=
int64
(
n
)
pt
.
Tracker
.
update
(
n
)
}
return
n
,
err
}

// Write in ProgressWriter is the same as io.Write

Write in ProgressWriter is the same as io . Write


func updateNodeVersion(tx *sql.Tx, address string, apiExtensions int) error {
	stmt := "UPDATE nodes SET schema=?, api_extensions=? WHERE address=?"
	result, err := tx.Exec(stmt, len(updates), apiExtensions, address)
	if err != nil {
		return err
	}
	n, err := result.RowsAffected()
	if err != nil {
		return err
	}
	if n != 1 {
		return fmt.Errorf("updated %d rows instead of 1", n)
	}
	return nil
}

func updateNodeVersion ( tx * sql . Tx , address string , apiExtensions int ) error { stmt := " " result , err := tx . Exec ( stmt , len ( updates ) , apiExtensions , address ) if err != nil { return err } n , err := result . RowsAffected ( ) if err != nil { return err } if n != 1 { return fmt . Errorf ( " " , n ) } return nil }

// Update the schema and api_extensions columns of the row in the nodes table
// that matches the given id.
//
// If not such row is found, an error is returned.

Update the schema and api_extensions columns of the row in the nodes table that matches the given id . If not such row is found an error is returned .


func selectNodesVersions(tx *sql.Tx) ([][2]int, error) {
	versions := [][2]int{}

	dest := func(i int) []interface{} {
		versions = append(versions, [2]int{})
		return []interface{}{&versions[i][0], &versions[i][1]}
	}

	stmt, err := tx.Prepare("SELECT schema, api_extensions FROM nodes")
	if err != nil {
		return nil, err
	}
	defer stmt.Close()
	err = query.SelectObjects(stmt, dest)
	if err != nil {
		return nil, err
	}
	return versions, nil
}

func selectNodesVersions ( tx * sql . Tx ) ( [ ] [ 2 ] int , error ) { versions := [ ] [ 2 ] int { } dest := func ( i int ) [ ] interface { } { versions = append ( versions , [ 2 ] int { } ) return [ ] interface { } { & versions [ i ] [ 0 ] , & versions [ i ] [ 1 ] } } stmt , err := tx . Prepare ( " " ) if err != nil { return nil , err } defer stmt . Close ( ) err = query . SelectObjects ( stmt , dest ) if err != nil { return nil , err } return versions , nil }

// Return a slice of binary integer tuples. Each tuple contains the schema
// version and number of api extensions of a node in the cluster.

Return a slice of binary integer tuples . Each tuple contains the schema version and number of api extensions of a node in the cluster .


func GetArchitectures() ([]int, error) {
	architectures := []int{}

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

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

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

func GetArchitectures ( ) ( [ ] int , error ) { architectures := [ ] int { } architectureName , err := osarch . ArchitectureGetLocal ( ) if err != nil { return nil , err } architecture , err := osarch . ArchitectureId ( architectureName ) if err != nil { return nil , err } architectures = append ( architectures , architecture ) personalities , err := osarch . ArchitecturePersonalities ( architecture ) if err != nil { return nil , err } for _ , personality := range personalities { architectures = append ( architectures , personality ) } return architectures , nil }

// GetArchitectures returns the list of supported architectures.

GetArchitectures returns the list of supported architectures .


func RuntimeLiblxcVersionAtLeast(major int, minor int, micro int) bool {
	version := golxc.Version()
	version = strings.Replace(version, " (devel)", "-devel", 1)
	parts := strings.Split(version, ".")
	partsLen := len(parts)
	if partsLen == 0 {
		return false
	}

	develParts := strings.Split(parts[partsLen-1], "-")
	if len(develParts) == 2 && develParts[1] == "devel" {
		return true
	}

	maj := -1
	min := -1
	mic := -1

	for i, v := range parts {
		if i > 2 {
			break
		}

		num, err := strconv.Atoi(v)
		if err != nil {
			return false
		}

		switch i {
		case 0:
			maj = num
		case 1:
			min = num
		case 2:
			mic = num
		}
	}

	/* Major version is greater. */
	if maj > major {
		return true
	}

	if maj < major {
		return false
	}

	/* Minor number is greater.*/
	if min > minor {
		return true
	}

	if min < minor {
		return false
	}

	/* Patch number is greater. */
	if mic > micro {
		return true
	}

	if mic < micro {
		return false
	}

	return true
}

func
RuntimeLiblxcVersionAtLeast
(
major
int
,
minor
int
,
micro
int
)
bool
{
version
:=
golxc
.
Version
(
)
version
=
strings
.
Replace
(
version
,
"
"
,
"
"
,
1
)
parts
:=
strings
.
Split
(
version
,
"
"
)
partsLen
:=
len
(
parts
)
if
partsLen
==
0
{
return
false
}
develParts
:=
strings
.
Split
(
parts
[
partsLen
1
]
,
"
"
)
if
len
(
develParts
)
==
2
&&
develParts
[
1
]
==
"
"
{
return
true
}
maj
:=
1
min
:=
1
mic
:=
1
for
i
,
v
:=
range
parts
{
if
i
>
2
{
break
}
num
,
err
:=
strconv
.
Atoi
(
v
)
if
err
!=
{
return
false
}
switch
i
{
case
0
:
maj
=
num
case
1
:
min
=
num
case
2
:
mic
=
num
}
}
/* Major version is greater. */
if
maj
>
major
{
return
true
}
if
maj
<
major
{
return
false
}
/* Minor number is greater.*/
if
min
>
minor
{
return
true
}
if
min
<
minor
{
return
false
}
/* Patch number is greater. */
if
mic
>
micro
{
return
true
}
if
mic
<
micro
{
return
false
}
return
true
}

// RuntimeLiblxcVersionAtLeast checks if the system's liblxc matches the
// provided version requirement

RuntimeLiblxcVersionAtLeast checks if the system s liblxc matches the provided version requirement


func GetExecPath() string {
	execPath := os.Getenv("LXD_EXEC_PATH")
	if execPath != "" {
		return execPath
	}

	execPath, err := os.Readlink("/proc/self/exe")
	if err != nil {
		execPath = "bad-exec-path"
	}
	return execPath
}

func GetExecPath ( ) string { execPath := os . Getenv ( " " ) if execPath != " " { return execPath } execPath , err := os . Readlink ( " " ) if err != nil { execPath = " " } return execPath }

// GetExecPath returns the path to the current binary