Merge branch 'feature/implement_resource_images' into '1.26'
Feature/implement resource images See merge request rudecs/terraform-provider-decort!1
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
|||||||
decort/vendor/
|
decort/vendor/
|
||||||
|
examples/
|
||||||
|
url_scrapping/
|
||||||
terraform-provider-decort*
|
terraform-provider-decort*
|
||||||
|
|||||||
39
Makefile
Normal file
39
Makefile
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
TEST?=$$(go list ./... | grep -v 'vendor')
|
||||||
|
HOSTNAME=digitalenergy.online
|
||||||
|
NAMESPACE=decort
|
||||||
|
NAME=terraform-provider-decort
|
||||||
|
#BINARY=terraform-provider-${NAME}
|
||||||
|
BINARY=${NAME}.exe
|
||||||
|
VERSION=0.2
|
||||||
|
#OS_ARCH=darwin_amd64
|
||||||
|
OS_ARCH=windows_amd64
|
||||||
|
|
||||||
|
default: install
|
||||||
|
|
||||||
|
build:
|
||||||
|
go build -o ${BINARY}
|
||||||
|
|
||||||
|
release:
|
||||||
|
GOOS=darwin GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_darwin_amd64
|
||||||
|
GOOS=freebsd GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_freebsd_386
|
||||||
|
GOOS=freebsd GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_freebsd_amd64
|
||||||
|
GOOS=freebsd GOARCH=arm go build -o ./bin/${BINARY}_${VERSION}_freebsd_arm
|
||||||
|
GOOS=linux GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_linux_386
|
||||||
|
GOOS=linux GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_linux_amd64
|
||||||
|
GOOS=linux GOARCH=arm go build -o ./bin/${BINARY}_${VERSION}_linux_arm
|
||||||
|
GOOS=openbsd GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_openbsd_386
|
||||||
|
GOOS=openbsd GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_openbsd_amd64
|
||||||
|
GOOS=solaris GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_solaris_amd64
|
||||||
|
GOOS=windows GOARCH=386 go build -o ./bin/${BINARY}_${VERSION}_windows_386
|
||||||
|
GOOS=windows GOARCH=amd64 go build -o ./bin/${BINARY}_${VERSION}_windows_amd64
|
||||||
|
|
||||||
|
install: build
|
||||||
|
mkdir -p ~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH}
|
||||||
|
mv ${BINARY} ~/.terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH}
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test -i $(TEST) || exit 1
|
||||||
|
echo $(TEST) | xargs -t -n4 go test $(TESTARGS) -timeout=30s -parallel=4
|
||||||
|
|
||||||
|
testacc:
|
||||||
|
TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 120m
|
||||||
100
decort/data_source_grid.go
Normal file
100
decort/data_source_grid.go
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenGrid(d *schema.ResourceData, grid *Grid) {
|
||||||
|
d.Set("name", grid.Name)
|
||||||
|
d.Set("flag", grid.Flag)
|
||||||
|
d.Set("gid", grid.Gid)
|
||||||
|
d.Set("guid", grid.Guid)
|
||||||
|
d.Set("location_code", grid.LocationCode)
|
||||||
|
d.Set("id", grid.Id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceGridRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
grid, err := utilityGridCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId(strconv.Itoa(grid.Id))
|
||||||
|
flattenGrid(d, grid)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceGetGridSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"grid_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"flag": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"location_code": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceGrid() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceGridRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceGetGridSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
128
decort/data_source_grid_list.go
Normal file
128
decort/data_source_grid_list.go
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenGridList(gl GridList) []map[string]interface{} {
|
||||||
|
res := make([]map[string]interface{}, 0)
|
||||||
|
for _, item := range gl {
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"name": item.Name,
|
||||||
|
"flag": item.Flag,
|
||||||
|
"gid": item.Gid,
|
||||||
|
"guid": item.Guid,
|
||||||
|
"location_code": item.LocationCode,
|
||||||
|
"id": item.Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
res = append(res, temp)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceGridListRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
gridList, err := utilityGridListCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", flattenGridList(gridList))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceGridListSchemaMake() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"page": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "page number",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "page size",
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Description: "grid list",
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: dataSourceGridSchemaMake(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceGridSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"flag": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"location_code": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceGridList() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceGridListRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceGridListSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -25,57 +25,275 @@ Visit https://github.com/rudecs/terraform-provider-decort for full source code p
|
|||||||
package decort
|
package decort
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"strconv"
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func flattenImage(d *schema.ResourceData, image *Image) {
|
||||||
|
d.Set("name", image.Name)
|
||||||
|
d.Set("drivers", image.Drivers)
|
||||||
|
d.Set("url", image.Url)
|
||||||
|
d.Set("gid", image.Gid)
|
||||||
|
d.Set("image_id", image.ImageId)
|
||||||
|
d.Set("boot_type", image.Boottype)
|
||||||
|
d.Set("image_type", image.Imagetype)
|
||||||
|
d.Set("bootable", image.Bootable)
|
||||||
|
d.Set("sep_id", image.SepId)
|
||||||
|
d.Set("unc_path", image.UNCPath)
|
||||||
|
d.Set("link_to", image.LinkTo)
|
||||||
|
d.Set("status", image.Status)
|
||||||
|
d.Set("tech_status", image.TechStatus)
|
||||||
|
d.Set("version", image.Version)
|
||||||
|
d.Set("size", image.Size)
|
||||||
|
d.Set("enabled", image.Enabled)
|
||||||
|
d.Set("computeci_id", image.ComputeciId)
|
||||||
|
d.Set("pool_name", image.PoolName)
|
||||||
|
d.Set("username", image.Username)
|
||||||
|
d.Set("username_dl", image.UsernameDL)
|
||||||
|
d.Set("password", image.Password)
|
||||||
|
d.Set("password_dl", image.PasswordDL)
|
||||||
|
d.Set("account_id", image.AccountId)
|
||||||
|
d.Set("guid", image.Guid)
|
||||||
|
d.Set("milestones", image.Milestones)
|
||||||
|
d.Set("provider_name", image.ProviderName)
|
||||||
|
d.Set("purge_attempts", image.PurgeAttempts)
|
||||||
|
d.Set("reference_id", image.ReferenceId)
|
||||||
|
d.Set("res_id", image.ResId)
|
||||||
|
d.Set("res_name", image.ResName)
|
||||||
|
d.Set("rescuecd", image.Rescuecd)
|
||||||
|
d.Set("architecture", image.Architecture)
|
||||||
|
d.Set("hot_resize", image.Hotresize)
|
||||||
|
d.Set("history", flattenHistory(image.History))
|
||||||
|
d.Set("last_modified", image.LastModified)
|
||||||
|
d.Set("meta", flattenMeta(image.Meta))
|
||||||
|
d.Set("desc", image.Desc)
|
||||||
|
d.Set("shared_with", image.SharedWith)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func dataSourceImageRead(d *schema.ResourceData, m interface{}) error {
|
func dataSourceImageRead(d *schema.ResourceData, m interface{}) error {
|
||||||
name := d.Get("name").(string)
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
// rg_id, rgid_set := d.GetOk("rg_id")
|
|
||||||
accId, accSet := d.GetOk("account_id")
|
|
||||||
|
|
||||||
controller := m.(*ControllerCfg)
|
|
||||||
url_values := &url.Values{}
|
|
||||||
if accSet {
|
|
||||||
url_values.Add("accountId", fmt.Sprintf("%d", accId.(int)))
|
|
||||||
}
|
|
||||||
body_string, err := controller.decortAPICall("POST", ImagesListAPI, url_values)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
d.SetId(strconv.Itoa(image.Guid))
|
||||||
|
flattenImage(d, image)
|
||||||
|
|
||||||
log.Debugf("dataSourceImageRead: ready to decode response body from %s", ImagesListAPI)
|
return nil
|
||||||
model := ImagesListResp{}
|
}
|
||||||
err = json.Unmarshal([]byte(body_string), &model)
|
|
||||||
if err != nil {
|
func dataSourceImageSchemaMake() map[string]*schema.Schema {
|
||||||
return err
|
return map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Name of the rescue disk",
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "URL where to download media from",
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "grid (platform) ID where this template should be create in",
|
||||||
|
},
|
||||||
|
"boot_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Boot type of image bios or uefi",
|
||||||
|
},
|
||||||
|
"image_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Image type linux, windows or other",
|
||||||
|
},
|
||||||
|
"shared_with": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"drivers": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "List of types of compute suitable for image. Example: [ \"KVM_X86\" ]",
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "meta",
|
||||||
|
},
|
||||||
|
"hot_resize": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this machine supports hot resize",
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional username for the image",
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional password for the image",
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "AccountId to make the image exclusive",
|
||||||
|
},
|
||||||
|
"username_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "username for upload binary media",
|
||||||
|
},
|
||||||
|
"password_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "password for upload binary media",
|
||||||
|
},
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "storage endpoint provider ID",
|
||||||
|
},
|
||||||
|
"pool_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "pool for image create",
|
||||||
|
},
|
||||||
|
"architecture": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "binary architecture of this image, one of X86_64 of PPC64_LE",
|
||||||
|
},
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "image id",
|
||||||
|
},
|
||||||
|
"permanently": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Whether to completely delete the image",
|
||||||
|
},
|
||||||
|
"bootable": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this image boot OS",
|
||||||
|
},
|
||||||
|
"unc_path": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "unc path",
|
||||||
|
},
|
||||||
|
"link_to": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "",
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "status",
|
||||||
|
},
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "tech atatus",
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "version",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image size",
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"computeci_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"provider_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"purge_attempts": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reference_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rescuecd": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"last_modified": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// log.Printf("%#v", model)
|
|
||||||
log.Debugf("dataSourceImageRead: traversing decoded JSON of length %d", len(model))
|
|
||||||
for index, item := range model {
|
|
||||||
// need to match Image by name
|
|
||||||
if item.Name == name {
|
|
||||||
log.Debugf("dataSourceImageRead: index %d, matched name %s", index, item.Name)
|
|
||||||
d.SetId(fmt.Sprintf("%d", item.ID))
|
|
||||||
d.Set("account_id", item.AccountID)
|
|
||||||
d.Set("arch", item.Arch)
|
|
||||||
d.Set("sep_id", item.SepID)
|
|
||||||
d.Set("pool", item.Pool)
|
|
||||||
d.Set("status", item.Status)
|
|
||||||
d.Set("size", item.Size)
|
|
||||||
// d.Set("field_name", value)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Errorf("Cannot find Image name %s", name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataSourceImage() *schema.Resource {
|
func dataSourceImage() *schema.Resource {
|
||||||
@@ -89,57 +307,6 @@ func dataSourceImage() *schema.Resource {
|
|||||||
Default: &Timeout60s,
|
Default: &Timeout60s,
|
||||||
},
|
},
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: dataSourceImageSchemaMake(),
|
||||||
"name": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
Description: "Name of the image to locate. This parameter is case sensitive.",
|
|
||||||
},
|
|
||||||
|
|
||||||
"account_id": {
|
|
||||||
Type: schema.TypeInt,
|
|
||||||
Optional: true,
|
|
||||||
ValidateFunc: validation.IntAtLeast(1),
|
|
||||||
Description: "Optional ID of the account to limit image search to.",
|
|
||||||
},
|
|
||||||
|
|
||||||
"arch": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
Description: "Binary architecture of this image.",
|
|
||||||
},
|
|
||||||
|
|
||||||
"sep_id": {
|
|
||||||
Type: schema.TypeInt,
|
|
||||||
Computed: true,
|
|
||||||
Description: "Storage end-point provider serving this image.",
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
"sep_type": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
Description: "Type of the storage end-point provider serving this image.",
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
|
|
||||||
"pool": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
Description: "Pool where this image is located.",
|
|
||||||
},
|
|
||||||
|
|
||||||
"size": {
|
|
||||||
Type: schema.TypeInt,
|
|
||||||
Computed: true,
|
|
||||||
Description: "Size of the image in GB.",
|
|
||||||
},
|
|
||||||
|
|
||||||
"status": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
Description: "Current model status of this image.",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
140
decort/data_source_image_list.go
Normal file
140
decort/data_source_image_list.go
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenImageList(il ImageList) []map[string]interface{} {
|
||||||
|
res := make([]map[string]interface{}, 0)
|
||||||
|
for _, item := range il {
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"name": item.Name,
|
||||||
|
"url": item.Url,
|
||||||
|
"gid": item.Gid,
|
||||||
|
"guid": item.Guid,
|
||||||
|
"drivers": item.Drivers,
|
||||||
|
"image_id": item.ImageId,
|
||||||
|
"boot_type": item.Boottype,
|
||||||
|
"bootable": item.Bootable,
|
||||||
|
"image_type": item.Imagetype,
|
||||||
|
"status": item.Status,
|
||||||
|
"tech_status": item.TechStatus,
|
||||||
|
"version": item.Version,
|
||||||
|
"username": item.Username,
|
||||||
|
"username_dl": item.UsernameDL,
|
||||||
|
"password": item.Password,
|
||||||
|
"password_dl": item.PasswordDL,
|
||||||
|
"purge_attempts": item.PurgeAttempts,
|
||||||
|
"architecture": item.Architecture,
|
||||||
|
"account_id": item.AccountId,
|
||||||
|
"computeci_id": item.ComputeciId,
|
||||||
|
"enabled": item.Enabled,
|
||||||
|
"reference_id": item.ReferenceId,
|
||||||
|
"res_id": item.ResId,
|
||||||
|
"res_name": item.ResName,
|
||||||
|
"rescuecd": item.Rescuecd,
|
||||||
|
"provider_name": item.ProviderName,
|
||||||
|
"milestones": item.Milestones,
|
||||||
|
"size": item.Size,
|
||||||
|
"sep_id": item.SepId,
|
||||||
|
"link_to": item.LinkTo,
|
||||||
|
"unc_path": item.UNCPath,
|
||||||
|
"pool_name": item.PoolName,
|
||||||
|
"hot_resize": item.Hotresize,
|
||||||
|
"history": flattenHistory(item.History),
|
||||||
|
"last_modified": item.LastModified,
|
||||||
|
"meta": flattenMeta(item.Meta),
|
||||||
|
"desc": item.Desc,
|
||||||
|
"shared_with": item.SharedWith,
|
||||||
|
}
|
||||||
|
res = append(res, temp)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageListRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
imageList, err := utilityImageListCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", flattenImageList(imageList))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageListSchemaMake() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "filter images by storage endpoint provider ID",
|
||||||
|
},
|
||||||
|
"shared_with": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "filter images by account ID availability",
|
||||||
|
},
|
||||||
|
"page": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "page number",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "page size",
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image list",
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: dataSourceImageSchemaMake(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageList() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceImageListRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceImageListSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
182
decort/data_source_image_list_stacks.go
Normal file
182
decort/data_source_image_list_stacks.go
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenImageListStacks(d *schema.ResourceData, stack ImageListStacks) []map[string]interface{} {
|
||||||
|
temp := make([]map[string]interface{}, 0)
|
||||||
|
for _, item := range stack {
|
||||||
|
t := map[string]interface{}{
|
||||||
|
"api_url": item.ApiURL,
|
||||||
|
"api_key": item.ApiKey,
|
||||||
|
"app_id": item.AppId,
|
||||||
|
"desc": item.Desc,
|
||||||
|
"drivers": item.Drivers,
|
||||||
|
"error": item.Error,
|
||||||
|
"guid": item.Guid,
|
||||||
|
"id": item.Id,
|
||||||
|
"images": item.Images,
|
||||||
|
"login": item.Login,
|
||||||
|
"name": item.Name,
|
||||||
|
"passwd": item.Passwd,
|
||||||
|
"reference_id": item.ReferenceId,
|
||||||
|
"status": item.Status,
|
||||||
|
"type": item.Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = append(temp, t)
|
||||||
|
}
|
||||||
|
return temp
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageListStacksRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
imageListStacks, err := utilityImageListStacksCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", flattenImageListStacks(d, imageListStacks))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageListStackSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"api_url": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"api_key": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"app_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"drivers": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"images": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"login": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"passwd": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reference_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageListStacksSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "image id",
|
||||||
|
},
|
||||||
|
"page": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "page number",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "page size",
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: dataSourceImageListStackSchemaMake(),
|
||||||
|
},
|
||||||
|
Description: "items of stacks list",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageListStacks() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceImageListStacksRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceImageListStacksSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -667,3 +667,112 @@ type SshKeyConfig struct {
|
|||||||
SshKey string
|
SshKey string
|
||||||
UserShell string
|
UserShell string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// IMAGE API //
|
||||||
|
////////////////////
|
||||||
|
const imageCreateAPI = "/restmachine/cloudbroker/image/createImage"
|
||||||
|
const imageSyncCreateAPI = "/restmachine/cloudbroker/image/syncCreateImage"
|
||||||
|
const imageCreateVirtualAPI = "/restmachine/cloudbroker/image/createVirtual"
|
||||||
|
const imageCreateCDROMAPI = "/restmachine/cloudbroker/image/createCDROMImage"
|
||||||
|
const imageListStacksApi = "/restmachine/cloudbroker/image/listStacks"
|
||||||
|
const imageGetAPI = "/restmachine/cloudbroker/image/get"
|
||||||
|
const imageListGetAPI = "/restmachine/cloudbroker/image/list"
|
||||||
|
const imageEditAPI = "/restmachine/cloudbroker/image/edit"
|
||||||
|
const imageDeleteAPI = "/restmachine/cloudbroker/image/delete"
|
||||||
|
const imageDeleteCDROMAPI = "/restmachine/cloudbroker/image/deleteCDROMImage"
|
||||||
|
const imageEnableAPI = "/restmachine/cloudbroker/image/enable"
|
||||||
|
const imageDisableAPI = "/restmachine/cloudbroker/image/disable"
|
||||||
|
const imageEditNameAPI = "/restmachine/cloudbroker/image/rename"
|
||||||
|
const imageLinkAPI = "/restmachine/cloudbroker/image/link"
|
||||||
|
const imageShareAPI = "/restmachine/cloudbroker/image/share"
|
||||||
|
const imageComputeciSetAPI = "/restmachine/cloudbroker/image/computeciSet"
|
||||||
|
const imageComputeciUnsetAPI = "/restmachine/cloudbroker/image/computeciUnset"
|
||||||
|
const imageUpdateNodesAPI = "/restmachine/cloudbroker/image/updateNodes"
|
||||||
|
const imageDeleteImagesAPI = "/restmachine/cloudbroker/image/deleteImages"
|
||||||
|
|
||||||
|
type History struct {
|
||||||
|
Guid string `json:"guid"`
|
||||||
|
Id int `json:"id"`
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Image struct {
|
||||||
|
ImageId int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
Gid int `json:"gid"`
|
||||||
|
Guid int `json:"guid"`
|
||||||
|
Boottype string `json:"bootType"`
|
||||||
|
Imagetype string `json:"type"`
|
||||||
|
Drivers []string `json:"drivers"`
|
||||||
|
Hotresize bool `json:"hotResize"`
|
||||||
|
Bootable bool `json:"bootable"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
AccountId int `json:"accountId"`
|
||||||
|
UsernameDL string `json:"usernameDL"`
|
||||||
|
PasswordDL string `json:"passwordDL"`
|
||||||
|
SepId int `json:"sepId"`
|
||||||
|
PoolName string `json:"pool"`
|
||||||
|
Architecture string `json:"architecture"`
|
||||||
|
UNCPath string `json:"UNCPath"`
|
||||||
|
LinkTo int `json:"linkTo"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
TechStatus string `json:"techStatus"`
|
||||||
|
Size int `json:"size"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
ComputeciId int `json:"computeciId"`
|
||||||
|
Milestones int `json:"milestones"`
|
||||||
|
ProviderName string `json:"provider_name"`
|
||||||
|
PurgeAttempts int `json:"purgeAttempts"`
|
||||||
|
ReferenceId string `json:"referenceId"`
|
||||||
|
ResId string `json:"resId"`
|
||||||
|
ResName string `json:"resName"`
|
||||||
|
Rescuecd bool `json:"rescuecd"`
|
||||||
|
Meta []interface{} `json:"_meta"`
|
||||||
|
History []History `json:"history"`
|
||||||
|
LastModified int64 `json:"lastModified"`
|
||||||
|
Desc string `json:"desc"`
|
||||||
|
SharedWith []int `json:"sharedWith"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImageList []Image
|
||||||
|
|
||||||
|
type ImageStack struct {
|
||||||
|
ApiURL string `json:"apiUrl"`
|
||||||
|
ApiKey string `json:"apikey"`
|
||||||
|
AppId string `json:"appId"`
|
||||||
|
Desc string `json:"desc"`
|
||||||
|
Drivers []string `json:"drivers"`
|
||||||
|
Error int `json:"error"`
|
||||||
|
Guid int `json:"guid"`
|
||||||
|
Id int `json:"id"`
|
||||||
|
Images []int `json:"images"`
|
||||||
|
Login string `json:"login"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Passwd string `json:"passwd"`
|
||||||
|
ReferenceId string `json:"referenceId"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImageListStacks []ImageStack
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
// GRID API //
|
||||||
|
/////////////////
|
||||||
|
const GridListGetAPI = "/restmachine/cloudbroker/grid/list"
|
||||||
|
const GridGetAPI = "/restmachine/cloudbroker/grid/get"
|
||||||
|
|
||||||
|
type Grid struct {
|
||||||
|
Flag string `json:"flag"`
|
||||||
|
Gid int `json:"gid"`
|
||||||
|
Guid int `json:"guid"`
|
||||||
|
Id int `json:"id"`
|
||||||
|
LocationCode string `json:"locationCode"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GridList []Grid
|
||||||
|
|||||||
@@ -99,22 +99,30 @@ func Provider() *schema.Provider {
|
|||||||
},
|
},
|
||||||
|
|
||||||
ResourcesMap: map[string]*schema.Resource{
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
"decort_resgroup": resourceResgroup(),
|
"decort_resgroup": resourceResgroup(),
|
||||||
"decort_kvmvm": resourceCompute(),
|
"decort_kvmvm": resourceCompute(),
|
||||||
"decort_disk": resourceDisk(),
|
"decort_disk": resourceDisk(),
|
||||||
"decort_vins": resourceVins(),
|
"decort_vins": resourceVins(),
|
||||||
"decort_pfw": resourcePfw(),
|
"decort_pfw": resourcePfw(),
|
||||||
"decort_k8s": resourceK8s(),
|
"decort_k8s": resourceK8s(),
|
||||||
"decort_k8s_wg": resourceK8sWg(),
|
"decort_k8s_wg": resourceK8sWg(),
|
||||||
|
"decort_image": resourceImage(),
|
||||||
|
"decort_virtual_image": resourceVirtualImage(),
|
||||||
|
"decort_cdrom_image": resourceCDROMImage(),
|
||||||
|
"decort_delete_images": resourceDeleteImages(),
|
||||||
},
|
},
|
||||||
|
|
||||||
DataSourcesMap: map[string]*schema.Resource{
|
DataSourcesMap: map[string]*schema.Resource{
|
||||||
"decort_account": dataSourceAccount(),
|
"decort_account": dataSourceAccount(),
|
||||||
"decort_resgroup": dataSourceResgroup(),
|
"decort_resgroup": dataSourceResgroup(),
|
||||||
"decort_kvmvm": dataSourceCompute(),
|
"decort_kvmvm": dataSourceCompute(),
|
||||||
"decort_image": dataSourceImage(),
|
"decort_image": dataSourceImage(),
|
||||||
"decort_disk": dataSourceDisk(),
|
"decort_disk": dataSourceDisk(),
|
||||||
"decort_vins": dataSourceVins(),
|
"decort_vins": dataSourceVins(),
|
||||||
|
"decort_grid": dataSourceGrid(),
|
||||||
|
"decort_grid_list": dataSourceGridList(),
|
||||||
|
"decort_image_list": dataSourceImageList(),
|
||||||
|
"decort_image_list_stacks": dataSourceImageListStacks(),
|
||||||
// "decort_pfw": dataSourcePfw(),
|
// "decort_pfw": dataSourcePfw(),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
449
decort/resource_cdrom_image.go
Normal file
449
decort/resource_cdrom_image.go
Normal file
@@ -0,0 +1,449 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/customdiff"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceCDROMImageCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceCDROMImageCreate: called for image %s", d.Get("name").(string))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
urlValues.Add("url", d.Get("url").(string))
|
||||||
|
urlValues.Add("gid", strconv.Itoa(d.Get("gid").(int)))
|
||||||
|
|
||||||
|
tstr := d.Get("drivers").([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(tstr)
|
||||||
|
for i, str := range tstr {
|
||||||
|
s := "\"" + str.(string) + "\""
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ","
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
urlValues.Add("drivers", temp)
|
||||||
|
|
||||||
|
if username, ok := d.GetOk("username"); ok {
|
||||||
|
urlValues.Add("username", username.(string))
|
||||||
|
}
|
||||||
|
if password, ok := d.GetOk("password"); ok {
|
||||||
|
urlValues.Add("password", password.(string))
|
||||||
|
}
|
||||||
|
if accountId, ok := d.GetOk("account_id"); ok {
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(accountId.(int)))
|
||||||
|
}
|
||||||
|
if usernameDL, ok := d.GetOk("username_dl"); ok {
|
||||||
|
urlValues.Add("usernameDL", usernameDL.(string))
|
||||||
|
}
|
||||||
|
if passwordDL, ok := d.GetOk("password_dl"); ok {
|
||||||
|
urlValues.Add("passwordDL", passwordDL.(string))
|
||||||
|
}
|
||||||
|
if sepId, ok := d.GetOk("sep_id"); ok {
|
||||||
|
urlValues.Add("sepId", strconv.Itoa(sepId.(int)))
|
||||||
|
}
|
||||||
|
if poolName, ok := d.GetOk("pool_name"); ok {
|
||||||
|
urlValues.Add("pool_name", poolName.(string))
|
||||||
|
}
|
||||||
|
if architecture, ok := d.GetOk("architecture"); ok {
|
||||||
|
urlValues.Add("architecture", architecture.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
imageId, err := controller.decortAPICall("POST", imageCreateCDROMAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(imageId)
|
||||||
|
d.Set("image_id", imageId)
|
||||||
|
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(strconv.Itoa(image.ImageId))
|
||||||
|
d.Set("bootable", image.Bootable)
|
||||||
|
//d.Set("image_id", image.ImageId)
|
||||||
|
|
||||||
|
err = resourceImageRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceCDROMImageDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceCDROMImageDelete: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if image == nil {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
|
||||||
|
if permanently, ok := d.GetOk("permanently"); ok {
|
||||||
|
urlValues.Add("permanently", strconv.FormatBool(permanently.(bool)))
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = controller.decortAPICall("POST", imageDeleteCDROMAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceCDROMImageSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Name of the rescue disk",
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "URL where to download ISO from",
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "grid (platform) ID where this template should be create in",
|
||||||
|
},
|
||||||
|
"boot_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Boot type of image bios or uefi",
|
||||||
|
},
|
||||||
|
"image_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Image type linux, windows or other",
|
||||||
|
},
|
||||||
|
"drivers": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Required: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "List of types of compute suitable for image. Example: [ \"KVM_X86\" ]",
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "meta",
|
||||||
|
},
|
||||||
|
"hot_resize": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this machine supports hot resize",
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional username for the image",
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional password for the image",
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "AccountId to make the image exclusive",
|
||||||
|
},
|
||||||
|
"username_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "username for upload binary media",
|
||||||
|
},
|
||||||
|
"password_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "password for upload binary media",
|
||||||
|
},
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "storage endpoint provider ID",
|
||||||
|
},
|
||||||
|
"pool_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "pool for image create",
|
||||||
|
},
|
||||||
|
"architecture": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "binary architecture of this image, one of X86_64 of PPC64_LE",
|
||||||
|
},
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image id",
|
||||||
|
},
|
||||||
|
"permanently": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Whether to completely delete the image",
|
||||||
|
},
|
||||||
|
"bootable": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this image boot OS",
|
||||||
|
},
|
||||||
|
"unc_path": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "unc path",
|
||||||
|
},
|
||||||
|
"link_to": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "",
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "status",
|
||||||
|
},
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "tech atatus",
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "version",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image size",
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"computeci_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"provider_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"purge_attempts": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reference_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rescuecd": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"shared_with": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"enabled_stacks": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceCDROMImage() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceCDROMImageCreate,
|
||||||
|
Read: resourceImageRead,
|
||||||
|
Update: resourceImageEdit,
|
||||||
|
Delete: resourceCDROMImageDelete,
|
||||||
|
Exists: resourceImageExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
CustomizeDiff: customdiff.All(
|
||||||
|
customdiff.IfValueChange("enabled", func(old, new, meta interface{}) bool {
|
||||||
|
if old.(bool) != new.(bool) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageChangeEnabled),
|
||||||
|
customdiff.IfValueChange("name", func(old, new, meta interface{}) bool {
|
||||||
|
if old.(string) != new.(string) && old.(string) != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageEditName),
|
||||||
|
customdiff.IfValueChange("shared_with", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.([]interface{})
|
||||||
|
n := new.([]interface{})
|
||||||
|
|
||||||
|
if len(o) != len(n) {
|
||||||
|
return true
|
||||||
|
} else if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
for i, v := range n {
|
||||||
|
if v.(int) == o[i].(int) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if count == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageShare),
|
||||||
|
customdiff.IfValueChange("computeci_id", func(old, new, meta interface{}) bool {
|
||||||
|
if old.(int) != new.(int) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageChangeComputeci),
|
||||||
|
customdiff.IfValueChange("enabled_stacks", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.([]interface{})
|
||||||
|
n := new.([]interface{})
|
||||||
|
|
||||||
|
if len(o) != len(n) {
|
||||||
|
return true
|
||||||
|
} else if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
for i, v := range n {
|
||||||
|
if v.(string) == o[i].(string) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if count == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageUpdateNodes),
|
||||||
|
),
|
||||||
|
|
||||||
|
Schema: resourceCDROMImageSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
131
decort/resource_delete_images.go
Normal file
131
decort/resource_delete_images.go
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceCreateListImages(d *schema.ResourceData, m interface{}) error {
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceDeleteListImages(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceDeleteListImages: start deleting...")
|
||||||
|
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
imageIds := d.Get("image_ids").([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(imageIds)
|
||||||
|
for i, imageId := range imageIds {
|
||||||
|
s := strconv.Itoa(imageId.(int))
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ",\n"
|
||||||
|
} else {
|
||||||
|
s += "\n"
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
|
||||||
|
urlValues.Add("reason", d.Get("reason").(string))
|
||||||
|
urlValues.Add("permanently", strconv.FormatBool(d.Get("permanently").(bool)))
|
||||||
|
urlValues.Add("imageIds", temp)
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", imageDeleteImagesAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceReadListImages(d *schema.ResourceData, m interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceDeleteImagesSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"image_ids": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
MinItems: 1,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
Description: "images ids for deleting",
|
||||||
|
},
|
||||||
|
"reason": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "reason for deleting the images",
|
||||||
|
},
|
||||||
|
"permanently": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "whether to completely delete the images",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceDeleteImages() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceCreateListImages,
|
||||||
|
Read: resourceReadListImages,
|
||||||
|
Delete: resourceDeleteListImages,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: resourceDeleteImagesSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
738
decort/resource_image.go
Normal file
738
decort/resource_image.go
Normal file
@@ -0,0 +1,738 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/customdiff"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceImageCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageCreate: called for image %s", d.Get("name").(string))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
urlValues.Add("url", d.Get("url").(string))
|
||||||
|
urlValues.Add("gid", strconv.Itoa(d.Get("gid").(int)))
|
||||||
|
urlValues.Add("boottype", d.Get("boot_type").(string))
|
||||||
|
urlValues.Add("imagetype", d.Get("image_type").(string))
|
||||||
|
|
||||||
|
tstr := d.Get("drivers").([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(tstr)
|
||||||
|
for i, str := range tstr {
|
||||||
|
s := "\"" + str.(string) + "\""
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ","
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
urlValues.Add("drivers", temp)
|
||||||
|
|
||||||
|
if hotresize, ok := d.GetOk("hot_resize"); ok {
|
||||||
|
urlValues.Add("hotresize", strconv.FormatBool(hotresize.(bool)))
|
||||||
|
}
|
||||||
|
if username, ok := d.GetOk("username"); ok {
|
||||||
|
urlValues.Add("username", username.(string))
|
||||||
|
}
|
||||||
|
if password, ok := d.GetOk("password"); ok {
|
||||||
|
urlValues.Add("password", password.(string))
|
||||||
|
}
|
||||||
|
if accountId, ok := d.GetOk("account_id"); ok {
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(accountId.(int)))
|
||||||
|
}
|
||||||
|
if usernameDL, ok := d.GetOk("username_dl"); ok {
|
||||||
|
urlValues.Add("usernameDL", usernameDL.(string))
|
||||||
|
}
|
||||||
|
if passwordDL, ok := d.GetOk("password_dl"); ok {
|
||||||
|
urlValues.Add("passwordDL", passwordDL.(string))
|
||||||
|
}
|
||||||
|
if sepId, ok := d.GetOk("sep_id"); ok {
|
||||||
|
urlValues.Add("sepId", strconv.Itoa(sepId.(int)))
|
||||||
|
}
|
||||||
|
if poolName, ok := d.GetOk("pool_name"); ok {
|
||||||
|
urlValues.Add("poolName", poolName.(string))
|
||||||
|
}
|
||||||
|
if architecture, ok := d.GetOk("architecture"); ok {
|
||||||
|
urlValues.Add("architecture", architecture.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
api := ""
|
||||||
|
isSync := d.Get("sync").(bool)
|
||||||
|
if !isSync {
|
||||||
|
api = imageCreateAPI
|
||||||
|
} else {
|
||||||
|
api = imageSyncCreateAPI
|
||||||
|
}
|
||||||
|
imageId, err := controller.decortAPICall("POST", api, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(imageId)
|
||||||
|
d.Set("image_id", imageId)
|
||||||
|
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(strconv.Itoa(image.ImageId))
|
||||||
|
d.Set("bootable", image.Bootable)
|
||||||
|
//d.Set("image_id", image.ImageId)
|
||||||
|
|
||||||
|
err = resourceImageRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageRead: called for %s id: %s", d.Get("name").(string), d.Id())
|
||||||
|
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if image == nil {
|
||||||
|
d.SetId("")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("name", image.Name)
|
||||||
|
d.Set("drivers", image.Drivers)
|
||||||
|
d.Set("url", image.Url)
|
||||||
|
d.Set("gid", image.Gid)
|
||||||
|
d.Set("image_id", image.ImageId)
|
||||||
|
d.Set("boot_type", image.Boottype)
|
||||||
|
d.Set("image_type", image.Imagetype)
|
||||||
|
d.Set("bootable", image.Bootable)
|
||||||
|
d.Set("sep_id", image.SepId)
|
||||||
|
d.Set("unc_path", image.UNCPath)
|
||||||
|
d.Set("link_to", image.LinkTo)
|
||||||
|
d.Set("status", image.Status)
|
||||||
|
d.Set("tech_status", image.TechStatus)
|
||||||
|
d.Set("version", image.Version)
|
||||||
|
d.Set("size", image.Size)
|
||||||
|
d.Set("enabled", image.Enabled)
|
||||||
|
d.Set("computeci_id", image.ComputeciId)
|
||||||
|
d.Set("pool_name", image.PoolName)
|
||||||
|
d.Set("username", image.Username)
|
||||||
|
d.Set("username_dl", image.UsernameDL)
|
||||||
|
d.Set("password", image.Password)
|
||||||
|
d.Set("password_dl", image.PasswordDL)
|
||||||
|
d.Set("account_id", image.AccountId)
|
||||||
|
d.Set("guid", image.Guid)
|
||||||
|
d.Set("milestones", image.Milestones)
|
||||||
|
d.Set("provider_name", image.ProviderName)
|
||||||
|
d.Set("purge_attempts", image.PurgeAttempts)
|
||||||
|
d.Set("reference_id", image.ReferenceId)
|
||||||
|
d.Set("res_id", image.ResId)
|
||||||
|
d.Set("res_name", image.ResName)
|
||||||
|
d.Set("rescuecd", image.Rescuecd)
|
||||||
|
d.Set("architecture", image.Architecture)
|
||||||
|
d.Set("meta", flattenMeta(image.Meta))
|
||||||
|
d.Set("hot_resize", image.Hotresize)
|
||||||
|
d.Set("history", flattenHistory(image.History))
|
||||||
|
d.Set("last_modified", image.LastModified)
|
||||||
|
d.Set("desc", image.Desc)
|
||||||
|
d.Set("shared_with", image.SharedWith)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageDelete: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if image == nil {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
if reason, ok := d.GetOk("reason"); ok {
|
||||||
|
urlValues.Add("reason", reason.(string))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("reason", "")
|
||||||
|
}
|
||||||
|
if permanently, ok := d.GetOk("permanently"); ok {
|
||||||
|
urlValues.Add("permanently", strconv.FormatBool(permanently.(bool)))
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = controller.decortAPICall("POST", imageDeleteAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
log.Debugf("resourceImageExists: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if image == nil {
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageEditName(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageEditName: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
_, err := c.decortAPICall("POST", imageEditNameAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageEdit(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageEdit: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
|
||||||
|
urlValues.Add("username", d.Get("username").(string))
|
||||||
|
urlValues.Add("password", d.Get("password").(string))
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
urlValues.Add("bootable", strconv.FormatBool(d.Get("bootable").(bool)))
|
||||||
|
urlValues.Add("hotresize", strconv.FormatBool(d.Get("hot_resize").(bool)))
|
||||||
|
|
||||||
|
//_, err := c.decortAPICall("POST", imageEditAPI, urlValues)
|
||||||
|
_, err := c.decortAPICall("POST", imageEditAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
err = resourceImageRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = resourceImageRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageChangeEnabled(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
var api string
|
||||||
|
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
if d.Get("enabled").(bool) {
|
||||||
|
api = imageEnableAPI
|
||||||
|
} else {
|
||||||
|
api = imageDisableAPI
|
||||||
|
}
|
||||||
|
resp, err := c.decortAPICall("POST", api, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res, err := strconv.ParseBool(resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !res {
|
||||||
|
return errors.New("Cannot enable/disable")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageLink(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
log.Debugf("resourceVirtualImageLink: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
urlValues.Add("targetId", strconv.Itoa(d.Get("link_to").(int)))
|
||||||
|
_, err := c.decortAPICall("POST", imageLinkAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageShare(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageShare: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
accIds := d.Get("shared_with").([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(accIds)
|
||||||
|
for i, accId := range accIds {
|
||||||
|
s := strconv.Itoa(accId.(int))
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ",\n"
|
||||||
|
} else {
|
||||||
|
s += "\n"
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
urlValues.Add("accounts", temp)
|
||||||
|
_, err := c.decortAPICall("POST", imageShareAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageChangeComputeci(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
computeci := d.Get("computeci_id").(int)
|
||||||
|
|
||||||
|
api := ""
|
||||||
|
|
||||||
|
if computeci == 0 {
|
||||||
|
api = imageComputeciUnsetAPI
|
||||||
|
} else {
|
||||||
|
urlValues.Add("computeciId", strconv.Itoa(computeci))
|
||||||
|
api = imageComputeciSetAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", api, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageUpdateNodes(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageUpdateNodes: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
enabledStacks := d.Get("enabled_stacks").([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(enabledStacks)
|
||||||
|
for i, stackId := range enabledStacks {
|
||||||
|
s := stackId.(string)
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ","
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
urlValues.Add("enabledStacks", temp)
|
||||||
|
_, err := c.decortAPICall("POST", imageUpdateNodesAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Name of the rescue disk",
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "URL where to download media from",
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "grid (platform) ID where this template should be create in",
|
||||||
|
},
|
||||||
|
"boot_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Boot type of image bios or uefi",
|
||||||
|
},
|
||||||
|
"image_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Image type linux, windows or other",
|
||||||
|
},
|
||||||
|
"drivers": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Required: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "List of types of compute suitable for image. Example: [ \"KVM_X86\" ]",
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "meta",
|
||||||
|
},
|
||||||
|
"hot_resize": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this machine supports hot resize",
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional username for the image",
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional password for the image",
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "AccountId to make the image exclusive",
|
||||||
|
},
|
||||||
|
"username_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "username for upload binary media",
|
||||||
|
},
|
||||||
|
"password_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "password for upload binary media",
|
||||||
|
},
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "storage endpoint provider ID",
|
||||||
|
},
|
||||||
|
"pool_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "pool for image create",
|
||||||
|
},
|
||||||
|
"architecture": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "binary architecture of this image, one of X86_64 of PPC64_LE",
|
||||||
|
},
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image id",
|
||||||
|
},
|
||||||
|
"permanently": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Whether to completely delete the image",
|
||||||
|
},
|
||||||
|
"bootable": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this image boot OS",
|
||||||
|
},
|
||||||
|
"unc_path": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "unc path",
|
||||||
|
},
|
||||||
|
"link_to": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "",
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "status",
|
||||||
|
},
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "tech atatus",
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "version",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image size",
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"computeci_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"provider_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"purge_attempts": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reference_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rescuecd": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reason": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"last_modified": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"shared_with": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sync": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "Create image from a media identified by URL (in synchronous mode)",
|
||||||
|
},
|
||||||
|
"enabled_stacks": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImage() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceImageCreate,
|
||||||
|
Read: resourceImageRead,
|
||||||
|
Update: resourceImageEdit,
|
||||||
|
Delete: resourceImageDelete,
|
||||||
|
Exists: resourceImageExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
CustomizeDiff: customdiff.All(
|
||||||
|
customdiff.IfValueChange("enabled", func(old, new, meta interface{}) bool {
|
||||||
|
if old.(bool) != new.(bool) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageChangeEnabled),
|
||||||
|
customdiff.IfValueChange("name", func(old, new, meta interface{}) bool {
|
||||||
|
if old.(string) != new.(string) && old.(string) != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageEditName),
|
||||||
|
customdiff.IfValueChange("shared_with", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.([]interface{})
|
||||||
|
n := new.([]interface{})
|
||||||
|
|
||||||
|
if len(o) != len(n) {
|
||||||
|
return true
|
||||||
|
} else if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
for i, v := range n {
|
||||||
|
if v.(int) == o[i].(int) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if count == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageShare),
|
||||||
|
customdiff.IfValueChange("computeci_id", func(old, new, meta interface{}) bool {
|
||||||
|
if old.(int) != new.(int) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageChangeComputeci),
|
||||||
|
customdiff.IfValueChange("enabled_stacks", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.([]interface{})
|
||||||
|
n := new.([]interface{})
|
||||||
|
|
||||||
|
if len(o) != len(n) {
|
||||||
|
return true
|
||||||
|
} else if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
for i, v := range n {
|
||||||
|
if v.(string) == o[i].(string) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if count == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageUpdateNodes),
|
||||||
|
),
|
||||||
|
|
||||||
|
Schema: resourceImageSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenMeta(m []interface{}) []string {
|
||||||
|
output := []string{}
|
||||||
|
for _, item := range m {
|
||||||
|
switch d := item.(type) {
|
||||||
|
case string:
|
||||||
|
output = append(output, d)
|
||||||
|
case int:
|
||||||
|
output = append(output, strconv.Itoa(d))
|
||||||
|
case int64:
|
||||||
|
output = append(output, strconv.FormatInt(d, 10))
|
||||||
|
case float64:
|
||||||
|
output = append(output, strconv.FormatInt(int64(d), 10))
|
||||||
|
default:
|
||||||
|
output = append(output, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenHistory(history []History) []map[string]interface{} {
|
||||||
|
temp := make([]map[string]interface{}, 0)
|
||||||
|
for _, item := range history {
|
||||||
|
t := map[string]interface{}{
|
||||||
|
"id": item.Id,
|
||||||
|
"guid": item.Guid,
|
||||||
|
"timestamp": item.Timestamp,
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = append(temp, t)
|
||||||
|
}
|
||||||
|
return temp
|
||||||
|
}
|
||||||
402
decort/resource_virtual_image.go
Normal file
402
decort/resource_virtual_image.go
Normal file
@@ -0,0 +1,402 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/customdiff"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceVirtualImageCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageCreate: called for image %s", d.Get("name").(string))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
urlValues.Add("targetId", strconv.Itoa(d.Get("target_id").(int)))
|
||||||
|
|
||||||
|
imageId, err := controller.decortAPICall("POST", imageCreateVirtualAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(imageId)
|
||||||
|
d.Set("image_id", imageId)
|
||||||
|
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(strconv.Itoa(image.ImageId))
|
||||||
|
d.Set("bootable", image.Bootable)
|
||||||
|
//d.Set("image_id", image.ImageId)
|
||||||
|
|
||||||
|
err = resourceImageRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVirtualImageSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "name of the virtual image to create",
|
||||||
|
},
|
||||||
|
"target_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "ID of real image to link this virtual image to upon creation",
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "URL where to download media from",
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "grid (platform) ID where this template should be create in",
|
||||||
|
},
|
||||||
|
"boot_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Boot type of image bios or uefi",
|
||||||
|
},
|
||||||
|
"image_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Image type linux, windows or other",
|
||||||
|
},
|
||||||
|
"drivers": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "List of types of compute suitable for image. Example: [ \"KVM_X86\" ]",
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "meta",
|
||||||
|
},
|
||||||
|
"hot_resize": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this machine supports hot resize",
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional username for the image",
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional password for the image",
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "AccountId to make the image exclusive",
|
||||||
|
},
|
||||||
|
"username_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "username for upload binary media",
|
||||||
|
},
|
||||||
|
"password_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "password for upload binary media",
|
||||||
|
},
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "storage endpoint provider ID",
|
||||||
|
},
|
||||||
|
"pool_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "pool for image create",
|
||||||
|
},
|
||||||
|
"architecture": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "binary architecture of this image, one of X86_64 of PPC64_LE",
|
||||||
|
},
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image id",
|
||||||
|
},
|
||||||
|
"permanently": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Whether to completely delete the image",
|
||||||
|
},
|
||||||
|
"bootable": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this image boot OS",
|
||||||
|
},
|
||||||
|
"unc_path": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "unc path",
|
||||||
|
},
|
||||||
|
"link_to": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "",
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "status",
|
||||||
|
},
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "tech atatus",
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "version",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image size",
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"computeci_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"provider_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"purge_attempts": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reference_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rescuecd": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reason": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"last_modified": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"enabled_stacks": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"shared_with": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVirtualImage() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceVirtualImageCreate,
|
||||||
|
Read: resourceImageRead,
|
||||||
|
Update: resourceImageEdit,
|
||||||
|
Delete: resourceImageDelete,
|
||||||
|
Exists: resourceImageExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
CustomizeDiff: customdiff.All(
|
||||||
|
customdiff.IfValueChange("enabled", func(old, new, meta interface{}) bool {
|
||||||
|
if old.(bool) != new.(bool) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageChangeEnabled),
|
||||||
|
customdiff.IfValueChange("link_to", func(old, new, meta interface{}) bool {
|
||||||
|
if old.(int) != new.(int) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageLink),
|
||||||
|
customdiff.IfValueChange("name", func(old, new, meta interface{}) bool {
|
||||||
|
if old.(string) != new.(string) && old.(string) != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageEditName),
|
||||||
|
customdiff.IfValueChange("shared_with", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.([]interface{})
|
||||||
|
n := new.([]interface{})
|
||||||
|
|
||||||
|
if len(o) != len(n) {
|
||||||
|
return true
|
||||||
|
} else if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
for i, v := range n {
|
||||||
|
if v.(int) == o[i].(int) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if count == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageShare),
|
||||||
|
customdiff.IfValueChange("computeci_id", func(old, new, meta interface{}) bool {
|
||||||
|
if old.(int) != new.(int) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageChangeComputeci),
|
||||||
|
customdiff.IfValueChange("enabled_stacks", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.([]interface{})
|
||||||
|
n := new.([]interface{})
|
||||||
|
|
||||||
|
if len(o) != len(n) {
|
||||||
|
return true
|
||||||
|
} else if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
for i, v := range n {
|
||||||
|
if v.(string) == o[i].(string) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if count == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceImageUpdateNodes),
|
||||||
|
),
|
||||||
|
|
||||||
|
Schema: resourceVirtualImageSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
62
decort/utility_grid.go
Normal file
62
decort/utility_grid.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityGridCheckPresence(d *schema.ResourceData, m interface{}) (*Grid, error) {
|
||||||
|
grid := &Grid{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
if gridId, ok := d.GetOk("grid_id"); ok {
|
||||||
|
urlValues.Add("gridId", strconv.Itoa(gridId.(int)))
|
||||||
|
} else {
|
||||||
|
return nil, errors.New(fmt.Sprintf("grid_id is required"))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityGridCheckPresence: load grid")
|
||||||
|
gridRaw, err := controller.decortAPICall("POST", GridGetAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(gridRaw), grid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return grid, nil
|
||||||
|
}
|
||||||
61
decort/utility_grid_list.go
Normal file
61
decort/utility_grid_list.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityGridListCheckPresence(d *schema.ResourceData, m interface{}) (GridList, error) {
|
||||||
|
gridList := GridList{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
if page, ok := d.GetOk("page"); ok {
|
||||||
|
urlValues.Add("page", strconv.Itoa(page.(int)))
|
||||||
|
}
|
||||||
|
if size, ok := d.GetOk("size"); ok {
|
||||||
|
urlValues.Add("size", strconv.Itoa(size.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityGridListCheckPresence: load grid list")
|
||||||
|
gridListRaw, err := controller.decortAPICall("POST", GridListGetAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(gridListRaw), &gridList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gridList, nil
|
||||||
|
}
|
||||||
62
decort/utility_image.go
Normal file
62
decort/utility_image.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityImageCheckPresence(d *schema.ResourceData, m interface{}) (*Image, error) {
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
if (strconv.Itoa(d.Get("image_id").(int))) != "0" {
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("imageId", d.Id())
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := controller.decortAPICall("POST", imageGetAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
image := &Image{}
|
||||||
|
if err := json.Unmarshal([]byte(resp), image); err != nil {
|
||||||
|
return nil, errors.New(fmt.Sprint("Can not unmarshall data to image: ", resp, " ", image))
|
||||||
|
}
|
||||||
|
|
||||||
|
return image, nil
|
||||||
|
}
|
||||||
68
decort/utility_image_list.go
Normal file
68
decort/utility_image_list.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityImageListCheckPresence(d *schema.ResourceData, m interface{}) (ImageList, error) {
|
||||||
|
imageList := ImageList{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
if sepId, ok := d.GetOk("sep_id"); ok {
|
||||||
|
urlValues.Add("sepId", strconv.Itoa(sepId.(int)))
|
||||||
|
}
|
||||||
|
if sharedWith, ok := d.GetOk("shared_with"); ok {
|
||||||
|
urlValues.Add("sharedWith", strconv.Itoa(sharedWith.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if page, ok := d.GetOk("page"); ok {
|
||||||
|
urlValues.Add("page", strconv.Itoa(page.(int)))
|
||||||
|
}
|
||||||
|
if size, ok := d.GetOk("size"); ok {
|
||||||
|
urlValues.Add("size", strconv.Itoa(size.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityImageListCheckPresence: load image list")
|
||||||
|
imageListRaw, err := controller.decortAPICall("POST", imageListGetAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(imageListRaw), &imageList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return imageList, nil
|
||||||
|
}
|
||||||
56
decort/utility_image_list_stacks.go
Normal file
56
decort/utility_image_list_stacks.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityImageListStacksCheckPresence(d *schema.ResourceData, m interface{}) (ImageListStacks, error) {
|
||||||
|
imageListStacks := ImageListStacks{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
|
||||||
|
log.Debugf("utilityImageListStacksCheckPresence: load image list")
|
||||||
|
imageListRaw, err := controller.decortAPICall("POST", imageListStacksApi, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(imageListRaw), &imageListStacks)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return imageListStacks, nil
|
||||||
|
}
|
||||||
2
go.mod
2
go.mod
@@ -4,7 +4,7 @@ go 1.15
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
github.com/google/uuid v1.1.2
|
github.com/google/uuid v1.3.0
|
||||||
github.com/hashicorp/terraform-plugin-docs v0.5.1
|
github.com/hashicorp/terraform-plugin-docs v0.5.1
|
||||||
github.com/hashicorp/terraform-plugin-sdk v1.16.0
|
github.com/hashicorp/terraform-plugin-sdk v1.16.0
|
||||||
github.com/sirupsen/logrus v1.7.0
|
github.com/sirupsen/logrus v1.7.0
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -171,6 +171,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
|
|||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
|||||||
Reference in New Issue
Block a user