Skip to content

Commit

Permalink
WIP: Add lxd_project resource type (#279)
Browse files Browse the repository at this point in the history
* feat: generating instances in correct project (destroy not working)

* feat: spawn instances in specific project with succesful destruction

* feat: profile project configuration

* feat: network feature requires newer lxd dependency version

* feat: project configuration with cached image

* feat: project configuration in container_file

* feat: publish_image project configuration added

* feat: snapshot project configuration

* feat: storage_pool project configuration added

* feat: volume project configuration added

* feat: project input handling

* feat: make fmt

* feat: trigger workflow

* fix: add features.storage.buckets parameter

* fix: typo d.Set()

* docs: project parameter docs update

* fix: review requested changes applied
  • Loading branch information
dorkamotorka authored Dec 20, 2022
1 parent 3f01ac8 commit 5d84499
Show file tree
Hide file tree
Showing 32 changed files with 1,457 additions and 9 deletions.
2 changes: 2 additions & 0 deletions docs/resources/cached_image.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ resource "lxd_container" "test1" {
* `copy_aliases` - *Optional* - Whether to copy the aliases of the image from
the remote. Valid values are `true` and `false`. Defaults to `true`.

* `project` - *Optional* - Name of the project where the image will be stored.

## Attribute Reference

The following attributes are exported:
Expand Down
2 changes: 2 additions & 0 deletions docs/resources/container.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ resource "lxd_container" "container1" {

* `target` - *Optional* - Specify a target node in a cluster.

* `project` - *Optional* - Name of the project where the container will be spawned.

The `device` block supports:

* `name` - *Required* - Name of the device.
Expand Down
2 changes: 2 additions & 0 deletions docs/resources/container_file.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,5 @@ resource "lxd_container_file" "file1" {
to the target if they do not exist.

* `append` - *Optional* - Whether to append the content to the target file. Defaults to false, where target file will be overwritten

* `project` - *Optional* - Name of the project where the container to which this file will be appended exist.
2 changes: 2 additions & 0 deletions docs/resources/network.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ for more details on how to create a network in clustered mode.
* `config` - *Optional* - Map of key/value pairs of
[network config settings](https://github.com/lxc/lxd/blob/master/doc/configuration.md).

* `project` - *Optional* - Name of the project where the network will be created.

## Attribute Reference

The following attributes are exported:
Expand Down
2 changes: 2 additions & 0 deletions docs/resources/profile.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ resource "lxd_container" "test1" {

* `device` - *Optional* - Device definition. See reference below.

* `project` - *Optional* - Name of the project where the profile will be stored.

The `device` block supports:

* `name` - *Required* - Name of the device.
Expand Down
31 changes: 30 additions & 1 deletion docs/resources/project.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,33 @@

Manages an LXD project.

Not implemented yet. Please follow progress on [issue #279](https://github.com/terraform-lxd/terraform-provider-lxd/pull/279).
## Example Usage

```hcl
resource "lxd_project" "project" {
name = "project1"
description = "Terraform provider example project"
config = {
"features.storage.volumes" = false
"features.images" = false
"features.profiles" = false
"features.storage.buckets" = false
}
}
resource "lxd_container" "container" {
name = "container1"
image = "images:alpine/3.16/amd64"
project = lxd_project.project.name
}
```

## Argument Reference

* `name` - *Required* - Name of the project.

* `description` - *Optional* - Description of the project.

* `config` - *Optional* - Map of key/value pairs of [project config settings](https://github.com/lxc/lxd/blob/master/doc/projects.md).

* `target` - *Optional* - Specify a target node in a cluster.
2 changes: 2 additions & 0 deletions docs/resources/publish_image.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ resource "lxd_publish_image" "test1" {

* `triggers` - *Optional* - A map of arbitrary strings that, when changed, will force the resource to be replaced.

* `project` - *Optional* - Name of the project where the published image will be stored.

## Notes

* The container must be stopped
2 changes: 2 additions & 0 deletions docs/resources/snapshot.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ resource "lxd_snapshot" "snap1" {
`false` for stateless. Stateful snapshots include runtime state. Defaults to
`true`.

* `project` - *Optional* - Name of the project where the snapshot will be stored.

## Attribute Reference

The following attributes are exported:
Expand Down
2 changes: 2 additions & 0 deletions docs/resources/storage_pool.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ for more details on how to create a storage pool in clustered mode.
[storage pool config settings](https://github.com/lxc/lxd/blob/master/doc/configuration.md).
Config settings vary from driver to driver.

* `project` - *Optional* - Name of the project where the storage pool will be stored.

## Importing

Storage pools can be imported by doing:
Expand Down
2 changes: 2 additions & 0 deletions docs/resources/volume.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ resource "lxd_volume" "volume1" {
[volume config settings](https://github.com/lxc/lxd/blob/master/doc/configuration.md).
Config settings vary depending on the Storage Pool used.

* `project` - *Optional* - Name of the project where the volume will be stored.

## Attribute Reference

The following attributes are exported:
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/juju/go4 v0.0.0-20160222163258-40d72ab9641a h1:45JtCyuNYE+QN9aPuR1ID9++BQU+NMTMudHSuaK0Las=
github.com/juju/go4 v0.0.0-20160222163258-40d72ab9641a/go.mod h1:RVHtZuvrpETIepiNUrNlih2OynoFf1eM6DGC6dloXzk=
Expand Down Expand Up @@ -413,6 +414,7 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
Expand All @@ -421,6 +423,7 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20150829230318-ea47fc708ee3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -551,6 +554,7 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed h1:+qzWo37K31KxduIYaBeMqJ8MUOyTayOQKpH9aDPLMSY=
golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down Expand Up @@ -580,6 +584,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
Expand Down
12 changes: 12 additions & 0 deletions lxd/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type lxdProvider struct {
// LXDConfig is the converted form of terraformLXDConfig
// in LXD's native data structure. This is lazy-loaded / created
// only when a connection to an LXD remote/server happens.
// https://github.com/lxc/lxd/blob/master/lxc/config/config.go
LXDConfig *lxd_config.Config

// lxdClientMap is a map of LXD client connections to LXD
Expand Down Expand Up @@ -184,6 +185,11 @@ func Provider() terraform.ResourceProvider {
Description: descriptions["lxd_refresh_interval"],
Default: "10s",
},
"project": {
Type: schema.TypeString,
Optional: true,
Description: descriptions["lxd_project"],
},
},

ResourcesMap: map[string]*schema.Resource{
Expand All @@ -193,6 +199,7 @@ func Provider() terraform.ResourceProvider {
"lxd_container_file": resourceLxdContainerFile(),
"lxd_network": resourceLxdNetwork(),
"lxd_profile": resourceLxdProfile(),
"lxd_project": resourceLxdProject(),
"lxd_snapshot": resourceLxdSnapshot(),
"lxd_storage_pool": resourceLxdStoragePool(),
"lxd_volume": resourceLxdVolume(),
Expand All @@ -216,6 +223,7 @@ func init() {
"lxd_remote_port": "Port LXD Daemon API is listening on. default = 8443.",
"lxd_remote_name": "Name of the LXD remote. Required when lxd_scheme set to https, to enable locating server certificate.",
"lxd_remote_password": "The password for the remote.",
"lxd_project": "The project where project-scoped resources will be created. Can be overridden in individual resources. default = default",
}
}

Expand Down Expand Up @@ -268,6 +276,10 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
}
}

if v, ok := d.Get("project").(string); ok && v != "" {
config.ProjectOverride = v
}

// Create an lxdProvider struct.
// This struct is used to store information about this Terraform
// provider's configuration for reference throughout the lifecycle.
Expand Down
29 changes: 28 additions & 1 deletion lxd/resource_lxd_cached_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ func resourceLxdCachedImage() *schema.Resource {
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},

"project": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
},
}
}
Expand All @@ -88,6 +94,10 @@ func resourceLxdCachedImageCreate(d *schema.ResourceData, meta interface{}) erro
if err != nil {
return err
}
if v, ok := d.GetOk("project"); ok && v != "" {
project := v.(string)
dstServer = dstServer.UseProject(project)
}

srcName := d.Get("source_remote").(string)
imgServer, err := p.GetImageServer(srcName)
Expand Down Expand Up @@ -172,6 +182,10 @@ func resourceLxdCachedImageUpdate(d *schema.ResourceData, meta interface{}) erro
if err != nil {
return err
}
if v, ok := d.GetOk("project"); ok && v != "" {
project := v.(string)
server = server.UseProject(project)
}
id := newCachedImageIDFromResourceID(d.Id())

if d.HasChange("aliases") {
Expand Down Expand Up @@ -214,6 +228,10 @@ func resourceLxdCachedImageDelete(d *schema.ResourceData, meta interface{}) erro
if err != nil {
return err
}
if v, ok := d.GetOk("project"); ok && v != "" {
project := v.(string)
server = server.UseProject(project)
}

id := newCachedImageIDFromResourceID(d.Id())

Expand All @@ -233,6 +251,11 @@ func resourceLxdCachedImageExists(d *schema.ResourceData, meta interface{}) (boo
return false, err
}

if v, ok := d.GetOk("project"); ok && v != "" {
project := v.(string)
server = server.UseProject(project)
}

id := newCachedImageIDFromResourceID(d.Id())

_, _, err = server.GetImage(id.fingerprint)
Expand All @@ -249,10 +272,14 @@ func resourceLxdCachedImageExists(d *schema.ResourceData, meta interface{}) (boo
func resourceLxdCachedImageRead(d *schema.ResourceData, meta interface{}) error {
p := meta.(*lxdProvider)
remote := p.selectRemote(d)
server, err := p.GetImageServer(remote)
server, err := p.GetInstanceServer(remote)
if err != nil {
return err
}
if v, ok := d.GetOk("project"); ok && v != "" {
project := v.(string)
server = server.UseProject(project)
}

id := newCachedImageIDFromResourceID(d.Id())

Expand Down
71 changes: 71 additions & 0 deletions lxd/resource_lxd_cached_image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,26 @@ func TestAccCachedImage_addRemoveAlias(t *testing.T) {
})
}

func TestAccCachedImage_project(t *testing.T) {
var img api.Image
var project api.Project
projectName := strings.ToLower(petname.Name())

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCachedImage_project(projectName),
Check: resource.ComposeTestCheckFunc(
testAccProjectRunning(t, "lxd_project.project1", &project),
testAccCachedImageExistsInProject(t, "lxd_cached_image.img1", &img, projectName),
),
},
},
})
}

func testAccCachedImageExists(t *testing.T, n string, image *api.Image) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
Expand Down Expand Up @@ -195,6 +215,37 @@ func testAccCachedImageExists(t *testing.T, n string, image *api.Image) resource
}
}

func testAccCachedImageExistsInProject(t *testing.T, n string, image *api.Image, project string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found in state: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}

id := newCachedImageIDFromResourceID(rs.Primary.ID)
client, err := testAccProvider.Meta().(*lxdProvider).GetInstanceServer("")
if err != nil {
return err
}
client = client.UseProject(project)
img, _, err := client.GetImage(id.fingerprint)
if err != nil {
return err
}

if img != nil {
*image = *img
return nil
}

return fmt.Errorf("Image not found: %s", rs.Primary.ID)
}
}

func testAccCachedImageContainsAlias(img *api.Image, alias string) resource.TestCheckFunc {
return func(s *terraform.State) error {
if img.Aliases == nil || len(img.Aliases) == 0 {
Expand Down Expand Up @@ -317,3 +368,23 @@ resource "lxd_cached_image" "img4" {
}
`)
}

func testAccCachedImage_project(project string) string {
return fmt.Sprintf(`
resource "lxd_project" "project1" {
name = "%s"
description = "Terraform provider test project"
config = {
"features.storage.volumes" = false
"features.images" = false
"features.storage.buckets" = false
"features.profiles" = false
}
}
resource "lxd_cached_image" "img1" {
source_remote = "images"
source_image = "alpine/3.16"
project = lxd_project.project1.name
}
`, project)
}
Loading

0 comments on commit 5d84499

Please sign in to comment.