@@ -53,6 +53,8 @@ func (c *incusRuntime) Dependencies() []string {
5353
5454// Provision implements environment.Container. 
5555func  (c  * incusRuntime ) Provision (ctx  context.Context ) error  {
56+ 	log  :=  c .Logger (ctx )
57+ 
5658	// ensure that the systemd socket file is created 
5759	if  err  :=  c .guest .RunQuiet ("sudo" , "systemctl" , "start" , "incus.socket" ); err  !=  nil  {
5860		return  fmt .Errorf ("error starting incus socket: %w" , err )
@@ -67,17 +69,23 @@ func (c *incusRuntime) Provision(ctx context.Context) error {
6769		return  nil 
6870	}
6971
72+ 	emptyDisk  :=  true 
73+ 	recoverStorage  :=  false 
7074	if  limautil .DiskProvisioned (Name ) {
71- 		// disk already provisioned 
72- 		return  nil 
75+ 		emptyDisk  =  false 
76+ 		// previous disk exist 
77+ 		// ignore storage, recovery would be attempted later 
78+ 		recoverStorage  =  cli .Prompt ("existing Incus data found, would you like to recover the storage pool" )
7379	}
7480
7581	var  value  struct  {
76- 		Disk       string 
77- 		Interface  string 
82+ 		Disk        string 
83+ 		Interface   string 
84+ 		SetStorage  bool 
7885	}
7986	value .Disk  =  "/dev/vdb" 
8087	value .Interface  =  incusBridgeInterface 
88+ 	value .SetStorage  =  emptyDisk  // set only when the disk is empty 
8189
8290	buf , err  :=  util .ParseTemplate (configYaml , value )
8391	if  err  !=  nil  {
@@ -89,6 +97,40 @@ func (c *incusRuntime) Provision(ctx context.Context) error {
8997		return  fmt .Errorf ("error setting up incus: %w" , err )
9098	}
9199
100+ 	// provision successful 
101+ 	if  emptyDisk  {
102+ 		return  nil 
103+ 	}
104+ 
105+ 	if  ! recoverStorage  {
106+ 		log .Warnln ("discarding data, creating new storage pool" )
107+ 		return  c .wipeDisk (false )
108+ 	}
109+ 
110+ 	if  ! c .hasExistingPool () {
111+ 		log .Warnln ("discarding corrupted disk, creating new storage pool" )
112+ 		return  c .wipeDisk (false )
113+ 	}
114+ 
115+ 	if  err  :=  c .importExistingPool (); err  !=  nil  {
116+ 		log .Warnln (fmt .Errorf ("cannot recover disk: %w, creating new storage pool" , err ))
117+ 		return  c .wipeDisk (false )
118+ 	}
119+ 
120+ 	for  {
121+ 		if  err  :=  c .recoverDisk (ctx ); err  !=  nil  {
122+ 			log .Warnln (err )
123+ 
124+ 			if  cli .Prompt ("recovery failed, try again" ) {
125+ 				continue 
126+ 			}
127+ 
128+ 			log .Warnln ("discarding disk, creating new storage pool" )
129+ 			return  c .wipeDisk (true )
130+ 		}
131+ 		break 
132+ 	}
133+ 
92134	return  nil 
93135}
94136
@@ -315,9 +357,61 @@ func DataDisk() environment.DataDisk {
315357	}
316358}
317359
318- func  SystemdServices () []string  {
319- 	return  []string {
320- 		"incus.service" ,
321- 		"incus.socket" ,
360+ func  (c  * incusRuntime ) hasExistingPool () bool  {
361+ 	return  c .guest .RunQuiet ("sh" , "-c" , "sudo zpool import | grep -A 2 'pool: default' | grep 'state: ONLINE'" ) ==  nil 
362+ }
363+ 
364+ func  (c  * incusRuntime ) importExistingPool () error  {
365+ 	if  err  :=  c .guest .RunQuiet ("sudo" , "zpool" , "import" , "default" ); err  !=  nil  {
366+ 		return  fmt .Errorf ("error importing existing zpool: %w" , err )
322367	}
368+ 
369+ 	return  nil 
370+ }
371+ 
372+ func  (c  * incusRuntime ) recoverDisk (ctx  context.Context ) error  {
373+ 	log  :=  c .Logger (ctx )
374+ 
375+ 	log .Println ()
376+ 	log .Println ("Running 'incus admin recover' ..." )
377+ 	log .Println ()
378+ 	log .Println ("Use the following values for the prompts" )
379+ 	log .Println ("  name of storage pool: default" )
380+ 	log .Println ("  name of storage backend: zfs" )
381+ 	log .Println ("  source of storage pool: /dev/vdb" )
382+ 	log .Println ()
383+ 
384+ 	if  err  :=  c .guest .RunInteractive ("sudo" , "incus" , "admin" , "recover" ); err  !=  nil  {
385+ 		return  fmt .Errorf ("error recovering storage pool: %w" , err )
386+ 	}
387+ 
388+ 	out , err  :=  c .guest .RunOutput ("sudo" , "incus" , "storage" , "list" , "name=default" , "-c" , "n" , "--format" , "compact,noheader" )
389+ 	if  err  !=  nil  {
390+ 		return  err 
391+ 	}
392+ 
393+ 	if  out  !=  "default"  {
394+ 		return  fmt .Errorf ("storage pool recovery failure" )
395+ 	}
396+ 
397+ 	return  nil 
398+ }
399+ 
400+ func  (c  * incusRuntime ) wipeDisk (wipeZpool  bool ) error  {
401+ 	if  wipeZpool  {
402+ 		if  err  :=  c .guest .RunQuiet ("sudo" , "zpool" , "destroy" , "default" ); err  !=  nil  {
403+ 			return  fmt .Errorf ("cannot resetting pool data: %w" , err )
404+ 		}
405+ 	} else  {
406+ 		if  err  :=  c .guest .RunQuiet ("sudo" , "sfdisk" , "--delete" , "/dev/vdb" , "1" ); err  !=  nil  {
407+ 			return  fmt .Errorf ("error resetting pool data: %w" , err )
408+ 		}
409+ 	}
410+ 
411+ 	// prepare directory 
412+ 	if  err  :=  c .guest .RunQuiet ("sudo" , "rm" , "-rf" , "/var/lib/incus/storage-pools/default" ); err  !=  nil  {
413+ 		return  fmt .Errorf ("error preparing storage pools directory: %w" , err )
414+ 	}
415+ 
416+ 	return  c .guest .RunQuiet ("sudo" , "incus" , "storage" , "create" , "default" , "zfs" , "source=/dev/vdb" )
323417}
0 commit comments