func (r *ProtocolLXD) GetContainerMetadata(name string) (*api.ImageMetadata, string, error) {
	if !r.HasExtension("container_edit_metadata") {
		return nil, "", fmt.Errorf("The server is missing the required \"container_edit_metadata\" API extension")
	}

	metadata := api.ImageMetadata{}

	url := fmt.Sprintf("/containers/%s/metadata", url.QueryEscape(name))
	etag, err := r.queryStruct("GET", url, nil, "", &metadata)
	if err != nil {
		return nil, "", err
	}

	return &metadata, etag, err
}

func ( r * ProtocolLXD ) GetContainerMetadata ( name string ) ( * api . ImageMetadata , string , error ) { if ! r . HasExtension ( " " ) { return nil , " " , fmt . Errorf ( " \" \" " ) } metadata := api . ImageMetadata { } url := fmt . Sprintf ( " " , url . QueryEscape ( name ) ) etag , err := r . queryStruct ( " " , url , nil , " " , & metadata ) if err != nil { return nil , " " , err } return & metadata , etag , err }

// GetContainerMetadata returns container metadata.

GetContainerMetadata returns container metadata .


func (r *ProtocolLXD) SetContainerMetadata(name string, metadata api.ImageMetadata, ETag string) error {
	if !r.HasExtension("container_edit_metadata") {
		return fmt.Errorf("The server is missing the required \"container_edit_metadata\" API extension")
	}

	url := fmt.Sprintf("/containers/%s/metadata", url.QueryEscape(name))
	_, _, err := r.query("PUT", url, metadata, ETag)
	if err != nil {
		return err
	}

	return nil
}

func ( r * ProtocolLXD ) SetContainerMetadata ( name string , metadata api . ImageMetadata , ETag string ) error { if ! r . HasExtension ( " " ) { return fmt . Errorf ( " \" \" " ) } url := fmt . Sprintf ( " " , url . QueryEscape ( name ) ) _ , _ , err := r . query ( " " , url , metadata , ETag ) if err != nil { return err } return nil }

// SetContainerMetadata sets the content of the container metadata file.

SetContainerMetadata sets the content of the container metadata file .


func (r *ProtocolLXD) GetContainerTemplateFiles(containerName string) ([]string, error) {
	if !r.HasExtension("container_edit_metadata") {
		return nil, fmt.Errorf("The server is missing the required \"container_edit_metadata\" API extension")
	}

	templates := []string{}

	url := fmt.Sprintf("/containers/%s/metadata/templates", url.QueryEscape(containerName))
	_, err := r.queryStruct("GET", url, nil, "", &templates)
	if err != nil {
		return nil, err
	}

	return templates, nil
}

func ( r * ProtocolLXD ) GetContainerTemplateFiles ( containerName string ) ( [ ] string , error ) { if ! r . HasExtension ( " " ) { return nil , fmt . Errorf ( " \" \" " ) } templates := [ ] string { } url := fmt . Sprintf ( " " , url . QueryEscape ( containerName ) ) _ , err := r . queryStruct ( " " , url , nil , " " , & templates ) if err != nil { return nil , err } return templates , nil }

// GetContainerTemplateFiles returns the list of names of template files for a container.

GetContainerTemplateFiles returns the list of names of template files for a container .


func (r *ProtocolLXD) CreateContainerTemplateFile(containerName string, templateName string, content io.ReadSeeker) error {
	return r.setContainerTemplateFile(containerName, templateName, content, "POST")
}

func ( r * ProtocolLXD ) CreateContainerTemplateFile ( containerName string , templateName string , content io . ReadSeeker ) error { return r . setContainerTemplateFile ( containerName , templateName , content , " " ) }

// CreateContainerTemplateFile creates an a template for a container.

CreateContainerTemplateFile creates an a template for a container .


func (r *ProtocolLXD) DeleteContainerTemplateFile(name string, templateName string) error {
	if !r.HasExtension("container_edit_metadata") {
		return fmt.Errorf("The server is missing the required \"container_edit_metadata\" API extension")
	}
	_, _, err := r.query("DELETE", fmt.Sprintf("/containers/%s/metadata/templates?path=%s", url.QueryEscape(name), url.QueryEscape(templateName)), nil, "")
	return err
}

func ( r * ProtocolLXD ) DeleteContainerTemplateFile ( name string , templateName string ) error { if ! r . HasExtension ( " " ) { return fmt . Errorf ( " \" \" " ) } _ , _ , err := r . query ( " " , fmt . Sprintf ( " " , url . QueryEscape ( name ) , url . QueryEscape ( templateName ) ) , nil , " " ) return err }

// DeleteContainerTemplateFile deletes a template file for a container.

DeleteContainerTemplateFile deletes a template file for a container .


func (r *ProtocolLXD) ConsoleContainer(containerName string, console api.ContainerConsolePost, args *ContainerConsoleArgs) (Operation, error) {
	if !r.HasExtension("console") {
		return nil, fmt.Errorf("The server is missing the required \"console\" API extension")
	}

	// Send the request
	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s/console", url.QueryEscape(containerName)), console, "")
	if err != nil {
		return nil, err
	}
	opAPI := op.Get()

	if args == nil || args.Terminal == nil {
		return nil, fmt.Errorf("A terminal must be set")
	}

	if args.Control == nil {
		return nil, fmt.Errorf("A control channel must be set")
	}

	// Parse the fds
	fds := map[string]string{}

	value, ok := opAPI.Metadata["fds"]
	if ok {
		values := value.(map[string]interface{})
		for k, v := range values {
			fds[k] = v.(string)
		}
	}

	var controlConn *websocket.Conn
	// Call the control handler with a connection to the control socket
	if fds["control"] == "" {
		return nil, fmt.Errorf("Did not receive a file descriptor for the control channel")
	}

	controlConn, err = r.GetOperationWebsocket(opAPI.ID, fds["control"])
	if err != nil {
		return nil, err
	}

	go args.Control(controlConn)

	// Connect to the websocket
	conn, err := r.GetOperationWebsocket(opAPI.ID, fds["0"])
	if err != nil {
		return nil, err
	}

	// Detach from console.
	go func(consoleDisconnect <-chan bool) {
		<-consoleDisconnect
		msg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "Detaching from console")
		// We don't care if this fails. This is just for convenience.
		controlConn.WriteMessage(websocket.CloseMessage, msg)
		controlConn.Close()
	}(args.ConsoleDisconnect)

	// And attach stdin and stdout to it
	go func() {
		shared.WebsocketSendStream(conn, args.Terminal, -1)
		<-shared.WebsocketRecvStream(args.Terminal, conn)
		conn.Close()
	}()

	return op, nil
}

// ConsoleContainer requests that LXD attaches to the console device of a container.

ConsoleContainer requests that LXD attaches to the console device of a container .


func (r *ProtocolLXD) GetContainerConsoleLog(containerName string, args *ContainerConsoleLogArgs) (io.ReadCloser, error) {
	if !r.HasExtension("console") {
		return nil, fmt.Errorf("The server is missing the required \"console\" API extension")
	}

	// Prepare the HTTP request
	url := fmt.Sprintf("%s/1.0/containers/%s/console", r.httpHost, url.QueryEscape(containerName))

	url, err := r.setQueryAttributes(url)
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	// Set the user agent
	if r.httpUserAgent != "" {
		req.Header.Set("User-Agent", r.httpUserAgent)
	}

	// Send the request
	resp, err := r.do(req)
	if err != nil {
		return nil, err
	}

	// Check the return value for a cleaner error
	if resp.StatusCode != http.StatusOK {
		_, _, err := lxdParseResponse(resp)
		if err != nil {
			return nil, err
		}
	}

	return resp.Body, err
}

// GetContainerConsoleLog requests that LXD attaches to the console device of a container.
//
// Note that it's the caller's responsibility to close the returned ReadCloser

GetContainerConsoleLog requests that LXD attaches to the console device of a container . Note that it s the caller s responsibility to close the returned ReadCloser


func (r *ProtocolLXD) DeleteContainerConsoleLog(containerName string, args *ContainerConsoleLogArgs) error {
	if !r.HasExtension("console") {
		return fmt.Errorf("The server is missing the required \"console\" API extension")
	}

	// Send the request
	_, _, err := r.query("DELETE", fmt.Sprintf("/containers/%s/console", url.QueryEscape(containerName)), nil, "")
	if err != nil {
		return err
	}

	return nil
}

func
(
r
*
ProtocolLXD
)
DeleteContainerConsoleLog
(
containerName
string
,
args
*
ContainerConsoleLogArgs
)
error
{
if
!
r
.
HasExtension
(
"
"
)
{
return
fmt
.
Errorf
(
"
\"
\"
"
)
}
// Send the request
_
,
_
,
err
:=
r
.
query
(
"
"
,
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
containerName
)
)
,
,
"
"
)
if
err
!=
{
return
err
}
return
}

// DeleteContainerConsoleLog deletes the requested container's console log

DeleteContainerConsoleLog deletes the requested container s console log


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

	// Fetch the raw value
	backups := []api.ContainerBackup{}

	_, err := r.queryStruct("GET", fmt.Sprintf("/containers/%s/backups?recursion=1", url.QueryEscape(containerName)), nil, "", &backups)
	if err != nil {
		return nil, err
	}

	return backups, nil
}

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

// GetContainerBackups returns a list of backups for the container


func (r *ProtocolLXD) GetContainerBackup(containerName string, name string) (*api.ContainerBackup, string, error) {
	if !r.HasExtension("container_backup") {
		return nil, "", fmt.Errorf("The server is missing the required \"container_backup\" API extension")
	}

	// Fetch the raw value
	backup := api.ContainerBackup{}
	etag, err := r.queryStruct("GET", fmt.Sprintf("/containers/%s/backups/%s", url.QueryEscape(containerName), url.QueryEscape(name)), nil, "", &backup)
	if err != nil {
		return nil, "", err
	}

	return &backup, etag, nil
}

func
(
r
*
ProtocolLXD
)
GetContainerBackup
(
containerName
string
,
name
string
)
(
*
api
.
ContainerBackup
,
string
,
error
)
{
if
!
r
.
HasExtension
(
"
"
)
{
return
,
"
"
,
fmt
.
Errorf
(
"
\"
\"
"
)
}
// Fetch the raw value
backup
:=
api
.
ContainerBackup
{
}
etag
,
err
:=
r
.
queryStruct
(
"
"
,
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
containerName
)
,
url
.
QueryEscape
(
name
)
)
,
,
"
"
,
&
backup
)
if
err
!=
{
return
,
"
"
,
err
}
return
&
backup
,
etag
,
}

// GetContainerBackup returns a Backup struct for the provided container and backup names


func (r *ProtocolLXD) CreateContainerBackup(containerName string, backup api.ContainerBackupsPost) (Operation, error) {
	if !r.HasExtension("container_backup") {
		return nil, fmt.Errorf("The server is missing the required \"container_backup\" API extension")
	}

	// Send the request
	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s/backups",
		url.QueryEscape(containerName)), backup, "")
	if err != nil {
		return nil, err
	}

	return op, nil
}

func
(
r
*
ProtocolLXD
)
CreateContainerBackup
(
containerName
string
,
backup
api
.
ContainerBackupsPost
)
(
Operation
,
error
)
{
if
!
r
.
HasExtension
(
"
"
)
{
return
,
fmt
.
Errorf
(
"
\"
\"
"
)
}
// Send the request
op
,
_
,
err
:=
r
.
queryOperation
(
"
"
,
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
containerName
)
)
,
backup
,
"
"
)
if
err
!=
{
return
,
err
}
return
op
,
}

// CreateContainerBackup requests that LXD creates a new backup for the container


func (r *ProtocolLXD) RenameContainerBackup(containerName string, name string, backup api.ContainerBackupPost) (Operation, error) {
	if !r.HasExtension("container_backup") {
		return nil, fmt.Errorf("The server is missing the required \"container_backup\" API extension")
	}

	// Send the request
	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s/backups/%s",
		url.QueryEscape(containerName), url.QueryEscape(name)), backup, "")
	if err != nil {
		return nil, err
	}

	return op, nil
}

func
(
r
*
ProtocolLXD
)
RenameContainerBackup
(
containerName
string
,
name
string
,
backup
api
.
ContainerBackupPost
)
(
Operation
,
error
)
{
if
!
r
.
HasExtension
(
"
"
)
{
return
,
fmt
.
Errorf
(
"
\"
\"
"
)
}
// Send the request
op
,
_
,
err
:=
r
.
queryOperation
(
"
"
,
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
containerName
)
,
url
.
QueryEscape
(
name
)
)
,
backup
,
"
"
)
if
err
!=
{
return
,
err
}
return
op
,
}

// RenameContainerBackup requests that LXD renames the backup


func (r *ProtocolLXD) DeleteContainerBackup(containerName string, name string) (Operation, error) {
	if !r.HasExtension("container_backup") {
		return nil, fmt.Errorf("The server is missing the required \"container_backup\" API extension")
	}

	// Send the request
	op, _, err := r.queryOperation("DELETE", fmt.Sprintf("/containers/%s/backups/%s",
		url.QueryEscape(containerName), url.QueryEscape(name)), nil, "")
	if err != nil {
		return nil, err
	}

	return op, nil
}

func
(
r
*
ProtocolLXD
)
DeleteContainerBackup
(
containerName
string
,
name
string
)
(
Operation
,
error
)
{
if
!
r
.
HasExtension
(
"
"
)
{
return
,
fmt
.
Errorf
(
"
\"
\"
"
)
}
// Send the request
op
,
_
,
err
:=
r
.
queryOperation
(
"
"
,
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
containerName
)
,
url
.
QueryEscape
(
name
)
)
,
,
"
"
)
if
err
!=
{
return
,
err
}
return
op
,
}

// DeleteContainerBackup requests that LXD deletes the container backup


func (r *ProtocolLXD) GetContainerBackupFile(containerName string, name string, req *BackupFileRequest) (*BackupFileResponse, error) {
	if !r.HasExtension("container_backup") {
		return nil, fmt.Errorf("The server is missing the required \"container_backup\" API extension")
	}

	// Build the URL
	uri := fmt.Sprintf("%s/1.0/containers/%s/backups/%s/export", r.httpHost,
		url.QueryEscape(containerName), url.QueryEscape(name))
	if r.project != "" {
		uri += fmt.Sprintf("?project=%s", url.QueryEscape(r.project))
	}

	// Prepare the download request
	request, err := http.NewRequest("GET", uri, nil)
	if err != nil {
		return nil, err
	}

	if r.httpUserAgent != "" {
		request.Header.Set("User-Agent", r.httpUserAgent)
	}

	// Start the request
	response, doneCh, err := cancel.CancelableDownload(req.Canceler, r.http, request)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	defer close(doneCh)

	if response.StatusCode != http.StatusOK {
		_, _, err := lxdParseResponse(response)
		if err != nil {
			return nil, err
		}
	}

	// Handle the data
	body := response.Body
	if req.ProgressHandler != nil {
		body = &ioprogress.ProgressReader{
			ReadCloser: response.Body,
			Tracker: &ioprogress.ProgressTracker{
				Length: response.ContentLength,
				Handler: func(percent int64, speed int64) {
					req.ProgressHandler(ioprogress.ProgressData{Text: fmt.Sprintf("%d%% (%s/s)", percent, shared.GetByteSizeString(speed, 2))})
				},
			},
		}
	}

	size, err := io.Copy(req.BackupFile, body)
	if err != nil {
		return nil, err
	}

	resp := BackupFileResponse{}
	resp.Size = size

	return &resp, nil
}

func
(
r
*
ProtocolLXD
)
GetContainerBackupFile
(
containerName
string
,
name
string
,
req
*
BackupFileRequest
)
(
*
BackupFileResponse
,
error
)
{
if
!
r
.
HasExtension
(
"
"
)
{
return
,
fmt
.
Errorf
(
"
\"
\"
"
)
}
// Build the URL
uri
:=
fmt
.
Sprintf
(
"
"
,
r
.
httpHost
,
url
.
QueryEscape
(
containerName
)
,
url
.
QueryEscape
(
name
)
)
if
r
.
project
!=
"
"
{
uri
+=
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
r
.
project
)
)
}
// Prepare the download request
request
,
err
:=
http
.
NewRequest
(
"
"
,
uri
,
)
if
err
!=
{
return
,
err
}
if
r
.
httpUserAgent
!=
"
"
{
request
.
Header
.
Set
(
"
"
,
r
.
httpUserAgent
)
}
// Start the request
response
,
doneCh
,
err
:=
cancel
.
CancelableDownload
(
req
.
Canceler
,
r
.
http
,
request
)
if
err
!=
{
return
,
err
}
defer
response
.
Body
.
Close
(
)
defer
close
(
doneCh
)
if
response
.
StatusCode
!=
http
.
StatusOK
{
_
,
_
,
err
:=
lxdParseResponse
(
response
)
if
err
!=
{
return
,
err
}
}
// Handle the data
body
:=
response
.
Body
if
req
.
ProgressHandler
!=
{
body
=
&
ioprogress
.
ProgressReader
{
ReadCloser
:
response
.
Body
,
Tracker
:
&
ioprogress
.
ProgressTracker
{
Length
:
response
.
ContentLength
,
Handler
:
func
(
percent
int64
,
speed
int64
)
{
req
.
ProgressHandler
(
ioprogress
.
ProgressData
{
Text
:
fmt
.
Sprintf
(
"
"
,
percent
,
shared
.
GetByteSizeString
(
speed
,
2
)
)
}
)
}
,
}
,
}
}
size
,
err
:=
io
.
Copy
(
req
.
BackupFile
,
body
)
if
err
!=
{
return
,
err
}
resp
:=
BackupFileResponse
{
}
resp
.
Size
=
size
return
&
resp
,
}

// GetContainerBackupFile requests the container backup content


func RsyncSend(name string, path string, conn *websocket.Conn, readWrapper func(io.ReadCloser) io.ReadCloser, features []string, bwlimit string, execPath string) error {
	cmd, dataSocket, stderr, err := rsyncSendSetup(name, path, bwlimit, execPath, features)
	if err != nil {
		return err
	}

	if dataSocket != nil {
		defer dataSocket.Close()
	}

	readPipe := io.ReadCloser(dataSocket)
	if readWrapper != nil {
		readPipe = readWrapper(dataSocket)
	}

	readDone, writeDone := shared.WebsocketMirror(conn, dataSocket, readPipe, nil, nil)

	chError := make(chan error, 1)
	go func() {
		err = cmd.Wait()
		if err != nil {
			dataSocket.Close()
			readPipe.Close()
		}
		chError <- err
	}()

	output, err := ioutil.ReadAll(stderr)
	if err != nil {
		cmd.Process.Kill()
	}

	err = <-chError
	if err != nil {
		logger.Errorf("Rsync send failed: %s: %s: %s", path, err, string(output))
	}

	<-readDone
	<-writeDone

	return err
}

func RsyncSend ( name string , path string , conn * websocket . Conn , readWrapper func ( io . ReadCloser ) io . ReadCloser , features [ ] string , bwlimit string , execPath string ) error { cmd , dataSocket , stderr , err := rsyncSendSetup ( name , path , bwlimit , execPath , features ) if err != nil { return err } if dataSocket != nil { defer dataSocket . Close ( ) } readPipe := io . ReadCloser ( dataSocket ) if readWrapper != nil { readPipe = readWrapper ( dataSocket ) } readDone , writeDone := shared . WebsocketMirror ( conn , dataSocket , readPipe , nil , nil ) chError := make ( chan error , 1 ) go func ( ) { err = cmd . Wait ( ) if err != nil { dataSocket . Close ( ) readPipe . Close ( ) } chError <- err } ( ) output , err := ioutil . ReadAll ( stderr ) if err != nil { cmd . Process . Kill ( ) } err = <- chError if err != nil { logger . Errorf ( " " , path , err , string ( output ) ) } <- readDone <- writeDone return err }

// RsyncSend sets up the sending half of an rsync, to recursively send the
// directory pointed to by path over the websocket.

RsyncSend sets up the sending half of an rsync to recursively send the directory pointed to by path over the websocket .


func patchesGetNames() []string {
	names := make([]string, len(patches))
	for i, patch := range patches {
		names[i] = patch.name
	}
	return names
}

func patchesGetNames ( ) [ ] string { names := make ( [ ] string , len ( patches ) ) for i , patch := range patches { names [ i ] = patch . name } return names }

// Return the names of all available patches.

Return the names of all available patches .


func patchRenameCustomVolumeLVs(name string, d *Daemon) error {
	// Ignore the error since it will also fail if there are no pools.
	pools, _ := d.cluster.StoragePools()

	for _, poolName := range pools {
		poolID, pool, err := d.cluster.StoragePoolGet(poolName)
		if err != nil {
			return err
		}

		sType, err := storageStringToType(pool.Driver)
		if err != nil {
			return err
		}

		if sType != storageTypeLvm {
			continue
		}

		volumes, err := d.cluster.StoragePoolNodeVolumesGetType(storagePoolVolumeTypeCustom, poolID)
		if err != nil {
			return err
		}

		vgName := poolName
		if pool.Config["lvm.vg_name"] != "" {
			vgName = pool.Config["lvm.vg_name"]
		}

		for _, volume := range volumes {
			oldName := fmt.Sprintf("%s/custom_%s", vgName, volume)
			newName := fmt.Sprintf("%s/custom_%s", vgName, containerNameToLVName(volume))

			exists, err := storageLVExists(newName)
			if err != nil {
				return err
			}

			if exists || oldName == newName {
				continue
			}

			err = lvmLVRename(vgName, oldName, newName)
			if err != nil {
				return err
			}

			logger.Info("Successfully renamed LV", log.Ctx{"old_name": oldName, "new_name": newName})
		}
	}

	return nil
}


func patchLvmNodeSpecificConfigKeys(name string, d *Daemon) error {
	tx, err := d.cluster.Begin()
	if err != nil {
		return errors.Wrap(err, "failed to begin transaction")
	}

	// 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 lvm pools.
	poolIDs, err := query.SelectIntegers(tx, "SELECT id FROM storage_pools WHERE driver='lvm'")
	if err != nil {
		return errors.Wrap(err, "failed to get IDs of current lvm pools")
	}

	for _, poolID := range poolIDs {
		// Fetch the config for this lvm pool and check if it has the
		// lvn.thinpool_name or lvm.vg_name keys.
		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 lvm pool config")
		}

		for _, key := range []string{"lvm.thinpool_name", "lvm.vg_name"} {
			value, ok := config[key]
			if !ok {
				continue
			}

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

			// Add the 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(?, ?, ?, ?)
`, poolID, nodeID, key, value)
				if err != nil {
					return errors.Wrapf(err, "failed to create %s node config", key)
				}
			}
		}
	}

	err = tx.Commit()
	if err != nil {
		return errors.Wrap(err, "failed to commit transaction")
	}

	return err
}

// The lvm.thinpool_name and lvm.vg_name config keys are node-specific and need
// to be linked to nodes.

The lvm . thinpool_name and lvm . vg_name config keys are node - specific and need to be linked to nodes .


func (r *ProtocolLXD) GetHTTPClient() (*http.Client, error) {
	if r.http == nil {
		return nil, fmt.Errorf("HTTP client isn't set, bad connection")
	}

	return r.http, nil
}

func ( r * ProtocolLXD ) GetHTTPClient ( ) ( * http . Client , error ) { if r . http == nil { return nil , fmt . Errorf ( " " ) } return r . http , nil }

// GetHTTPClient returns the http client used for the connection. This can be used to set custom http options.

GetHTTPClient returns the http client used for the connection . This can be used to set custom http options .


func (r *ProtocolLXD) do(req *http.Request) (*http.Response, error) {
	if r.bakeryClient != nil {
		r.addMacaroonHeaders(req)
		return r.bakeryClient.Do(req)
	}

	return r.http.Do(req)
}

func ( r * ProtocolLXD ) do ( req * http . Request ) ( * http . Response , error ) { if r . bakeryClient != nil { r . addMacaroonHeaders ( req ) return r . bakeryClient . Do ( req ) } return r . http . Do ( req ) }

// Do performs a Request, using macaroon authentication if set.

Do performs a Request using macaroon authentication if set .


func (r *ProtocolLXD) RawQuery(method string, path string, data interface{}, ETag string) (*api.Response, string, error) {
	// Generate the URL
	url := fmt.Sprintf("%s%s", r.httpHost, path)

	return r.rawQuery(method, url, data, ETag)
}

func
(
r
*
ProtocolLXD
)
RawQuery
(
method
string
,
path
string
,
data
interface
{
}
,
ETag
string
)
(
*
api
.
Response
,
string
,
error
)
{
// Generate the URL
url
:=
fmt
.
Sprintf
(
"
"
,
r
.
httpHost
,
path
)
return
r
.
rawQuery
(
method
,
url
,
data
,
ETag
)
}

// RawQuery allows directly querying the LXD API
//
// This should only be used by internal LXD tools.

RawQuery allows directly querying the LXD API This should only be used by internal LXD tools .


func (r *ProtocolLXD) RawWebsocket(path string) (*websocket.Conn, error) {
	return r.websocket(path)
}

func ( r * ProtocolLXD ) RawWebsocket ( path string ) ( * websocket . Conn , error ) { return r . websocket ( path ) }

// RawWebsocket allows directly connection to LXD API websockets
//
// This should only be used by internal LXD tools.

RawWebsocket allows directly connection to LXD API websockets This should only be used by internal LXD tools .


func (r *ProtocolLXD) RawOperation(method string, path string, data interface{}, ETag string) (Operation, string, error) {
	return r.queryOperation(method, path, data, ETag)
}

func ( r * ProtocolLXD ) RawOperation ( method string , path string , data interface { } , ETag string ) ( Operation , string , error ) { return r . queryOperation ( method , path , data , ETag ) }

// RawOperation allows direct querying of a LXD API endpoint returning
// background operations.

RawOperation allows direct querying of a LXD API endpoint returning background operations .


func ProfileToAPI(profile *Profile) *api.Profile {
	p := &api.Profile{
		Name:   profile.Name,
		UsedBy: profile.UsedBy,
	}
	p.Description = profile.Description
	p.Config = profile.Config
	p.Devices = profile.Devices

	return p
}

func ProfileToAPI ( profile * Profile ) * api . Profile { p := & api . Profile { Name : profile . Name , UsedBy : profile . UsedBy , } p . Description = profile . Description p . Config = profile . Config p . Devices = profile . Devices return p }

// ProfileToAPI is a convenience to convert a Profile db struct into
// an API profile struct.

ProfileToAPI is a convenience to convert a Profile db struct into an API profile struct .


func (c *Cluster) Profiles(project string) ([]string, error) {
	err := c.Transaction(func(tx *ClusterTx) error {
		enabled, err := tx.ProjectHasProfiles(project)
		if err != nil {
			return errors.Wrap(err, "Check if project has profiles")
		}
		if !enabled {
			project = "default"
		}
		return nil
	})
	if err != nil {
		return nil, err
	}

	q := fmt.Sprintf(`
SELECT profiles.name
 FROM profiles
 JOIN projects ON projects.id = profiles.project_id
WHERE projects.name = ?
`)
	inargs := []interface{}{project}
	var name string
	outfmt := []interface{}{name}
	result, err := queryScan(c.db, q, inargs, outfmt)
	if err != nil {
		return []string{}, err
	}

	response := []string{}
	for _, r := range result {
		response = append(response, r[0].(string))
	}

	return response, nil
}

// Profiles returns a string list of profiles.

Profiles returns a string list of profiles .


func (c *Cluster) ProfileGet(project, name string) (int64, *api.Profile, error) {
	var result *api.Profile
	var id int64

	err := c.Transaction(func(tx *ClusterTx) error {
		enabled, err := tx.ProjectHasProfiles(project)
		if err != nil {
			return errors.Wrap(err, "Check if project has profiles")
		}
		if !enabled {
			project = "default"
		}

		profile, err := tx.ProfileGet(project, name)
		if err != nil {
			return err
		}

		result = ProfileToAPI(profile)
		id = int64(profile.ID)

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

	return id, result, nil
}

func ( c * Cluster ) ProfileGet ( project , name string ) ( int64 , * api . Profile , error ) { var result * api . Profile var id int64 err := c . Transaction ( func ( tx * ClusterTx ) error { enabled , err := tx . ProjectHasProfiles ( project ) if err != nil { return errors . Wrap ( err , " " ) } if ! enabled { project = " " } profile , err := tx . ProfileGet ( project , name ) if err != nil { return err } result = ProfileToAPI ( profile ) id = int64 ( profile . ID ) return nil } ) if err != nil { return - 1 , nil , err } return id , result , nil }

// ProfileGet returns the profile with the given name.

ProfileGet returns the profile with the given name .


func (c *Cluster) ProfilesGet(project string, names []string) ([]api.Profile, error) {
	profiles := make([]api.Profile, len(names))

	err := c.Transaction(func(tx *ClusterTx) error {
		enabled, err := tx.ProjectHasProfiles(project)
		if err != nil {
			return errors.Wrap(err, "Check if project has profiles")
		}
		if !enabled {
			project = "default"
		}

		for i, name := range names {
			profile, err := tx.ProfileGet(project, name)
			if err != nil {
				return errors.Wrapf(err, "Load profile %q", name)
			}
			profiles[i] = *ProfileToAPI(profile)
		}

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

	return profiles, nil
}

func ( c * Cluster ) ProfilesGet ( project string , names [ ] string ) ( [ ] api . Profile , error ) { profiles := make ( [ ] api . Profile , len ( names ) ) err := c . Transaction ( func ( tx * ClusterTx ) error { enabled , err := tx . ProjectHasProfiles ( project ) if err != nil { return errors . Wrap ( err , " " ) } if ! enabled { project = " " } for i , name := range names { profile , err := tx . ProfileGet ( project , name ) if err != nil { return errors . Wrapf ( err , " " , name ) } profiles [ i ] = * ProfileToAPI ( profile ) } return nil } ) if err != nil { return nil , err } return profiles , nil }

// ProfilesGet returns the profiles with the given names in the given project.

ProfilesGet returns the profiles with the given names in the given project .


func (c *Cluster) ProfileConfig(project, name string) (map[string]string, error) {
	err := c.Transaction(func(tx *ClusterTx) error {
		enabled, err := tx.ProjectHasProfiles(project)
		if err != nil {
			return errors.Wrap(err, "Check if project has profiles")
		}
		if !enabled {
			project = "default"
		}
		return nil
	})
	if err != nil {
		return nil, err
	}

	var key, value string
	query := `
        SELECT
            key, value
        FROM profiles_config
        JOIN profiles ON profiles_config.profile_id=profiles.id
        JOIN projects ON projects.id = profiles.project_id
        WHERE projects.name=? AND profiles.name=?`
	inargs := []interface{}{project, name}
	outfmt := []interface{}{key, value}
	results, err := queryScan(c.db, query, inargs, outfmt)
	if err != nil {
		return nil, errors.Wrapf(err, "Failed to get profile '%s'", name)
	}

	if len(results) == 0 {
		/*
		 * If we didn't get any rows here, let's check to make sure the
		 * profile really exists; if it doesn't, let's send back a 404.
		 */
		query := "SELECT id FROM profiles WHERE name=?"
		var id int
		results, err := queryScan(c.db, query, []interface{}{name}, []interface{}{id})
		if err != nil {
			return nil, err
		}

		if len(results) == 0 {
			return nil, ErrNoSuchObject
		}
	}

	config := map[string]string{}

	for _, r := range results {
		key = r[0].(string)
		value = r[1].(string)

		config[key] = value
	}

	return config, nil
}

// ProfileConfig gets the profile configuration map from the DB.

ProfileConfig gets the profile configuration map from the DB .


func ProfileConfigClear(tx *sql.Tx, id int64) error {
	_, err := tx.Exec("DELETE FROM profiles_config WHERE profile_id=?", id)
	if err != nil {
		return err
	}

	_, err = tx.Exec(`DELETE FROM profiles_devices_config WHERE id IN
		(SELECT profiles_devices_config.id
		 FROM profiles_devices_config JOIN profiles_devices
		 ON profiles_devices_config.profile_device_id=profiles_devices.id
		 WHERE profiles_devices.profile_id=?)`, id)
	if err != nil {
		return err
	}
	_, err = tx.Exec("DELETE FROM profiles_devices WHERE profile_id=?", id)
	if err != nil {
		return err
	}
	return nil
}

// ProfileConfigClear resets the config of the profile with the given ID.

ProfileConfigClear resets the config of the profile with the given ID .


func ProfileConfigAdd(tx *sql.Tx, id int64, config map[string]string) error {
	str := fmt.Sprintf("INSERT INTO profiles_config (profile_id, key, value) VALUES(?, ?, ?)")
	stmt, err := tx.Prepare(str)
	defer stmt.Close()
	if err != nil {
		return err
	}

	for k, v := range config {
		if v == "" {
			continue
		}

		_, err = stmt.Exec(id, k, v)
		if err != nil {
			return err
		}
	}

	return nil
}

func ProfileConfigAdd ( tx * sql . Tx , id int64 , config map [ string ] string ) error { str := fmt . Sprintf ( " " ) stmt , err := tx . Prepare ( str ) defer stmt . Close ( ) if err != nil { return err } for k , v := range config { if v == " " { continue } _ , err = stmt . Exec ( id , k , v ) if err != nil { return err } } return nil }

// ProfileConfigAdd adds a config to the profile with the given ID.

ProfileConfigAdd adds a config to the profile with the given ID .


func (c *Cluster) ProfileContainersGet(project, profile string) (map[string][]string, error) {
	err := c.Transaction(func(tx *ClusterTx) error {
		enabled, err := tx.ProjectHasProfiles(project)
		if err != nil {
			return errors.Wrap(err, "Check if project has profiles")
		}
		if !enabled {
			project = "default"
		}
		return nil
	})
	if err != nil {
		return nil, err
	}

	q := `SELECT containers.name, projects.name FROM containers
		JOIN containers_profiles ON containers.id == containers_profiles.container_id
		JOIN projects ON projects.id == containers.project_id
		WHERE containers_profiles.profile_id ==
		  (SELECT profiles.id FROM profiles
		   JOIN projects ON projects.id == profiles.project_id
		   WHERE profiles.name=? AND projects.name=?)
		AND containers.type == 0`

	results := map[string][]string{}
	inargs := []interface{}{profile, project}
	var name string
	outfmt := []interface{}{name, name}

	output, err := queryScan(c.db, q, inargs, outfmt)
	if err != nil {
		return nil, err
	}

	for _, r := range output {
		if results[r[1].(string)] == nil {
			results[r[1].(string)] = []string{}
		}

		results[r[1].(string)] = append(results[r[1].(string)], r[0].(string))
	}

	return results, nil
}

// ProfileContainersGet gets the names of the containers associated with the
// profile with the given name.

ProfileContainersGet gets the names of the containers associated with the profile with the given name .


func (c *Cluster) ProfileCleanupLeftover() error {
	stmt := `
DELETE FROM profiles_config WHERE profile_id NOT IN (SELECT id FROM profiles);
DELETE FROM profiles_devices WHERE profile_id NOT IN (SELECT id FROM profiles);
DELETE FROM profiles_devices_config WHERE profile_device_id NOT IN (SELECT id FROM profiles_devices);
`
	err := exec(c.db, stmt)
	if err != nil {
		return err
	}

	return nil
}

// ProfileCleanupLeftover removes unreferenced profiles.

ProfileCleanupLeftover removes unreferenced profiles .


func ProfilesExpandConfig(config map[string]string, profiles []api.Profile) map[string]string {
	expandedConfig := map[string]string{}

	// Apply all the profiles
	profileConfigs := make([]map[string]string, len(profiles))
	for i, profile := range profiles {
		profileConfigs[i] = profile.Config
	}

	for i := range profileConfigs {
		for k, v := range profileConfigs[i] {
			expandedConfig[k] = v
		}
	}

	// Stick the given config on top
	for k, v := range config {
		expandedConfig[k] = v
	}

	return expandedConfig
}

func
ProfilesExpandConfig
(
config
map
[
string
]
string
,
profiles
[
]
api
.
Profile
)
map
[
string
]
string
{
expandedConfig
:=
map
[
string
]
string
{
}
// Apply all the profiles
profileConfigs
:=
make
(
[
]
map
[
string
]
string
,
len
(
profiles
)
)
for
i
,
profile
:=
range
profiles
{
profileConfigs
[
i
]
=
profile
.
Config
}
for
i
:=
range
profileConfigs
{
for
k
,
v
:=
range
profileConfigs
[
i
]
{
expandedConfig
[
k
]
=
v
}
}
// Stick the given config on top
for
k
,
v
:=
range
config
{
expandedConfig
[
k
]
=
v
}
return
expandedConfig
}

// ProfilesExpandConfig expands the given container config with the config
// values of the given profiles.

ProfilesExpandConfig expands the given container config with the config values of the given profiles .


func ProfilesExpandDevices(devices types.Devices, profiles []api.Profile) types.Devices {
	expandedDevices := types.Devices{}

	// Apply all the profiles
	profileDevices := make([]types.Devices, len(profiles))
	for i, profile := range profiles {
		profileDevices[i] = profile.Devices
	}
	for i := range profileDevices {
		for k, v := range profileDevices[i] {
			expandedDevices[k] = v
		}
	}

	// Stick the given devices on top
	for k, v := range devices {
		expandedDevices[k] = v
	}

	return expandedDevices
}

func
ProfilesExpandDevices
(
devices
types
.
Devices
,
profiles
[
]
api
.
Profile
)
types
.
Devices
{
expandedDevices
:=
types
.
Devices
{
}
// Apply all the profiles
profileDevices
:=
make
(
[
]
types
.
Devices
,
len
(
profiles
)
)
for
i
,
profile
:=
range
profiles
{
profileDevices
[
i
]
=
profile
.
Devices
}
for
i
:=
range
profileDevices
{
for
k
,
v
:=
range
profileDevices
[
i
]
{
expandedDevices
[
k
]
=
v
}
}
// Stick the given devices on top
for
k
,
v
:=
range
devices
{
expandedDevices
[
k
]
=
v
}
return
expandedDevices
}

// ProfilesExpandDevices expands the given container devices with the devices
// defined in the given profiles.

ProfilesExpandDevices expands the given container devices with the devices defined in the given profiles .


func (r *ProtocolLXD) GetServer() (*api.Server, string, error) {
	server := api.Server{}

	// Fetch the raw value
	etag, err := r.queryStruct("GET", "", nil, "", &server)
	if err != nil {
		return nil, "", err
	}

	// Fill in certificate fingerprint if not provided
	if server.Environment.CertificateFingerprint == "" && server.Environment.Certificate != "" {
		var err error
		server.Environment.CertificateFingerprint, err = shared.CertFingerprintStr(server.Environment.Certificate)
		if err != nil {
			return nil, "", err
		}
	}

	if !server.Public && len(server.AuthMethods) == 0 {
		// TLS is always available for LXD servers
		server.AuthMethods = []string{"tls"}
	}

	// Add the value to the cache
	r.server = &server

	return &server, etag, nil
}

// Server handling functions
// GetServer returns the server status as a Server struct

Server handling functions GetServer returns the server status as a Server struct


func (r *ProtocolLXD) UpdateServer(server api.ServerPut, ETag string) error {
	// Send the request
	_, _, err := r.query("PUT", "", server, ETag)
	if err != nil {
		return err
	}

	return nil
}

func
(
r
*
ProtocolLXD
)
UpdateServer
(
server
api
.
ServerPut
,
ETag
string
)
error
{
// Send the request
_
,
_
,
err
:=
r
.
query
(
"
"
,
"
"
,
server
,
ETag
)
if
err
!=
{
return
err
}
return
}

// UpdateServer updates the server status to match the provided Server struct


func (r *ProtocolLXD) HasExtension(extension string) bool {
	// If no cached API information, just assume we're good
	// This is needed for those rare cases where we must avoid a GetServer call
	if r.server == nil {
		return true
	}

	for _, entry := range r.server.APIExtensions {
		if entry == extension {
			return true
		}
	}

	return false
}

// HasExtension returns true if the server supports a given API extension


func (r *ProtocolLXD) GetServerResources() (*api.Resources, error) {
	if !r.HasExtension("resources") {
		return nil, fmt.Errorf("The server is missing the required \"resources\" API extension")
	}

	resources := api.Resources{}

	// Fetch the raw value
	_, err := r.queryStruct("GET", "/resources", nil, "", &resources)
	if err != nil {
		return nil, err
	}

	return &resources, nil
}

func
(
r
*
ProtocolLXD
)
GetServerResources
(
)
(
*
api
.
Resources
,
error
)
{
if
!
r
.
HasExtension
(
"
"
)
{
return
,
fmt
.
Errorf
(
"
\"
\"
"
)
}
resources
:=
api
.
Resources
{
}
// Fetch the raw value
_
,
err
:=
r
.
queryStruct
(
"
"
,
"
"
,
,
"
"
,
&
resources
)
if
err
!=
{
return
,
err
}
return
&
resources
,
}

// GetServerResources returns the resources available to a given LXD server


func (r *ProtocolLXD) UseProject(name string) ContainerServer {
	return &ProtocolLXD{
		server:               r.server,
		http:                 r.http,
		httpCertificate:      r.httpCertificate,
		httpHost:             r.httpHost,
		httpProtocol:         r.httpProtocol,
		httpUserAgent:        r.httpUserAgent,
		bakeryClient:         r.bakeryClient,
		bakeryInteractor:     r.bakeryInteractor,
		requireAuthenticated: r.requireAuthenticated,
		clusterTarget:        r.clusterTarget,
		project:              name,
	}
}

func ( r * ProtocolLXD ) UseProject ( name string ) ContainerServer { return & ProtocolLXD { server : r . server , http : r . http , httpCertificate : r . httpCertificate , httpHost : r . httpHost , httpProtocol : r . httpProtocol , httpUserAgent : r . httpUserAgent , bakeryClient : r . bakeryClient , bakeryInteractor : r . bakeryInteractor , requireAuthenticated : r . requireAuthenticated , clusterTarget : r . clusterTarget , project : name , } }

// UseProject returns a client that will use a specific project.

UseProject returns a client that will use a specific project .


func sqliteOpen(path string) (*sql.DB, error) {
	timeout := 5 // TODO - make this command-line configurable?

	// These are used to tune the transaction BEGIN behavior instead of using the
	// similar "locking_mode" pragma (locking for the whole database connection).
	openPath := fmt.Sprintf("%s?_busy_timeout=%d&_txlock=exclusive", path, timeout*1000)

	// Open the database. If the file doesn't exist it is created.
	return sql.Open("sqlite3_with_fk", openPath)
}

// Opens the node-level database with the correct parameters for LXD.

Opens the node - level database with the correct parameters for LXD .


func Rebalance(state *state.State, gateway *Gateway) (string, []db.RaftNode, error) {
	// First get the current raft members, since this method should be
	// called after a node has left.
	currentRaftNodes, err := gateway.currentRaftNodes()
	if err != nil {
		return "", nil, errors.Wrap(err, "failed to get current raft nodes")
	}
	if len(currentRaftNodes) >= membershipMaxRaftNodes {
		// We're already at full capacity.
		return "", nil, nil
	}

	currentRaftAddresses := make([]string, len(currentRaftNodes))
	for i, node := range currentRaftNodes {
		currentRaftAddresses[i] = node.Address
	}

	// Check if we have a spare node that we can turn into a database one.
	address := ""
	err = state.Cluster.Transaction(func(tx *db.ClusterTx) error {
		config, err := ConfigLoad(tx)
		if err != nil {
			return errors.Wrap(err, "failed load cluster configuration")
		}
		nodes, err := tx.Nodes()
		if err != nil {
			return errors.Wrap(err, "failed to get cluster nodes")
		}
		// Find a node that is not part of the raft cluster yet.
		for _, node := range nodes {
			if shared.StringInSlice(node.Address, currentRaftAddresses) {
				continue // This is already a database node
			}
			if node.IsOffline(config.OfflineThreshold()) {
				continue // This node is offline
			}
			logger.Debugf(
				"Found spare node %s (%s) to be promoted as database node", node.Name, node.Address)
			address = node.Address
			break
		}

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

	if address == "" {
		// No node to promote
		return "", nil, nil
	}

	// Update the local raft_table adding the new member and building a new
	// list.
	updatedRaftNodes := currentRaftNodes
	err = gateway.db.Transaction(func(tx *db.NodeTx) error {
		id, err := tx.RaftNodeAdd(address)
		if err != nil {
			return errors.Wrap(err, "failed to add new raft node")
		}
		updatedRaftNodes = append(updatedRaftNodes, db.RaftNode{ID: id, Address: address})
		err = tx.RaftNodesReplace(updatedRaftNodes)
		if err != nil {
			return errors.Wrap(err, "failed to update raft nodes")
		}
		return nil
	})
	if err != nil {
		return "", nil, err
	}
	return address, updatedRaftNodes, nil
}

// Rebalance the raft cluster, trying to see if we have a spare online node
// that we can promote to database node if we are below membershipMaxRaftNodes.
//
// If there's such spare node, return its address as well as the new list of
// raft nodes.

Rebalance the raft cluster trying to see if we have a spare online node that we can promote to database node if we are below membershipMaxRaftNodes . If there s such spare node return its address as well as the new list of raft nodes .


func Promote(state *state.State, gateway *Gateway, nodes []db.RaftNode) error {
	logger.Info("Promote node to database node")

	// Sanity check that this is not already a database node
	if gateway.IsDatabaseNode() {
		return fmt.Errorf("this node is already a database node")
	}

	// Figure out our own address.
	address := ""
	err := state.Cluster.Transaction(func(tx *db.ClusterTx) error {
		var err error
		address, err = tx.NodeAddress()
		if err != nil {
			return errors.Wrap(err, "failed to fetch the address of this node")
		}
		return nil
	})
	if err != nil {
		return err
	}

	// Sanity check that we actually have an address.
	if address == "" {
		return fmt.Errorf("node is not exposed on the network")
	}

	// Figure out our raft node ID, and an existing target raft node that
	// we'll contact to add ourselves as member.
	id := ""
	target := ""
	for _, node := range nodes {
		if node.Address == address {
			id = strconv.Itoa(int(node.ID))
		} else {
			target = node.Address
		}
	}

	// Sanity check that our address was actually included in the given
	// list of raft nodes.
	if id == "" {
		return fmt.Errorf("this node is not included in the given list of database nodes")
	}

	// Replace our local list of raft nodes with the given one (which
	// includes ourselves). This will make the gateway start a raft node
	// when restarted.
	err = state.Node.Transaction(func(tx *db.NodeTx) error {
		err = tx.RaftNodesReplace(nodes)
		if err != nil {
			return errors.Wrap(err, "failed to set raft nodes")
		}

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

	// Lock regular access to the cluster database since we don't want any
	// other database code to run while we're reconfiguring raft.
	err = state.Cluster.EnterExclusive()
	if err != nil {
		return errors.Wrap(err, "failed to acquire cluster database lock")
	}

	// Wipe all existing raft data, for good measure (perhaps they were
	// somehow leftover).
	err = os.RemoveAll(state.OS.GlobalDatabaseDir())
	if err != nil {
		return errors.Wrap(err, "failed to remove existing raft data")
	}

	// Re-initialize the gateway. This will create a new raft factory an
	// dqlite driver instance, which will be exposed over gRPC by the
	// gateway handlers.
	err = gateway.init()
	if err != nil {
		return errors.Wrap(err, "failed to re-initialize gRPC SQL gateway")
	}

	logger.Info(
		"Joining dqlite raft cluster",
		log15.Ctx{"id": id, "address": address, "target": target})
	changer := gateway.raft.MembershipChanger()
	err = changer.Join(raft.ServerID(id), raft.ServerAddress(target), 5*time.Second)
	if err != nil {
		return err
	}

	// Unlock regular access to our cluster database, and make sure our
	// gateway still works correctly.
	err = state.Cluster.ExitExclusive(func(tx *db.ClusterTx) error {
		_, err := tx.Nodes()
		return err
	})
	if err != nil {
		return errors.Wrap(err, "cluster database initialization failed")
	}
	return nil
}

// Promote makes a LXD node which is not a database node, become part of the
// raft cluster.

Promote makes a LXD node which is not a database node become part of the raft cluster .


func Purge(cluster *db.Cluster, name string) error {
	logger.Debugf("Remove node %s from the database", name)

	return cluster.Transaction(func(tx *db.ClusterTx) error {
		// Get the node (if it doesn't exists an error is returned).
		node, err := tx.NodeByName(name)
		if err != nil {
			return errors.Wrapf(err, "failed to get node %s", name)
		}

		err = tx.NodeClear(node.ID)
		if err != nil {
			return errors.Wrapf(err, "failed to clear node %s", name)
		}

		err = tx.NodeRemove(node.ID)
		if err != nil {
			return errors.Wrapf(err, "failed to remove node %s", name)
		}
		return nil
	})
}

// Purge removes a node entirely from the cluster database.

Purge removes a node entirely from the cluster database .


func List(state *state.State) ([]api.ClusterMember, error) {
	addresses := []string{} // Addresses of database nodes
	err := state.Node.Transaction(func(tx *db.NodeTx) error {
		nodes, err := tx.RaftNodes()
		if err != nil {
			return errors.Wrap(err, "failed to fetch current raft nodes")
		}
		for _, node := range nodes {
			addresses = append(addresses, node.Address)
		}
		return nil
	})
	if err != nil {
		return nil, err
	}

	var nodes []db.NodeInfo
	var offlineThreshold time.Duration

	err = state.Cluster.Transaction(func(tx *db.ClusterTx) error {
		nodes, err = tx.Nodes()
		if err != nil {
			return err
		}
		offlineThreshold, err = tx.NodeOfflineThreshold()
		if err != nil {
			return err
		}

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

	result := make([]api.ClusterMember, len(nodes))
	now := time.Now()
	version := nodes[0].Version()
	for i, node := range nodes {
		result[i].ServerName = node.Name
		result[i].URL = fmt.Sprintf("https://%s", node.Address)
		result[i].Database = shared.StringInSlice(node.Address, addresses)
		if node.IsOffline(offlineThreshold) {
			result[i].Status = "Offline"
			result[i].Message = fmt.Sprintf(
				"no heartbeat since %s", now.Sub(node.Heartbeat))
		} else {
			result[i].Status = "Online"
			result[i].Message = "fully operational"
		}

		n, err := util.CompareVersions(version, node.Version())
		if err != nil {
			result[i].Status = "Broken"
			result[i].Message = "inconsistent version"
			continue
		}

		if n == 1 {
			// This node's version is lower, which means the
			// version that the previous node in the loop has been
			// upgraded.
			version = node.Version()
		}
	}

	// Update the state of online nodes that have been upgraded and whose
	// schema is more recent than the rest of the nodes.
	for i, node := range nodes {
		if result[i].Status != "Online" {
			continue
		}
		n, err := util.CompareVersions(version, node.Version())
		if err != nil {
			continue
		}
		if n == 2 {
			result[i].Status = "Blocked"
			result[i].Message = "waiting for other nodes to be upgraded"
		}
	}

	return result, nil
}


func Count(state *state.State) (int, error) {
	var count int
	err := state.Cluster.Transaction(func(tx *db.ClusterTx) error {
		var err error
		count, err = tx.NodesCount()
		return err
	})
	return count, err
}

func Count ( state * state . State ) ( int , error ) { var count int err := state . Cluster . Transaction ( func ( tx * db . ClusterTx ) error { var err error count , err = tx . NodesCount ( ) return err } ) return count , err }

// Count is a convenience for checking the current number of nodes in the
// cluster.

Count is a convenience for checking the current number of nodes in the cluster .


func Enabled(node *db.Node) (bool, error) {
	enabled := false
	err := node.Transaction(func(tx *db.NodeTx) error {
		addresses, err := tx.RaftNodeAddresses()
		if err != nil {
			return err
		}
		enabled = len(addresses) > 0
		return nil
	})
	return enabled, err
}

func Enabled ( node * db . Node ) ( bool , error ) { enabled := false err := node . Transaction ( func ( tx * db . NodeTx ) error { addresses , err := tx . RaftNodeAddresses ( ) if err != nil { return err } enabled = len ( addresses ) > 0 return nil } ) return enabled , err }

// Enabled is a convenience that returns true if clustering is enabled on this
// node.

Enabled is a convenience that returns true if clustering is enabled on this node .


func membershipCheckNodeStateForBootstrapOrJoin(tx *db.NodeTx, address string) error {
	nodes, err := tx.RaftNodes()
	if err != nil {
		return errors.Wrap(err, "failed to fetch current raft nodes")
	}

	hasClusterAddress := address != ""
	hasRaftNodes := len(nodes) > 0

	// Sanity check that we're not in an inconsistent situation, where no
	// cluster address is set, but still there are entries in the
	// raft_nodes table.
	if !hasClusterAddress && hasRaftNodes {
		return fmt.Errorf("inconsistent state: found leftover entries in raft_nodes")
	}

	if !hasClusterAddress {
		return fmt.Errorf("no cluster.https_address config is set on this node")
	}
	if hasRaftNodes {
		return fmt.Errorf("the node is already part of a cluster")
	}

	return nil
}

// Check that node-related preconditions are met for bootstrapping or joining a
// cluster.

Check that node - related preconditions are met for bootstrapping or joining a cluster .


func membershipCheckClusterStateForBootstrapOrJoin(tx *db.ClusterTx) error {
	nodes, err := tx.Nodes()
	if err != nil {
		return errors.Wrap(err, "failed to fetch current cluster nodes")
	}
	if len(nodes) != 1 {
		return fmt.Errorf("inconsistent state: found leftover entries in nodes")
	}
	return nil
}

// Check that cluster-related preconditions are met for bootstrapping or
// joining a cluster.

Check that cluster - related preconditions are met for bootstrapping or joining a cluster .


func membershipCheckClusterStateForAccept(tx *db.ClusterTx, name string, address string, schema int, api int) error {
	nodes, err := tx.Nodes()
	if err != nil {
		return errors.Wrap(err, "failed to fetch current cluster nodes")
	}
	if len(nodes) == 1 && nodes[0].Address == "0.0.0.0" {
		return fmt.Errorf("clustering not enabled")
	}

	for _, node := range nodes {
		if node.Name == name {
			return fmt.Errorf("cluster already has node with name %s", name)
		}
		if node.Address == address {
			return fmt.Errorf("cluster already has node with address %s", address)
		}
		if node.Schema != schema {
			return fmt.Errorf("schema version mismatch: cluster has %d", node.Schema)
		}
		if node.APIExtensions != api {
			return fmt.Errorf("API version mismatch: cluster has %d", node.APIExtensions)
		}
	}

	return nil
}

func membershipCheckClusterStateForAccept ( tx * db . ClusterTx , name string , address string , schema int , api int ) error { nodes , err := tx . Nodes ( ) if err != nil { return errors . Wrap ( err , " " ) } if len ( nodes ) == 1 && nodes [ 0 ] . Address == " " { return fmt . Errorf ( " " ) } for _ , node := range nodes { if node . Name == name { return fmt . Errorf ( " " , name ) } if node . Address == address { return fmt . Errorf ( " " , address ) } if node . Schema != schema { return fmt . Errorf ( " " , node . Schema ) } if node . APIExtensions != api { return fmt . Errorf ( " " , node . APIExtensions ) } } return nil }

// Check that cluster-related preconditions are met for accepting a new node.

Check that cluster - related preconditions are met for accepting a new node .


func membershipCheckClusterStateForLeave(tx *db.ClusterTx, nodeID int64) error {
	// Check that it has no containers or images.
	message, err := tx.NodeIsEmpty(nodeID)
	if err != nil {
		return err
	}
	if message != "" {
		return fmt.Errorf(message)
	}

	// Check that it's not the last node.
	nodes, err := tx.Nodes()
	if err != nil {
		return err
	}
	if len(nodes) == 1 {
		return fmt.Errorf("node is the only node in the cluster")
	}
	return nil
}

// Check that cluster-related preconditions are met for leaving a cluster.

Check that cluster - related preconditions are met for leaving a cluster .


func membershipCheckNoLeftoverClusterCert(dir string) error {
	// Sanity check that there's no leftover cluster certificate
	for _, basename := range []string{"cluster.crt", "cluster.key", "cluster.ca"} {
		if shared.PathExists(filepath.Join(dir, basename)) {
			return fmt.Errorf("inconsistent state: found leftover cluster certificate")
		}
	}
	return nil
}

// Check that there is no left-over cluster certificate in the LXD var dir of
// this node.

Check that there is no left - over cluster certificate in the LXD var dir of this node .


func ConfigLoad(tx *db.NodeTx) (*Config, error) {
	// Load current raw values from the database, any error is fatal.
	values, err := tx.Config()
	if err != nil {
		return nil, fmt.Errorf("cannot fetch node config from database: %v", err)
	}

	m, err := config.SafeLoad(ConfigSchema, values)
	if err != nil {
		return nil, fmt.Errorf("failed to load node config: %v", err)
	}

	return &Config{tx: tx, m: m}, nil
}

// ConfigLoad loads a new Config object with the current node-local configuration
// values fetched from the database. An optional list of config value triggers
// can be passed, each config key must have at most one trigger.

ConfigLoad loads a new Config object with the current node - local configuration values fetched from the database . An optional list of config value triggers can be passed each config key must have at most one trigger .


func (c *Config) Replace(values map[string]interface{}) (map[string]string, error) {
	return c.update(values)
}

func ( c * Config ) Replace ( values map [ string ] interface { } ) ( map [ string ] string , error ) { return c . update ( values ) }

// Replace the current configuration with the given values.

Replace the current configuration with the given values .


func (c *Config) Patch(patch map[string]interface{}) (map[string]string, error) {
	values := c.Dump() // Use current values as defaults
	for name, value := range patch {
		values[name] = value
	}

	return c.update(values)
}

func
(
c
*
Config
)
Patch
(
patch
map
[
string
]
interface
{
}
)
(
map
[
string
]
string
,
error
)
{
values
:=
c
.
Dump
(
)
// Use current values as defaults
for
name
,
value
:=
range
patch
{
values
[
name
]
=
value
}
return
c
.
update
(
values
)
}

// Patch changes only the configuration keys in the given map.

Patch changes only the configuration keys in the given map .


func HTTPSAddress(node *db.Node) (string, error) {
	var config *Config
	err := node.Transaction(func(tx *db.NodeTx) error {
		var err error
		config, err = ConfigLoad(tx)
		return err
	})
	if err != nil {
		return "", err
	}

	return config.HTTPSAddress(), nil
}

func HTTPSAddress ( node * db . Node ) ( string , error ) { var config * Config err := node . Transaction ( func ( tx * db . NodeTx ) error { var err error config , err = ConfigLoad ( tx ) return err } ) if err != nil { return " " , err } return config . HTTPSAddress ( ) , nil }

// HTTPSAddress is a convenience for loading the node configuration and
// returning the value of core.https_address.

HTTPSAddress is a convenience for loading the node configuration and returning the value of core . https_address .


func (c *Cluster) CertificatesGet() (certs []*CertInfo, err error) {
	err = c.Transaction(func(tx *ClusterTx) error {
		rows, err := tx.tx.Query(
			"SELECT id, fingerprint, type, name, certificate FROM certificates",
		)
		if err != nil {
			return err
		}

		defer rows.Close()

		for rows.Next() {
			cert := new(CertInfo)
			rows.Scan(
				&cert.ID,
				&cert.Fingerprint,
				&cert.Type,
				&cert.Name,
				&cert.Certificate,
			)
			certs = append(certs, cert)
		}

		return rows.Err()
	})
	if err != nil {
		return certs, err
	}

	return certs, nil
}

func ( c * Cluster ) CertificatesGet ( ) ( certs [ ] * CertInfo , err error ) { err = c . Transaction ( func ( tx * ClusterTx ) error { rows , err := tx . tx . Query ( " " , ) if err != nil { return err } defer rows . Close ( ) for rows . Next ( ) { cert := new ( CertInfo ) rows . Scan ( & cert . ID , & cert . Fingerprint , & cert . Type , & cert . Name , & cert . Certificate , ) certs = append ( certs , cert ) } return rows . Err ( ) } ) if err != nil { return certs , err } return certs , nil }

// CertificatesGet returns all certificates from the DB as CertBaseInfo objects.

CertificatesGet returns all certificates from the DB as CertBaseInfo objects .


func (c *Cluster) CertificateGet(fingerprint string) (cert *CertInfo, err error) {
	cert = new(CertInfo)

	inargs := []interface{}{fingerprint + "%"}
	outfmt := []interface{}{
		&cert.ID,
		&cert.Fingerprint,
		&cert.Type,
		&cert.Name,
		&cert.Certificate,
	}

	query := `
		SELECT
			id, fingerprint, type, name, certificate
		FROM
			certificates
		WHERE fingerprint LIKE ?`

	if err = dbQueryRowScan(c.db, query, inargs, outfmt); err != nil {
		if err == sql.ErrNoRows {
			return nil, ErrNoSuchObject
		}

		return nil, err
	}

	return cert, err
}

// CertificateGet gets an CertBaseInfo object from the database.
// The argument fingerprint will be queried with a LIKE query, means you can
// pass a shortform and will get the full fingerprint.
// There can never be more than one image with a given fingerprint, as it is
// enforced by a UNIQUE constraint in the schema.

CertificateGet gets an CertBaseInfo object from the database . The argument fingerprint will be queried with a LIKE query means you can pass a shortform and will get the full fingerprint . There can never be more than one image with a given fingerprint as it is enforced by a UNIQUE constraint in the schema .


func (c *Cluster) CertSave(cert *CertInfo) error {
	err := c.Transaction(func(tx *ClusterTx) error {
		stmt, err := tx.tx.Prepare(`
			INSERT INTO certificates (
				fingerprint,
				type,
				name,
				certificate
			) VALUES (?, ?, ?, ?)`,
		)
		if err != nil {
			return err
		}
		defer stmt.Close()
		_, err = stmt.Exec(
			cert.Fingerprint,
			cert.Type,
			cert.Name,
			cert.Certificate,
		)
		if err != nil {
			return err
		}
		return nil
	})
	return err
}

// CertSave stores a CertBaseInfo object in the db,
// it will ignore the ID field from the CertInfo.

CertSave stores a CertBaseInfo object in the db it will ignore the ID field from the CertInfo .


func (c *Cluster) CertDelete(fingerprint string) error {
	err := exec(c.db, "DELETE FROM certificates WHERE fingerprint=?", fingerprint)
	if err != nil {
		return err
	}

	return nil
}

func ( c * Cluster ) CertDelete ( fingerprint string ) error { err := exec ( c . db , " " , fingerprint ) if err != nil { return err } return nil }

// CertDelete deletes a certificate from the db.

CertDelete deletes a certificate from the db .


func (c *Cluster) CertUpdate(fingerprint string, certName string, certType int) error {
	err := c.Transaction(func(tx *ClusterTx) error {
		_, err := tx.tx.Exec("UPDATE certificates SET name=?, type=? WHERE fingerprint=?", certName, certType, fingerprint)
		return err
	})
	return err
}

func ( c * Cluster ) CertUpdate ( fingerprint string , certName string , certType int ) error { err := c . Transaction ( func ( tx * ClusterTx ) error { _ , err := tx . tx . Exec ( " " , certName , certType , fingerprint ) return err } ) return err }

// CertUpdate updates the certificate with the given fingerprint.

CertUpdate updates the certificate with the given fingerprint .


func createDevLxdlListener(dir string) (net.Listener, error) {
	path := filepath.Join(dir, "devlxd", "sock")

	// If this socket exists, that means a previous LXD instance died and
	// didn't clean up. We assume that such LXD instance is actually dead
	// if we get this far, since localCreateListener() tries to connect to
	// the actual lxd socket to make sure that it is actually dead. So, it
	// is safe to remove it here without any checks.
	//
	// Also, it would be nice to SO_REUSEADDR here so we don't have to
	// delete the socket, but we can't:
	//   http://stackoverflow.com/questions/15716302/so-reuseaddr-and-af-unix
	//
	// Note that this will force clients to reconnect when LXD is restarted.
	err := socketUnixRemoveStale(path)
	if err != nil {
		return nil, err
	}

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

	err = socketUnixSetPermissions(path, 0666)
	if err != nil {
		listener.Close()
		return nil, err
	}

	return listener, nil
}

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

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


func (i *raftInstance) Servers() ([]raft.Server, error) {
	if i.raft.State() != raft.Leader {
		return nil, raft.ErrNotLeader
	}
	future := i.raft.GetConfiguration()
	err := future.Error()
	if err != nil {
		return nil, err
	}
	configuration := future.Configuration()
	return configuration.Servers, nil
}

func ( i * raftInstance ) Servers ( ) ( [ ] raft . Server , error ) { if i . raft . State ( ) != raft . Leader { return nil , raft . ErrNotLeader } future := i . raft . GetConfiguration ( ) err := future . Error ( ) if err != nil { return nil , err } configuration := future . Configuration ( ) return configuration . Servers , nil }

// Servers returns the servers that are currently part of the cluster.
//
// If this raft instance is not the leader, an error is returned.

Servers returns the servers that are currently part of the cluster . If this raft instance is not the leader an error is returned .


func (i *raftInstance) Shutdown() error {
	logger.Debug("Stop raft instance")

	// Invoke raft APIs asynchronously to allow for a timeout.
	timeout := 10 * time.Second

	errCh := make(chan error)
	timer := time.After(timeout)
	go func() {
		errCh <- i.raft.Shutdown().Error()
	}()
	select {
	case err := <-errCh:
		if err != nil {
			return errors.Wrap(err, "failed to shutdown raft")
		}
	case <-timer:
		logger.Debug("Timeout waiting for raft to shutdown")
		return fmt.Errorf("raft did not shutdown within %s", timeout)

	}
	err := i.logs.Close()
	if err != nil {
		return errors.Wrap(err, "failed to close boltdb logs store")
	}
	return nil
}

// Shutdown raft and any raft-related resource we have instantiated.

Shutdown raft and any raft - related resource we have instantiated .


func raftNetworkTransport(
	db *db.Node,
	address string,
	logger *log.Logger,
	timeout time.Duration,
	dial rafthttp.Dial) (raft.Transport, *rafthttp.Handler, *rafthttp.Layer, error) {
	handler := rafthttp.NewHandlerWithLogger(logger)
	addr, err := net.ResolveTCPAddr("tcp", address)
	if err != nil {
		return nil, nil, nil, errors.Wrap(err, "invalid node address")
	}

	layer := rafthttp.NewLayer(raftEndpoint, addr, handler, dial)
	config := &raft.NetworkTransportConfig{
		Logger:                logger,
		Stream:                layer,
		MaxPool:               2,
		Timeout:               timeout,
		ServerAddressProvider: &raftAddressProvider{db: db},
	}
	transport := raft.NewNetworkTransportWithConfig(config)

	return transport, handler, layer, nil
}

func raftNetworkTransport ( db * db . Node , address string , logger * log . Logger , timeout time . Duration , dial rafthttp . Dial ) ( raft . Transport , * rafthttp . Handler , * rafthttp . Layer , error ) { handler := rafthttp . NewHandlerWithLogger ( logger ) addr , err := net . ResolveTCPAddr ( " " , address ) if err != nil { return nil , nil , nil , errors . Wrap ( err , " " ) } layer := rafthttp . NewLayer ( raftEndpoint , addr , handler , dial ) config := & raft . NetworkTransportConfig { Logger : logger , Stream : layer , MaxPool : 2 , Timeout : timeout , ServerAddressProvider : & raftAddressProvider { db : db } , } transport := raft . NewNetworkTransportWithConfig ( config ) return transport , handler , layer , nil }

// Create a network raft transport that will handle connections using a
// rafthttp.Handler.

Create a network raft transport that will handle connections using a rafthttp . Handler .


func raftConfig(latency float64) *raft.Config {
	config := raft.DefaultConfig()
	scale := func(duration *time.Duration) {
		*duration = time.Duration((math.Ceil(float64(*duration) * latency)))
	}
	durations := []*time.Duration{
		&config.HeartbeatTimeout,
		&config.ElectionTimeout,
		&config.CommitTimeout,
		&config.LeaderLeaseTimeout,
	}
	for _, duration := range durations {
		scale(duration)
	}

	config.SnapshotThreshold = 1024
	config.TrailingLogs = 512

	return config
}

func raftConfig ( latency float64 ) * raft . Config { config := raft . DefaultConfig ( ) scale := func ( duration * time . Duration ) { * duration = time . Duration ( ( math . Ceil ( float64 ( * duration ) * latency ) ) ) } durations := [ ] * time . Duration { & config . HeartbeatTimeout , & config . ElectionTimeout , & config . CommitTimeout , & config . LeaderLeaseTimeout , } for _ , duration := range durations { scale ( duration ) } config . SnapshotThreshold = 1024 config . TrailingLogs = 512 return config }

// Create a base raft configuration tweaked for a network with the given latency measure.

Create a base raft configuration tweaked for a network with the given latency measure .


func raftMaybeBootstrap(
	conf *raft.Config,
	logs *raftboltdb.BoltStore,
	snaps raft.SnapshotStore,
	trans raft.Transport) error {
	// First check if we were already bootstrapped.
	hasExistingState, err := raft.HasExistingState(logs, logs, snaps)
	if err != nil {
		return errors.Wrap(err, "failed to check if raft has existing state")
	}
	if hasExistingState {
		return nil
	}
	server := raft.Server{
		ID:      conf.LocalID,
		Address: trans.LocalAddr(),
	}
	configuration := raft.Configuration{
		Servers: []raft.Server{server},
	}
	return raft.BootstrapCluster(conf, logs, logs, snaps, trans, configuration)
}

// Helper to bootstrap the raft cluster if needed.

Helper to bootstrap the raft cluster if needed .


func CPUResource() (*api.ResourcesCPU, error) {
	c := api.ResourcesCPU{}

	threads, err := getThreads()
	if err != nil {
		return nil, err
	}

	var cur *api.ResourcesCPUSocket
	c.Total = uint64(len(threads))

	for _, v := range threads {
		if uint64(len(c.Sockets)) <= v.socketID {
			c.Sockets = append(c.Sockets, api.ResourcesCPUSocket{})
			cur = &c.Sockets[v.socketID]

			// Count the number of cores on the socket
			// Note that we can't assume sequential core IDs
			socketCores := map[uint64]bool{}
			for _, thread := range threads {
				if thread.socketID != v.socketID {
					continue
				}

				socketCores[thread.coreID] = true
			}
			cur.Cores = uint64(len(socketCores))
		} else {
			cur = &c.Sockets[v.socketID]
		}

		cur.Socket = v.socketID
		cur.NUMANode = v.numaNode
		cur.Threads++
		cur.Name = v.name
		cur.Vendor = v.vendor
		cur.Frequency = v.frequency
		cur.FrequencyTurbo = v.frequencyTurbo
	}

	return &c, nil
}

// CPUResource returns the system CPU information


func MemoryResource() (*api.ResourcesMemory, error) {
	var buffers uint64
	var cached uint64
	var free uint64
	var total uint64

	f, err := os.Open("/proc/meminfo")
	if err != nil {
		return nil, err
	}
	defer f.Close()

	cleanLine := func(l string) (string, error) {
		l = strings.TrimSpace(l)
		idx := strings.LastIndex(l, "kB")
		if idx < 0 {
			return "", fmt.Errorf(`Failed to detect "kB" suffix`)
		}

		return strings.TrimSpace(l[:idx]), nil
	}

	mem := api.ResourcesMemory{}
	scanner := bufio.NewScanner(f)
	found := 0
	for scanner.Scan() {
		var err error
		line := scanner.Text()

		if strings.HasPrefix(line, "MemTotal:") {
			line, err = cleanLine(line[len("MemTotal:"):])
			if err != nil {
				return nil, err
			}

			total, err = strconv.ParseUint(line, 10, 64)
			if err != nil {
				return nil, err
			}

			found++
		} else if strings.HasPrefix(line, "MemFree:") {
			line, err = cleanLine(line[len("MemFree:"):])
			if err != nil {
				return nil, err
			}

			free, err = strconv.ParseUint(line, 10, 64)
			if err != nil {
				return nil, err
			}

			found++
		} else if strings.HasPrefix(line, "Cached:") {
			line, err = cleanLine(line[len("Cached:"):])
			if err != nil {
				return nil, err
			}

			cached, err = strconv.ParseUint(line, 10, 64)
			if err != nil {
				return nil, err
			}

			found++
		} else if strings.HasPrefix(line, "Buffers:") {
			line, err = cleanLine(line[len("Buffers:"):])
			if err != nil {
				return nil, err
			}

			buffers, err = strconv.ParseUint(line, 10, 64)
			if err != nil {
				return nil, err
			}

			found++
		}

		if found == 4 {
			break
		}
	}

	mem.Total = total * 1024
	mem.Used = (total - free - cached - buffers) * 1024

	return &mem, err
}

func
MemoryResource
(
)
(
*
api
.
ResourcesMemory
,
error
)
{
var
buffers
uint64
var
cached
uint64
var
free
uint64
var
total
uint64
f
,
err
:=
os
.
Open
(
"
"
)
if
err
!=
{
return
,
err
}
defer
f
.
Close
(
)
cleanLine
:=
func
(
l
string
)
(
string
,
error
)
{
l
=
strings
.
TrimSpace
(
l
)
idx
:=
strings
.
LastIndex
(
l
,
"
"
)
if
idx
<
0
{
return
"
"
,
fmt
.
Errorf
(
`Failed to detect "kB" suffix`
)
}
return
strings
.
TrimSpace
(
l
[
:
idx
]
)
,
}
mem
:=
api
.
ResourcesMemory
{
}
scanner
:=
bufio
.
NewScanner
(
f
)
found
:=
0
for
scanner
.
Scan
(
)
{
var
err
error
line
:=
scanner
.
Text
(
)
if
strings
.
HasPrefix
(
line
,
"
"
)
{
line
,
err
=
cleanLine
(
line
[
len
(
"
"
)
:
]
)
if
err
!=
{
return
,
err
}
total
,
err
=
strconv
.
ParseUint
(
line
,
10
,
64
)
if
err
!=
{
return
,
err
}
found
++
}
else
if
strings
.
HasPrefix
(
line
,
"
"
)
{
line
,
err
=
cleanLine
(
line
[
len
(
"
"
)
:
]
)
if
err
!=
{
return
,
err
}
free
,
err
=
strconv
.
ParseUint
(
line
,
10
,
64
)
if
err
!=
{
return
,
err
}
found
++
}
else
if
strings
.
HasPrefix
(
line
,
"
"
)
{
line
,
err
=
cleanLine
(
line
[
len
(
"
"
)
:
]
)
if
err
!=
{
return
,
err
}
cached
,
err
=
strconv
.
ParseUint
(
line
,
10
,
64
)
if
err
!=
{
return
,
err
}
found
++
}
else
if
strings
.
HasPrefix
(
line
,
"
"
)
{
line
,
err
=
cleanLine
(
line
[
len
(
"
"
)
:
]
)
if
err
!=
{
return
,
err
}
buffers
,
err
=
strconv
.
ParseUint
(
line
,
10
,
64
)
if
err
!=
{
return
,
err
}
found
++
}
if
found
==
4
{
break
}
}
mem
.
Total
=
total
*
1024
mem
.
Used
=
(
total
free
cached
buffers
)
*
1024
return
&
mem
,
err
}

// MemoryResource returns the system memory information


func (r *ProtocolLXD) GetOperationUUIDs() ([]string, error) {
	urls := []string{}

	// Fetch the raw value
	_, err := r.queryStruct("GET", "/operations", nil, "", &urls)
	if err != nil {
		return nil, err
	}

	// Parse it
	uuids := []string{}
	for _, url := range urls {
		fields := strings.Split(url, "/operations/")
		uuids = append(uuids, fields[len(fields)-1])
	}

	return uuids, nil
}

func
(
r
*
ProtocolLXD
)
GetOperationUUIDs
(
)
(
[
]
string
,
error
)
{
urls
:=
[
]
string
{
}
// Fetch the raw value
_
,
err
:=
r
.
queryStruct
(
"
"
,
"
"
,
,
"
"
,
&
urls
)
if
err
!=
{
return
,
err
}
// Parse it
uuids
:=
[
]
string
{
}
for
_
,
url
:=
range
urls
{
fields
:=
strings
.
Split
(
url
,
"
"
)
uuids
=
append
(
uuids
,
fields
[
len
(
fields
)
1
]
)
}
return
uuids
,
}

// GetOperationUUIDs returns a list of operation uuids


func (r *ProtocolLXD) GetOperations() ([]api.Operation, error) {
	apiOperations := map[string][]api.Operation{}

	// Fetch the raw value
	_, err := r.queryStruct("GET", "/operations?recursion=1", nil, "", &apiOperations)
	if err != nil {
		return nil, err
	}

	// Turn it into just a list of operations
	operations := []api.Operation{}
	for _, v := range apiOperations {
		for _, operation := range v {
			operations = append(operations, operation)
		}
	}

	return operations, nil
}

// GetOperations returns a list of Operation struct


func (r *ProtocolLXD) GetOperation(uuid string) (*api.Operation, string, error) {
	op := api.Operation{}

	// Fetch the raw value
	etag, err := r.queryStruct("GET", fmt.Sprintf("/operations/%s", url.QueryEscape(uuid)), nil, "", &op)
	if err != nil {
		return nil, "", err
	}

	return &op, etag, nil
}

func
(
r
*
ProtocolLXD
)
GetOperation
(
uuid
string
)
(
*
api
.
Operation
,
string
,
error
)
{
op
:=
api
.
Operation
{
}
// Fetch the raw value
etag
,
err
:=
r
.
queryStruct
(
"
"
,
fmt
.
Sprintf
(
"
"
,
url
.
QueryEscape
(
uuid
)
)
,
,
"
"
,
&
op
)
if
err
!=
{
return
,
"
"
,
err
}
return
&
op
,
etag
,
}

// GetOperation returns an Operation entry for the provided uuid


func (r *ProtocolLXD) GetOperationWebsocket(uuid string, secret string) (*websocket.Conn, error) {
	path := fmt.Sprintf("/operations/%s/websocket", url.QueryEscape(uuid))
	if secret != "" {
		path = fmt.Sprintf("%s?secret=%s", path, url.QueryEscape(secret))
	}

	return r.websocket(path)
}

func ( r * ProtocolLXD ) GetOperationWebsocket ( uuid string , secret string ) ( * websocket . Conn , error ) { path := fmt . Sprintf ( " " , url . QueryEscape ( uuid ) ) if secret != " " { path = fmt . Sprintf ( " " , path , url . QueryEscape ( secret ) ) } return r . websocket ( path ) }

// GetOperationWebsocket returns a websocket connection for the provided operation


func tryMount(src string, dst string, fs string, flags uintptr, options string) error {
	var err error

	for i := 0; i < 20; i++ {
		err = syscall.Mount(src, dst, fs, flags, options)
		if err == nil {
			break
		}

		time.Sleep(500 * time.Millisecond)
	}

	if err != nil {
		return err
	}

	return nil
}

func tryMount ( src string , dst string , fs string , flags uintptr , options string ) error { var err error for i := 0 ; i < 20 ; i ++ { err = syscall . Mount ( src , dst , fs , flags , options ) if err == nil { break } time . Sleep ( 500 * time . Millisecond ) } if err != nil { return err } return nil }

// Useful functions for unreliable backends


func lxdUsesPool(dbObj *db.Cluster, onDiskPoolName string, driver string, onDiskProperty string) (bool, string, error) {
	pools, err := dbObj.StoragePools()
	if err != nil && err != db.ErrNoSuchObject {
		return false, "", err
	}

	for _, pool := range pools {
		_, pl, err := dbObj.StoragePoolGet(pool)
		if err != nil {
			continue
		}

		if pl.Driver != driver {
			continue
		}

		if pl.Config[onDiskProperty] == onDiskPoolName {
			return true, pl.Name, nil
		}
	}

	return false, "", nil
}

func lxdUsesPool ( dbObj * db . Cluster , onDiskPoolName string , driver string , onDiskProperty string ) ( bool , string , error ) { pools , err := dbObj . StoragePools ( ) if err != nil && err != db . ErrNoSuchObject { return false , " " , err } for _ , pool := range pools { _ , pl , err := dbObj . StoragePoolGet ( pool ) if err != nil { continue } if pl . Driver != driver { continue } if pl . Config [ onDiskProperty ] == onDiskPoolName { return true , pl . Name , nil } } return false , " " , nil }

// Detect whether LXD already uses the given storage pool.

Detect whether LXD already uses the given storage pool .


func (c *ClusterTx) ProjectURIs(filter ProjectFilter) ([]string, error) {
	// Check which filter criteria are active.
	criteria := map[string]interface{}{}
	if filter.Name != "" {
		criteria["Name"] = filter.Name
	}

	// Pick the prepared statement and arguments to use based on active criteria.
	var stmt *sql.Stmt
	var args []interface{}

	if criteria["Name"] != nil {
		stmt = c.stmt(projectNamesByName)
		args = []interface{}{
			filter.Name,
		}
	} else {
		stmt = c.stmt(projectNames)
		args = []interface{}{}
	}

	code := cluster.EntityTypes["project"]
	formatter := cluster.EntityFormatURIs[code]

	return query.SelectURIs(stmt, formatter, args...)
}

// ProjectURIs returns all available project URIs.

ProjectURIs returns all available project URIs .


func (c *ClusterTx) ProjectList(filter ProjectFilter) ([]api.Project, error) {
	// Result slice.
	objects := make([]api.Project, 0)

	// Check which filter criteria are active.
	criteria := map[string]interface{}{}
	if filter.Name != "" {
		criteria["Name"] = filter.Name
	}

	// Pick the prepared statement and arguments to use based on active criteria.
	var stmt *sql.Stmt
	var args []interface{}

	if criteria["Name"] != nil {
		stmt = c.stmt(projectObjectsByName)
		args = []interface{}{
			filter.Name,
		}
	} else {
		stmt = c.stmt(projectObjects)
		args = []interface{}{}
	}

	// Dest function for scanning a row.
	dest := func(i int) []interface{} {
		objects = append(objects, api.Project{})
		return []interface{}{
			&objects[i].Description,
			&objects[i].Name,
		}
	}

	// Select.
	err := query.SelectObjects(stmt, dest, args...)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to fetch projects")
	}

	// Fill field Config.
	configObjects, err := c.ProjectConfigRef(filter)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to fetch field Config")
	}

	for i := range objects {
		value := configObjects[objects[i].Name]
		if value == nil {
			value = map[string]string{}
		}
		objects[i].Config = value
	}

	// Fill field UsedBy.
	usedByObjects, err := c.ProjectUsedByRef(filter)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to fetch field UsedBy")
	}

	for i := range objects {
		value := usedByObjects[objects[i].Name]
		if value == nil {
			value = []string{}
		}
		objects[i].UsedBy = value
	}

	return objects, nil
}

// ProjectList returns all available projects.

ProjectList returns all available projects .


func (c *ClusterTx) ProjectGet(name string) (*api.Project, error) {
	filter := ProjectFilter{}
	filter.Name = name

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

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

func ( c * ClusterTx ) ProjectGet ( name string ) ( * api . Project , error ) { filter := ProjectFilter { } filter . Name = name objects , err := c . ProjectList ( 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 ( " " ) } }

// ProjectGet returns the project with the given key.

ProjectGet returns the project with the given key .


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

	return true, nil
}

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

// ProjectExists checks if a project with the given key exists.

ProjectExists checks if a project with the given key exists .


func (c *ClusterTx) ProjectCreate(object api.ProjectsPost) (int64, error) {
	// Check if a project with the same key exists.
	exists, err := c.ProjectExists(object.Name)
	if err != nil {
		return -1, errors.Wrap(err, "Failed to check for duplicates")
	}
	if exists {
		return -1, fmt.Errorf("This project already exists")
	}

	args := make([]interface{}, 2)

	// Populate the statement arguments.
	args[0] = object.Description
	args[1] = object.Name

	// Prepared statement to use.
	stmt := c.stmt(projectCreate)

	// Execute the statement.
	result, err := stmt.Exec(args...)
	if err != nil {
		return -1, errors.Wrap(err, "Failed to create project")
	}

	id, err := result.LastInsertId()
	if err != nil {
		return -1, errors.Wrap(err, "Failed to fetch project ID")
	}

	// Insert config reference.
	stmt = c.stmt(projectCreateConfigRef)
	for key, value := range object.Config {
		_, err := stmt.Exec(id, key, value)
		if err != nil {
			return -1, errors.Wrap(err, "Insert config for project")
		}
	}

	return id, nil
}

// ProjectCreate adds a new project to the database.

ProjectCreate adds a new project to the database .


func (c *ClusterTx) ProjectUsedByRef(filter ProjectFilter) (map[string][]string, error) {
	// Result slice.
	objects := make([]struct {
		Name  string
		Value string
	}, 0)

	// Check which filter criteria are active.
	criteria := map[string]interface{}{}
	if filter.Name != "" {
		criteria["Name"] = filter.Name
	}

	// Pick the prepared statement and arguments to use based on active criteria.
	var stmt *sql.Stmt
	var args []interface{}

	if criteria["Name"] != nil {
		stmt = c.stmt(projectUsedByRefByName)
		args = []interface{}{
			filter.Name,
		}
	} else {
		stmt = c.stmt(projectUsedByRef)
		args = []interface{}{}
	}

	// Dest function for scanning a row.
	dest := func(i int) []interface{} {
		objects = append(objects, struct {
			Name  string
			Value string
		}{})
		return []interface{}{
			&objects[i].Name,
			&objects[i].Value,
		}
	}

	// Select.
	err := query.SelectObjects(stmt, dest, args...)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to fetch string ref for projects")
	}

	// Build index by primary name.
	index := map[string][]string{}

	for _, object := range objects {
		item, ok := index[object.Name]
		if !ok {
			item = []string{}
		}

		index[object.Name] = append(item, object.Value)
	}

	return index, nil
}

// ProjectUsedByRef returns entities used by projects.

ProjectUsedByRef returns entities used by projects .


func (c *ClusterTx) ProjectRename(name string, to string) error {
	stmt := c.stmt(projectRename)
	result, err := stmt.Exec(to, name)
	if err != nil {
		return errors.Wrap(err, "Rename project")
	}

	n, err := result.RowsAffected()
	if err != nil {
		return errors.Wrap(err, "Fetch affected rows")
	}
	if n != 1 {
		return fmt.Errorf("Query affected %d rows instead of 1", n)
	}
	return nil
}

func ( c * ClusterTx ) ProjectRename ( name string , to string ) error { stmt := c . stmt ( projectRename ) result , err := stmt . Exec ( to , name ) if err != nil { return errors . Wrap ( err , " " ) } n , err := result . RowsAffected ( ) if err != nil { return errors . Wrap ( err , " " ) } if n != 1 { return fmt . Errorf ( " " , n ) } return nil }

// ProjectRename renames the project matching the given key parameters.

ProjectRename renames the project matching the given key parameters .


func (c *ClusterTx) ProjectDelete(name string) error {
	stmt := c.stmt(projectDelete)
	result, err := stmt.Exec(name)
	if err != nil {
		return errors.Wrap(err, "Delete project")
	}

	n, err := result.RowsAffected()
	if err != nil {
		return errors.Wrap(err, "Fetch affected rows")
	}
	if n != 1 {
		return fmt.Errorf("Query deleted %d rows instead of 1", n)
	}

	return nil
}

func ( c * ClusterTx ) ProjectDelete ( name string ) error { stmt := c . stmt ( projectDelete ) result , err := stmt . Exec ( name ) if err != nil { return errors . Wrap ( err , " " ) } n , err := result . RowsAffected ( ) if err != nil { return errors . Wrap ( err , " " ) } if n != 1 { return fmt . Errorf ( " " , n ) } return nil }

// ProjectDelete deletes the project matching the given key parameters.

ProjectDelete deletes the project matching the given key parameters .


func PasswordCheck(secret string, password string) error {
	// No password set
	if secret == "" {
		return fmt.Errorf("No password is set")
	}

	// Compare the password
	buff, err := hex.DecodeString(secret)
	if err != nil {
		return err
	}

	salt := buff[0:32]
	hash, err := scrypt.Key([]byte(password), salt, 1<<14, 8, 1, 64)
	if err != nil {
		return err
	}

	if !bytes.Equal(hash, buff[32:]) {
		return fmt.Errorf("Bad password provided")
	}

	return nil
}

func
PasswordCheck
(
secret
string
,
password
string
)
error
{
// No password set
if
secret
==
"
"
{
return
fmt
.
Errorf
(
"
"
)
}
// Compare the password
buff
,
err
:=
hex
.
DecodeString
(
secret
)
if
err
!=
{
return
err
}
salt
:=
buff
[
0
:
32
]
hash
,
err
:=
scrypt
.
Key
(
[
]
byte
(
password
)
,
salt
,
1
<<
14
,
8
,
1
,
64
)
if
err
!=
{
return
err
}
if
!
bytes
.
Equal
(
hash
,
buff
[
32
:
]
)
{
return
fmt
.
Errorf
(
"
"
)
}
return
}

// PasswordCheck validates the provided password against the encoded secret


func LoadCert(dir string) (*shared.CertInfo, error) {
	prefix := "server"
	if shared.PathExists(filepath.Join(dir, "cluster.crt")) {
		prefix = "cluster"
	}
	cert, err := shared.KeyPairAndCA(dir, prefix, shared.CertServer)
	if err != nil {
		return nil, errors.Wrap(err, "failed to load TLS certificate")
	}
	return cert, nil
}

func LoadCert ( dir string ) ( * shared . CertInfo , error ) { prefix := " " if shared . PathExists ( filepath . Join ( dir , " " ) ) { prefix = " " } cert , err := shared . KeyPairAndCA ( dir , prefix , shared . CertServer ) if err != nil { return nil , errors . Wrap ( err , " " ) } return cert , nil }

// LoadCert reads the LXD server certificate from the given var dir.
//
// If a cluster certificate is found it will be loaded instead.

LoadCert reads the LXD server certificate from the given var dir . If a cluster certificate is found it will be loaded instead .


func WriteCert(dir, prefix string, cert, key, ca []byte) error {
	err := ioutil.WriteFile(filepath.Join(dir, prefix+".crt"), cert, 0644)
	if err != nil {
		return err
	}

	err = ioutil.WriteFile(filepath.Join(dir, prefix+".key"), key, 0600)
	if err != nil {
		return err
	}

	if ca != nil {
		err = ioutil.WriteFile(filepath.Join(dir, prefix+".ca"), ca, 0644)
		if err != nil {
			return err
		}
	}

	return nil
}

func WriteCert ( dir , prefix string , cert , key , ca [ ] byte ) error { err := ioutil . WriteFile ( filepath . Join ( dir , prefix + " " ) , cert , 0644 ) if err != nil { return err } err = ioutil . WriteFile ( filepath . Join ( dir , prefix + " " ) , key , 0600 ) if err != nil { return err } if ca != nil { err = ioutil . WriteFile ( filepath . Join ( dir , prefix + " " ) , ca , 0644 ) if err != nil { return err } } return nil }

// WriteCert writes the given material to the appropriate certificate files in
// the given LXD var directory.

WriteCert writes the given material to the appropriate certificate files in the given LXD var directory .


func NewDaemon(config *DaemonConfig, os *sys.OS) *Daemon {
	return &Daemon{
		config:       config,
		os:           os,
		setupChan:    make(chan struct{}),
		readyChan:    make(chan struct{}),
		shutdownChan: make(chan struct{}),
	}
}

func NewDaemon ( config * DaemonConfig , os * sys . OS ) * Daemon { return & Daemon { config : config , os : os , setupChan : make ( chan struct { } ) , readyChan : make ( chan struct { } ) , shutdownChan : make ( chan struct { } ) , } }

// NewDaemon returns a new Daemon object with the given configuration.

NewDaemon returns a new Daemon object with the given configuration .


func DefaultDaemon() *Daemon {
	config := DefaultDaemonConfig()
	os := sys.DefaultOS()
	return NewDaemon(config, os)
}

func DefaultDaemon ( ) * Daemon { config := DefaultDaemonConfig ( ) os := sys . DefaultOS ( ) return NewDaemon ( config , os ) }

// DefaultDaemon returns a new, un-initialized Daemon object with default values.

DefaultDaemon returns a new un - initialized Daemon object with default values .


func AllowProjectPermission(feature string, permission string) func(d *Daemon, r *http.Request) Response {
	return func(d *Daemon, r *http.Request) Response {
		// Shortcut for speed
		if d.userIsAdmin(r) {
			return EmptySyncResponse
		}

		// Get the project
		project := projectParam(r)

		// Validate whether the user has the needed permission
		if !d.userHasPermission(r, project, permission) {
			return Forbidden(nil)
		}

		return EmptySyncResponse
	}
}

// AllowProjectPermission is a wrapper to check access against the project, its features and RBAC permission

AllowProjectPermission is a wrapper to check access against the project its features and RBAC permission


func (d *Daemon) checkTrustedClient(r *http.Request) error {
	trusted, _, _, err := d.Authenticate(r)
	if !trusted || err != nil {
		if err != nil {
			return err
		}

		return fmt.Errorf("Not authorized")
	}

	return nil
}

func ( d * Daemon ) checkTrustedClient ( r * http . Request ) error { trusted , _ , _ , err := d . Authenticate ( r ) if ! trusted || err != nil { if err != nil { return err } return fmt . Errorf ( " " ) } return nil }

// Convenience function around Authenticate


func (d *Daemon) Authenticate(r *http.Request) (bool, string, string, error) {
	// Allow internal cluster traffic
	if r.TLS != nil {
		cert, _ := x509.ParseCertificate(d.endpoints.NetworkCert().KeyPair().Certificate[0])
		clusterCerts := map[string]x509.Certificate{"0": *cert}
		for i := range r.TLS.PeerCertificates {
			trusted, _ := util.CheckTrustState(*r.TLS.PeerCertificates[i], clusterCerts)
			if trusted {
				return true, "", "cluster", nil
			}
		}
	}

	// Local unix socket queries
	if r.RemoteAddr == "@" {
		return true, "", "unix", nil
	}

	// Devlxd unix socket credentials on main API
	if r.RemoteAddr == "@devlxd" {
		return false, "", "", fmt.Errorf("Main API query can't come from /dev/lxd socket")
	}

	// Cluster notification with wrong certificate
	if isClusterNotification(r) {
		return false, "", "", fmt.Errorf("Cluster notification isn't using cluster certificate")
	}

	// Bad query, no TLS found
	if r.TLS == nil {
		return false, "", "", fmt.Errorf("Bad/missing TLS on network query")
	}

	if d.externalAuth != nil && r.Header.Get(httpbakery.BakeryProtocolHeader) != "" {
		// Validate external authentication
		ctx := httpbakery.ContextWithRequest(context.TODO(), r)
		authChecker := d.externalAuth.bakery.Checker.Auth(httpbakery.RequestMacaroons(r)...)

		ops := []bakery.Op{{
			Entity: r.URL.Path,
			Action: r.Method,
		}}

		info, err := authChecker.Allow(ctx, ops...)
		if err != nil {
			// Bad macaroon
			return false, "", "", err
		}

		if info != nil && info.Identity != nil {
			// Valid identity macaroon found
			return true, info.Identity.Id(), "candid", nil
		}

		// Valid macaroon with no identity information
		return true, "", "candid", nil
	}

	// Validate normal TLS access
	for i := range r.TLS.PeerCertificates {
		trusted, username := util.CheckTrustState(*r.TLS.PeerCertificates[i], d.clientCerts)
		if trusted {
			return true, username, "tls", nil
		}
	}

	// Reject unauthorized
	return false, "", "", nil
}

// Authenticate validates an incoming http Request
// It will check over what protocol it came, what type of request it is and
// will validate the TLS certificate or Macaroon.
//
// This does not perform authorization, only validates authentication

Authenticate validates an incoming http Request It will check over what protocol it came what type of request it is and will validate the TLS certificate or Macaroon . This does not perform authorization only validates authentication


func (d *Daemon) State() *state.State {
	return state.NewState(d.db, d.cluster, d.maas, d.os, d.endpoints)
}

func ( d * Daemon ) State ( ) * state . State { return state . NewState ( d . db , d . cluster , d . maas , d . os , d . endpoints ) }

// State creates a new State instance linked to our internal db and os.

State creates a new State instance linked to our internal db and os .


func (d *Daemon) UnixSocket() string {
	path := os.Getenv("LXD_SOCKET")
	if path != "" {
		return path
	}

	return filepath.Join(d.os.VarDir, "unix.socket")
}

func ( d * Daemon ) UnixSocket ( ) string { path := os . Getenv ( " " ) if path != " " { return path } return filepath . Join ( d . os . VarDir , " " ) }

// UnixSocket returns the full path to the unix.socket file that this daemon is
// listening on. Used by tests.

UnixSocket returns the full path to the unix . socket file that this daemon is listening on . Used by tests .


func (d *Daemon) Stop() error {
	logger.Info("Starting shutdown sequence")
	errs := []error{}
	trackError := func(err error) {
		if err != nil {
			errs = append(errs, err)
		}
	}

	if d.endpoints != nil {
		trackError(d.endpoints.Down())
	}

	trackError(d.tasks.Stop(3 * time.Second))        // Give tasks a bit of time to cleanup.
	trackError(d.clusterTasks.Stop(3 * time.Second)) // Give tasks a bit of time to cleanup.

	shouldUnmount := false
	if d.cluster != nil {
		// It might be that database nodes are all down, in that case
		// we don't want to wait too much.
		//
		// FIXME: it should be possible to provide a context or a
		//        timeout for database queries.
		ch := make(chan bool)
		go func() {
			n, err := d.numRunningContainers()
			ch <- err != nil || n == 0
		}()
		select {
		case shouldUnmount = <-ch:
		case <-time.After(2 * time.Second):
			shouldUnmount = true
		}

		logger.Infof("Closing the database")
		err := d.cluster.Close()
		// If we got io.EOF the network connection was interrupted and
		// it's likely that the other node shutdown. Let's just log the
		// event and return cleanly.
		if errors.Cause(err) == driver.ErrBadConn {
			logger.Debugf("Could not close remote database cleanly: %v", err)
		} else {
			trackError(err)
		}
	}
	if d.db != nil {
		trackError(d.db.Close())
	}

	if d.gateway != nil {
		trackError(d.gateway.Shutdown())
	}
	if d.endpoints != nil {
		trackError(d.endpoints.Down())
	}

	if d.endpoints != nil {
		trackError(d.endpoints.Down())
	}

	if shouldUnmount {
		logger.Infof("Unmounting temporary filesystems")

		syscall.Unmount(shared.VarPath("devlxd"), syscall.MNT_DETACH)
		syscall.Unmount(shared.VarPath("shmounts"), syscall.MNT_DETACH)

		logger.Infof("Done unmounting temporary filesystems")
	} else {
		logger.Debugf(
			"Not unmounting temporary filesystems (containers are still running)")
	}

	var err error
	if n := len(errs); n > 0 {
		format := "%v"
		if n > 1 {
			format += fmt.Sprintf(" (and %d more errors)", n)
		}
		err = fmt.Errorf(format, errs[0])
	}
	if err != nil {
		logger.Errorf("Failed to cleanly shutdown daemon: %v", err)
	}
	return err
}


func (d *Daemon) setupExternalAuthentication(authEndpoint string, authPubkey string, expiry int64, domains string) error {
	// Parse the list of domains
	authDomains := []string{}
	for _, domain := range strings.Split(domains, ",") {
		if domain == "" {
			continue
		}

		authDomains = append(authDomains, strings.TrimSpace(domain))
	}

	// Allow disable external authentication
	if authEndpoint == "" {
		d.externalAuth = nil
		return nil
	}

	// Setup the candid client
	idmClient, err := candidclient.New(candidclient.NewParams{
		BaseURL: authEndpoint,
	})
	if err != nil {
		return err
	}

	idmClientWrapper := &IdentityClientWrapper{
		client:       idmClient,
		ValidDomains: authDomains,
	}

	// Generate an internal private key
	key, err := bakery.GenerateKey()
	if err != nil {
		return err
	}

	pkCache := bakery.NewThirdPartyStore()
	pkLocator := httpbakery.NewThirdPartyLocator(nil, pkCache)
	if authPubkey != "" {
		// Parse the public key
		pkKey := bakery.Key{}
		err := pkKey.UnmarshalText([]byte(authPubkey))
		if err != nil {
			return err
		}

		// Add the key information
		pkCache.AddInfo(authEndpoint, bakery.ThirdPartyInfo{
			PublicKey: bakery.PublicKey{Key: pkKey},
			Version:   3,
		})

		// Allow http URLs if we have a public key set
		if strings.HasPrefix(authEndpoint, "http://") {
			pkLocator.AllowInsecure()
		}
	}

	// Setup the bakery
	bakery := identchecker.NewBakery(identchecker.BakeryParams{
		Key:            key,
		Location:       authEndpoint,
		Locator:        pkLocator,
		Checker:        httpbakery.NewChecker(),
		IdentityClient: idmClientWrapper,
		Authorizer: identchecker.ACLAuthorizer{
			GetACL: func(ctx context.Context, op bakery.Op) ([]string, bool, error) {
				return []string{identchecker.Everyone}, false, nil
			},
		},
	})

	// Store our settings
	d.externalAuth = &externalAuth{
		endpoint: authEndpoint,
		expiry:   expiry,
		bakery:   bakery,
	}

	return nil
}