gos_tech_4.4.3 4.4.4
nlloskutova 11 months ago
parent ce4b847596
commit 0faa6cbbd1

@ -1,6 +1,20 @@
## Version 4.4.3 ## Version 4.4.4
### Bugfix ### Bugfix
- Fixed panic - Changed field Value in schema resource kvmvm in blocks affinity_rules and anti_affinity_rules from required to optional in cloudapi
- Fixed field description in cloudapi/kvmvm/resource_compute - Changed the format ID in resource k8s_wg from wg_id to k8s_id#wg_id
- Fixed field owner in request create lb in cloudapi/cloudbroker - Fixed scripts intall.bat and intall.sh
- Change logic from disk delete and disk add to disk rename when disk.disk_name field is changed in resource cloudapi/kvmvm
- Fix allowed network plugin value from "weawenet" to "weavenet" for k8ci, k8s resources in cloudbroker and for k8s resource in cloudapi
- Fix bug with deleting decort_bservice resource when setting enable=false in cloudapi/bservice
- Fix panic in data source decort_bservice_snapshot_list in cloudapi/bservice
- Fix panic in data source decort_rg_affinity_groups_list in cloudapi/rg
- Fix duplicate enabling of bservice after create in cloudapi/bservice
- Fix start of bservice after create in cloudapi/b
- Fix permanently field for disks delete, change default value from true to false in decort_kvmvm in cloudapi/kvmvm
### Feature
- Add "permanently" flag in k8s, k8s_cp in cloudapi
- Add RAM validation in cloudapi/[k8s, k8s_cp, k8s_wg, kvmvm, bservice]
- Add RAM validation in cloudbroker/[k8s, k8s_wg, kvmvm]
- Add field restore in cloudapi/disk resource

@ -7,7 +7,7 @@ ZIPDIR = ./zip
BINARY=${NAME} BINARY=${NAME}
WORKPATH= ./examples/terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAMESPACE}/${VERSION}/${OS_ARCH} WORKPATH= ./examples/terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAMESPACE}/${VERSION}/${OS_ARCH}
MAINPATH = ./cmd/decort/ MAINPATH = ./cmd/decort/
VERSION=4.4.3 VERSION=4.4.4
OS_ARCH=$(shell go env GOHOSTOS)_$(shell go env GOHOSTARCH) OS_ARCH=$(shell go env GOHOSTOS)_$(shell go env GOHOSTARCH)
FILES = ${BINARY}_${VERSION}_darwin_amd64\ FILES = ${BINARY}_${VERSION}_darwin_amd64\

@ -8,7 +8,7 @@ require (
github.com/hashicorp/terraform-plugin-sdk/v2 v2.30.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.30.0
github.com/sirupsen/logrus v1.9.0 github.com/sirupsen/logrus v1.9.0
golang.org/x/net v0.17.0 golang.org/x/net v0.17.0
repository.basistech.ru/BASIS/decort-golang-sdk v1.6.10 repository.basistech.ru/BASIS/decort-golang-sdk v1.6.14
) )
require ( require (

@ -285,5 +285,5 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
repository.basistech.ru/BASIS/decort-golang-sdk v1.6.10 h1:3DSdLI1exX+QFO9FKmpw5r7duOKI1rITqSBsTYFdSyw= repository.basistech.ru/BASIS/decort-golang-sdk v1.6.14 h1:FSu4kPKHsrmZpYIUKlX0s4v53CGmmT2Ne2uWuiRh6pM=
repository.basistech.ru/BASIS/decort-golang-sdk v1.6.10/go.mod h1:szsTGa73O75ckCWVGJPvTtRbhA/ubuYrYhMkPjvHlmE= repository.basistech.ru/BASIS/decort-golang-sdk v1.6.14/go.mod h1:szsTGa73O75ckCWVGJPvTtRbhA/ubuYrYhMkPjvHlmE=

@ -37,3 +37,6 @@ const MaxCpusPerCompute = 128
// MinRamPerCompute sets minimum amount of RAM per compute in MB // MinRamPerCompute sets minimum amount of RAM per compute in MB
const MinRamPerCompute = 128 const MinRamPerCompute = 128
// RAMDivisibility sets divisibility of RAM value
const RAMDivisibility = 128

@ -1,105 +1,105 @@
/* /*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved. Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors: Authors:
Petr Krutov, <petr.krutov@digitalenergy.online> Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online> Stanislav Solovev, <spsolovev@digitalenergy.online>
Kasim Baybikov, <kmbaybikov@basistech.ru> Kasim Baybikov, <kmbaybikov@basistech.ru>
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.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
/* /*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp. Orchestration Technology) with Terraform by Hashicorp.
Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort
Please see README.md to learn where to place source code so that it Please see README.md to learn where to place source code so that it
builds seamlessly. builds seamlessly.
Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki
*/ */
package bservice package bservice
import ( import (
"context" "context"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
) )
func dataSourceBasicServiceSnapshotListRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { func dataSourceBasicServiceSnapshotListRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
basicServiceSnapshotList, err := utilityBasicServiceSnapshotListCheckPresence(ctx, d, m) basicServiceSnapshotList, err := utilityBasicServiceSnapshotListCheckPresence(ctx, d, m)
if err != nil { if err != nil {
return diag.FromErr(err) return diag.FromErr(err)
} }
id := uuid.New() id := uuid.New()
d.SetId(id.String()) d.SetId(id.String())
d.Set("items", flattenBasicServiceSnapshots(basicServiceSnapshotList)) d.Set("items", flattenBasicServiceSnapshots(basicServiceSnapshotList.Data))
return nil return nil
} }
func dataSourceBasicServiceSnapshotListSchemaMake() map[string]*schema.Schema { func dataSourceBasicServiceSnapshotListSchemaMake() map[string]*schema.Schema {
res := map[string]*schema.Schema{ res := map[string]*schema.Schema{
"service_id": { "service_id": {
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
Description: "ID of the BasicService instance", Description: "ID of the BasicService instance",
}, },
"items": { "items": {
Type: schema.TypeList, Type: schema.TypeList,
Computed: true, Computed: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"guid": { "guid": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
}, },
"label": { "label": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
}, },
"timestamp": { "timestamp": {
Type: schema.TypeInt, Type: schema.TypeInt,
Computed: true, Computed: true,
}, },
"valid": { "valid": {
Type: schema.TypeBool, Type: schema.TypeBool,
Computed: true, Computed: true,
}, },
}, },
}, },
}, },
} }
return res return res
} }
func DataSourceBasicServiceSnapshotList() *schema.Resource { func DataSourceBasicServiceSnapshotList() *schema.Resource {
return &schema.Resource{ return &schema.Resource{
SchemaVersion: 1, SchemaVersion: 1,
ReadContext: dataSourceBasicServiceSnapshotListRead, ReadContext: dataSourceBasicServiceSnapshotListRead,
Timeouts: &schema.ResourceTimeout{ Timeouts: &schema.ResourceTimeout{
Read: &constants.Timeout30s, Read: &constants.Timeout30s,
Default: &constants.Timeout60s, Default: &constants.Timeout60s,
}, },
Schema: dataSourceBasicServiceSnapshotListSchemaMake(), Schema: dataSourceBasicServiceSnapshotListSchemaMake(),
} }
} }

@ -34,14 +34,17 @@ package bservice
import ( import (
"context" "context"
"errors"
"strconv" "strconv"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/bservice" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/bservice"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/dc"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/status" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/status"
) )
@ -83,6 +86,8 @@ func resourceBasicServiceCreate(ctx context.Context, d *schema.ResourceData, m i
return diag.FromErr(err) return diag.FromErr(err)
} }
warnings := dc.Warnings{}
if d.Get("enable").(bool) && (service.Status == status.Disabled || service.Status == status.Created) { if d.Get("enable").(bool) && (service.Status == status.Disabled || service.Status == status.Created) {
log.Debugf("trying to enable bservice %v", serviceId) log.Debugf("trying to enable bservice %v", serviceId)
_, err := c.CloudAPI().BService().Enable(ctx, bservice.EnableRequest{ _, err := c.CloudAPI().BService().Enable(ctx, bservice.EnableRequest{
@ -90,21 +95,29 @@ func resourceBasicServiceCreate(ctx context.Context, d *schema.ResourceData, m i
}) })
if err != nil { if err != nil {
return diag.FromErr(err) warnings.Add(err)
} }
} }
if d.Get("start").(bool) && d.Get("enable").(bool) {
if d.Get("start").(bool) {
log.Debugf("trying to start bservice %v", serviceId) log.Debugf("trying to start bservice %v", serviceId)
_, err := c.CloudAPI().BService().Enable(ctx, bservice.EnableRequest{
ServiceID: serviceId,
})
if err != nil { if !d.Get("enable").(bool) {
return diag.FromErr(err) warnings.Add(errors.New("can not start bservice that is not enabled. Set enable = true and start = true to enable and start bservice"))
}
if d.Get("enable").(bool) {
_, err := c.CloudAPI().BService().Start(ctx, bservice.StartRequest{
ServiceID: serviceId,
})
if err != nil {
warnings.Add(err)
}
} }
} }
return resourceBasicServiceRead(ctx, d, m) return append(warnings.Get(), resourceBasicServiceRead(ctx, d, m)...)
} }
func resourceBasicServiceRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { func resourceBasicServiceRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
@ -230,25 +243,39 @@ func resourceBasicServiceUpdate(ctx context.Context, d *schema.ResourceData, m i
case status.Disabling: case status.Disabling:
log.Debugf("The basic service is in status: %s, troubles can occur with the update.", bs.Status) log.Debugf("The basic service is in status: %s, troubles can occur with the update.", bs.Status)
case status.Deleted: case status.Deleted:
id, _ := strconv.ParseUint(d.Id(), 10, 64) if d.Get("restore").(bool) {
restoreReq := bservice.RestoreRequest{ id, _ := strconv.ParseUint(d.Id(), 10, 64)
ServiceID: id, restoreReq := bservice.RestoreRequest{
} ServiceID: id,
enableReq := bservice.EnableRequest{ }
ServiceID: id,
}
_, err := c.CloudAPI().BService().Restore(ctx, restoreReq) _, err := c.CloudAPI().BService().Restore(ctx, restoreReq)
if err != nil { if err != nil {
return diag.FromErr(err) return diag.FromErr(err)
} }
_, err = c.CloudAPI().BService().Enable(ctx, enableReq) hasChanged = true
if err != nil {
return diag.FromErr(err) if d.Get("enable").(bool) {
} _, err := c.CloudAPI().BService().Enable(ctx, bservice.EnableRequest{
ServiceID: id,
})
if err != nil {
return diag.FromErr(err)
}
}
hasChanged = true if d.Get("start").(bool) {
_, err := c.CloudAPI().BService().Start(ctx, bservice.StartRequest{
ServiceID: id,
})
if err != nil {
return diag.FromErr(err)
}
}
}
case status.Deleting: case status.Deleting:
case status.Destroyed: case status.Destroyed:
d.SetId("") d.SetId("")
@ -291,19 +318,6 @@ func resourceBasicServiceUpdate(ctx context.Context, d *schema.ResourceData, m i
} }
} }
if d.HasChange("restore") {
restore := d.Get("restore").(bool)
if restore {
req := bservice.RestoreRequest{
ServiceID: uint64(d.Get("service_id").(int)),
}
_, err := c.CloudAPI().BService().Restore(ctx, req)
if err != nil {
return diag.FromErr(err)
}
}
}
if d.HasChange("start") { if d.HasChange("start") {
start := d.Get("start").(bool) start := d.Get("start").(bool)
if start { if start {

@ -43,6 +43,7 @@ import (
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/bservice" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/bservice"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/validators"
) )
func resourceBasicServiceGroupCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { func resourceBasicServiceGroupCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
@ -107,12 +108,12 @@ func resourceBasicServiceGroupCreate(ctx context.Context, d *schema.ResourceData
d.SetId(strconv.FormatUint(compgroupId, 10)) d.SetId(strconv.FormatUint(compgroupId, 10))
d.Set("compgroup_id", compgroupId) d.Set("compgroup_id", compgroupId)
serviceId:= uint64(d.Get("service_id").(int)) serviceId := uint64(d.Get("service_id").(int))
if d.Get("start").(bool) { if d.Get("start").(bool) {
log.Debugf("trying to start bservice group %v", compgroupId) log.Debugf("trying to start bservice group %v", compgroupId)
_, err := c.CloudAPI().BService().GroupStart(ctx, bservice.GroupStartRequest{ _, err := c.CloudAPI().BService().GroupStart(ctx, bservice.GroupStartRequest{
ServiceID: serviceId, ServiceID: serviceId,
CompGroupID: compgroupId, CompGroupID: compgroupId,
}) })
@ -371,8 +372,12 @@ func resourceBasicServiceGroupSchemaMake() map[string]*schema.Schema {
Description: "compute CPU number. All computes in the group have the same CPU count", Description: "compute CPU number. All computes in the group have the same CPU count",
}, },
"ram": { "ram": {
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
ValidateFunc: validation.All(
validation.IntAtLeast(constants.MinRamPerCompute),
validators.DivisibleBy(constants.RAMDivisibility),
),
Description: "compute RAM volume in MB. All computes in the group have the same RAM volume", Description: "compute RAM volume in MB. All computes in the group have the same RAM volume",
}, },
"disk": { "disk": {

@ -1,64 +1,64 @@
/* /*
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved. Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors: Authors:
Petr Krutov, <petr.krutov@digitalenergy.online> Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online> Stanislav Solovev, <spsolovev@digitalenergy.online>
Kasim Baybikov, <kmbaybikov@basistech.ru> Kasim Baybikov, <kmbaybikov@basistech.ru>
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.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
/* /*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp. Orchestration Technology) with Terraform by Hashicorp.
Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort
Please see README.md to learn where to place source code so that it Please see README.md to learn where to place source code so that it
builds seamlessly. builds seamlessly.
Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki
*/ */
package bservice package bservice
import ( import (
"context" "context"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/bservice" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/bservice"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
) )
func utilityBasicServiceSnapshotListCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (bservice.ListSnapshots, error) { func utilityBasicServiceSnapshotListCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (*bservice.ListInfoSnapshots, error) {
c := m.(*controller.ControllerCfg) c := m.(*controller.ControllerCfg)
var id uint64 var id uint64
if serviceId, ok := d.GetOk("service_id"); ok { if serviceId, ok := d.GetOk("service_id"); ok {
id = uint64(serviceId.(int)) id = uint64(serviceId.(int))
} }
req := bservice.SnapshotListRequest{ req := bservice.SnapshotListRequest{
ServiceID: id, ServiceID: id,
} }
log.Debugf("utilityBasicServiceSnapshotListCheckPresence") log.Debugf("utilityBasicServiceSnapshotListCheckPresence")
basicServiceSnapshotList, err := c.CloudAPI().BService().SnapshotList(ctx, req) basicServiceSnapshotList, err := c.CloudAPI().BService().SnapshotList(ctx, req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return basicServiceSnapshotList, nil return basicServiceSnapshotList, nil
} }

@ -231,20 +231,23 @@ func resourceDiskUpdate(ctx context.Context, d *schema.ResourceData, m interface
return diag.Errorf("The resource cannot be updated because it has been destroyed") return diag.Errorf("The resource cannot be updated because it has been destroyed")
// return resourceDiskCreate(ctx, d, m) // return resourceDiskCreate(ctx, d, m)
case status.Deleted: case status.Deleted:
hasChangeState = true if restore, ok:= d.GetOk("restore"); ok && restore.(bool) {
req := disks.RestoreRequest{ hasChangeState = true
DiskID: disk.ID, req := disks.RestoreRequest{
} DiskID: disk.ID,
}
if reason, ok := d.GetOk("reason"); ok {
req.Reason = reason.(string) if reason, ok := d.GetOk("reason"); ok {
} else { req.Reason = reason.(string)
req.Reason = "Terraform automatic restore" } else {
} req.Reason = "Terraform automatic restore"
}
_, err := c.CloudAPI().Disks().Restore(ctx, req)
if err != nil {
warnings.Add(err)
}
_, err := c.CloudAPI().Disks().Restore(ctx, req)
if err != nil {
warnings.Add(err)
} }
case status.Assigned: case status.Assigned:
case status.Modeled: case status.Modeled:
@ -357,10 +360,18 @@ func resourceDiskDelete(ctx context.Context, d *schema.ResourceData, m interface
} }
req := disks.DeleteRequest{ req := disks.DeleteRequest{
DiskID: disk.ID, DiskID: disk.ID,
Detach: d.Get("detach").(bool), }
Permanently: d.Get("permanently").(bool),
Reason: d.Get("reason").(string), if detach, ok := d.GetOk("detach"); ok {
req.Detach = detach.(bool)
}
if permanently, ok := d.GetOk("permanently"); ok {
req.Permanently = permanently.(bool)
}
if reason, ok := d.GetOk("reason"); ok {
req.Reason = reason.(string)
} }
c := m.(*controller.ControllerCfg) c := m.(*controller.ControllerCfg)
@ -446,6 +457,11 @@ func resourceDiskSchemaMake() map[string]*schema.Schema {
Optional: true, Optional: true,
Computed: true, Computed: true,
}, },
"restore": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"iotune": { "iotune": {
Type: schema.TypeList, Type: schema.TypeList,
Optional: true, Optional: true,

@ -35,6 +35,8 @@ package k8s
import ( import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/validators"
) )
func nodeMasterDefault() K8sNodeRecord { func nodeMasterDefault() K8sNodeRecord {
@ -85,21 +87,25 @@ func mastersSchemaMake() map[string]*schema.Schema {
Optional: true, Optional: true,
} }
masters["cpu"] = &schema.Schema{ masters["cpu"] = &schema.Schema{
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
ForceNew: true, //ForceNew: true,
Description: "Node CPU count.", Description: "Node CPU count.",
} }
masters["ram"] = &schema.Schema{ masters["ram"] = &schema.Schema{
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
ForceNew: true, //ForceNew: true,
ValidateFunc: validation.All(
validation.IntAtLeast(constants.MinRamPerCompute),
validators.DivisibleBy(constants.RAMDivisibility),
),
Description: "Node RAM in MB.", Description: "Node RAM in MB.",
} }
masters["disk"] = &schema.Schema{ masters["disk"] = &schema.Schema{
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
ForceNew: true, //ForceNew: true,
Description: "Node boot disk size in GB.", Description: "Node boot disk size in GB.",
} }
@ -117,7 +123,11 @@ func workersSchemaMake() map[string]*schema.Schema {
Required: true, Required: true,
}, },
"ram": { "ram": {
Type: schema.TypeInt, Type: schema.TypeInt,
ValidateFunc: validation.All(
validation.IntAtLeast(constants.MinRamPerCompute),
validators.DivisibleBy(constants.RAMDivisibility),
),
Required: true, Required: true,
}, },
"cpu": { "cpu": {

@ -513,6 +513,7 @@ func resourceK8sUpdate(ctx context.Context, d *schema.ResourceData, m interface{
} }
func resourceK8sDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { func resourceK8sDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceK8sDelete: called with id %s, rg %d", d.Id(), d.Get("rg_id").(int)) log.Debugf("resourceK8sDelete: called with id %s, rg %d", d.Id(), d.Get("rg_id").(int))
cluster, err := utilityK8sCheckPresence(ctx, d, m) cluster, err := utilityK8sCheckPresence(ctx, d, m)
@ -520,12 +521,14 @@ func resourceK8sDelete(ctx context.Context, d *schema.ResourceData, m interface{
return diag.FromErr(err) return diag.FromErr(err)
} }
c := m.(*controller.ControllerCfg) req := k8s.DeleteRequest{K8SID: cluster.ID}
req := k8s.DeleteRequest{
K8SID: cluster.ID, if val, ok := d.GetOk("permanently"); ok {
Permanently: true, req.Permanently = val.(bool)
} }
c := m.(*controller.ControllerCfg)
_, err = c.CloudAPI().K8S().Delete(ctx, req) _, err = c.CloudAPI().K8S().Delete(ctx, req)
if err != nil { if err != nil {
return diag.FromErr(err) return diag.FromErr(err)
@ -679,8 +682,6 @@ func resourceK8sSchemaMake() map[string]*schema.Schema {
Optional: true, Optional: true,
Description: "insert ssl certificate in x509 pem format", Description: "insert ssl certificate in x509 pem format",
}, },
////
"desc": { "desc": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
@ -741,6 +742,13 @@ func resourceK8sSchemaMake() map[string]*schema.Schema {
Computed: true, Computed: true,
Description: "IP address of default load balancer.", Description: "IP address of default load balancer.",
}, },
"permanently": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Determines if cluster should be destroyed",
},
"rg_name": { "rg_name": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,

@ -52,6 +52,7 @@ import (
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/dc" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/dc"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/status" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/status"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/validators"
) )
func resourceK8sCPCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { func resourceK8sCPCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
@ -530,25 +531,29 @@ func resourceK8sCPUpdate(ctx context.Context, d *schema.ResourceData, m interfac
} }
func resourceK8sCPDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { func resourceK8sCPDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceK8sControlPlaneDelete: called with id %s, rg %d", d.Id(), d.Get("rg_id").(int))
log.Debugf("resourceK8sDelete: called with id %s, rg %d", d.Id(), d.Get("rg_id").(int))
cluster, err := utilityK8sCheckPresence(ctx, d, m) cluster, err := utilityK8sCheckPresence(ctx, d, m)
if err != nil { if err != nil {
return diag.FromErr(err) return diag.FromErr(err)
} }
c := m.(*controller.ControllerCfg) req := k8s.DeleteRequest{K8SID: cluster.ID}
req := k8s.DeleteRequest{
K8SID: cluster.ID, if val, ok := d.GetOk("permanently"); ok {
Permanently: true, req.Permanently = val.(bool)
} }
c := m.(*controller.ControllerCfg)
_, err = c.CloudAPI().K8S().Delete(ctx, req) _, err = c.CloudAPI().K8S().Delete(ctx, req)
if err != nil { if err != nil {
return diag.FromErr(err) return diag.FromErr(err)
} }
return nil return nil
} }
func resourceK8sCPSchemaMake() map[string]*schema.Schema { func resourceK8sCPSchemaMake() map[string]*schema.Schema {
@ -590,9 +595,13 @@ func resourceK8sCPSchemaMake() map[string]*schema.Schema {
Description: "Node CPU count.", Description: "Node CPU count.",
}, },
"ram": { "ram": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Computed: true, Computed: true,
ValidateFunc: validation.All(
validation.IntAtLeast(constants.MinRamPerCompute),
validators.DivisibleBy(constants.RAMDivisibility),
),
Description: "Node RAM in MB.", Description: "Node RAM in MB.",
}, },
"disk": { "disk": {
@ -679,6 +688,13 @@ func resourceK8sCPSchemaMake() map[string]*schema.Schema {
Optional: true, Optional: true,
Description: "insert ssl certificate in x509 pem format", Description: "insert ssl certificate in x509 pem format",
}, },
"permanently": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Determines if cluster should be destroyed",
},
//// ////
"extnet_id": { "extnet_id": {
Type: schema.TypeInt, Type: schema.TypeInt,

@ -34,16 +34,19 @@ package k8s
import ( import (
"context" "context"
"fmt"
"strconv" "strconv"
"strings" "strings"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/compute" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/compute"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/k8s" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/k8s"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/validators"
) )
func resourceK8sWgCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { func resourceK8sWgCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
@ -101,7 +104,7 @@ func resourceK8sWgCreate(ctx context.Context, d *schema.ResourceData, m interfac
return diag.FromErr(err) return diag.FromErr(err)
} }
d.SetId(strconv.FormatUint(resp, 10)) d.SetId(fmt.Sprintf("%d#%d", d.Get("k8s_id").(int), resp))
return resourceK8sWgRead(ctx, d, m) return resourceK8sWgRead(ctx, d, m)
} }
@ -125,7 +128,7 @@ func resourceK8sWgRead(ctx context.Context, d *schema.ResourceData, m interface{
d.Set("wg_id", wg.ID) d.Set("wg_id", wg.ID)
if strings.Contains(d.Id(), "#") { if strings.Contains(d.Id(), "#") {
k8sId, err := strconv.Atoi(strings.Split(d.Id(), "#")[1]) k8sId, err := strconv.Atoi(strings.Split(d.Id(), "#")[0])
if err != nil { if err != nil {
return diag.FromErr(err) return diag.FromErr(err)
} }
@ -134,8 +137,7 @@ func resourceK8sWgRead(ctx context.Context, d *schema.ResourceData, m interface{
} else { } else {
d.Set("k8s_id", d.Get("k8s_id")) d.Set("k8s_id", d.Get("k8s_id"))
} }
d.SetId(fmt.Sprintf("%d#%d", d.Get("k8s_id").(int), wg.ID))
d.SetId(strings.Split(d.Id(), "#")[0])
flattenWg(d, *wg, workersComputeList) flattenWg(d, *wg, workersComputeList)
@ -161,11 +163,10 @@ func resourceK8sWgUpdate(ctx context.Context, d *schema.ResourceData, m interfac
return diag.FromErr(err) return diag.FromErr(err)
} }
wgId, _ := strconv.ParseUint(d.Id(), 10, 64)
if newNum := d.Get("num").(int); uint64(newNum) > wg.Num { if newNum := d.Get("num").(int); uint64(newNum) > wg.Num {
req := k8s.WorkerAddRequest{ req := k8s.WorkerAddRequest{
K8SID: uint64(d.Get("k8s_id").(int)), K8SID: uint64(d.Get("k8s_id").(int)),
WorkersGroupID: wgId, WorkersGroupID: wg.ID,
Num: uint64(newNum) - wg.Num, Num: uint64(newNum) - wg.Num,
} }
@ -177,7 +178,7 @@ func resourceK8sWgUpdate(ctx context.Context, d *schema.ResourceData, m interfac
for i := int(wg.Num) - 1; i >= newNum; i-- { for i := int(wg.Num) - 1; i >= newNum; i-- {
req := k8s.DeleteWorkerFromGroupRequest{ req := k8s.DeleteWorkerFromGroupRequest{
K8SID: uint64(d.Get("k8s_id").(int)), K8SID: uint64(d.Get("k8s_id").(int)),
WorkersGroupID: wgId, WorkersGroupID: wg.ID,
WorkerID: wg.DetailedInfo[i].ID, WorkerID: wg.DetailedInfo[i].ID,
} }
@ -191,7 +192,7 @@ func resourceK8sWgUpdate(ctx context.Context, d *schema.ResourceData, m interfac
if d.HasChange("cloud_init") { if d.HasChange("cloud_init") {
req := k8s.UpdateWorkerNodesMetaDataRequest{ req := k8s.UpdateWorkerNodesMetaDataRequest{
K8SID: uint64(d.Get("k8s_id").(int)), K8SID: uint64(d.Get("k8s_id").(int)),
WorkersGroupID: wgId, WorkersGroupID: wg.ID,
UserData: d.Get("cloud_init").(string), UserData: d.Get("cloud_init").(string),
} }
@ -229,16 +230,16 @@ func resourceK8sWgDelete(ctx context.Context, d *schema.ResourceData, m interfac
func resourceK8sWgSchemaMake() map[string]*schema.Schema { func resourceK8sWgSchemaMake() map[string]*schema.Schema {
return map[string]*schema.Schema{ return map[string]*schema.Schema{
"k8s_id": { "k8s_id": {
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
ForceNew: true, // ForceNew: true,
Description: "ID of k8s instance.", Description: "ID of k8s instance.",
}, },
"name": { "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
ForceNew: true, // ForceNew: true,
Description: "Name of the worker group.", Description: "Name of the worker group.",
}, },
@ -250,18 +251,22 @@ func resourceK8sWgSchemaMake() map[string]*schema.Schema {
}, },
"cpu": { "cpu": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
ForceNew: true, // ForceNew: true,
Default: 1, Default: 1,
Description: "Worker node CPU count.", Description: "Worker node CPU count.",
}, },
"ram": { "ram": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
ForceNew: true, //ForceNew: true,
Default: 1024, Default: 1024,
ValidateFunc: validation.All(
validation.IntAtLeast(constants.MinRamPerCompute),
validators.DivisibleBy(constants.RAMDivisibility),
),
Description: "Worker node RAM in MB.", Description: "Worker node RAM in MB.",
}, },

@ -91,11 +91,11 @@ func utilityK8sWgCheckPresence(ctx context.Context, d *schema.ResourceData, m in
var err error var err error
if strings.Contains(d.Id(), "#") { if strings.Contains(d.Id(), "#") {
wgId, err = strconv.Atoi(strings.Split(d.Id(), "#")[0]) wgId, err = strconv.Atoi(strings.Split(d.Id(), "#")[1])
if err != nil { if err != nil {
return nil, err return nil, err
} }
k8sId, err = strconv.Atoi(strings.Split(d.Id(), "#")[1]) k8sId, err = strconv.Atoi(strings.Split(d.Id(), "#")[0])
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -142,7 +142,7 @@ func utilityK8sWgListCheckPresence(ctx context.Context, d *schema.ResourceData,
func utilityK8sWgCloudInitCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (string, error) { func utilityK8sWgCloudInitCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (string, error) {
c := m.(*controller.ControllerCfg) c := m.(*controller.ControllerCfg)
req := k8s.GetWorkerNodesMetaDataRequest{ req := k8s.GetWorkerNodesMetaDataRequest{
K8SID: uint64(d.Get("k8s_id").(int)), K8SID: uint64(d.Get("k8s_id").(int)),
WorkersGroupID: uint64(d.Get("wg_id").(int)), WorkersGroupID: uint64(d.Get("wg_id").(int)),
} }

@ -33,6 +33,7 @@ Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/w
package kvmvm package kvmvm
import ( import (
"context"
"encoding/json" "encoding/json"
"sort" "sort"
"strconv" "strconv"
@ -236,27 +237,35 @@ func flattenBootDisk(bootDisk *compute.ItemComputeDisk) []map[string]interface{}
return res return res
} }
func flattenComputeDisksDemo(disksList compute.ListComputeDisks, extraDisks []interface{}, bootDiskId uint64) []map[string]interface{} { func flattenComputeDisksDemo(ctx context.Context, d *schema.ResourceData, disksList compute.ListComputeDisks, extraDisks []interface{}, bootDiskId uint64) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(disksList)) res := make([]map[string]interface{}, 0, len(disksList))
for _, disk := range disksList { for _, disk := range disksList {
if disk.ID == bootDiskId || findInExtraDisks(uint(disk.ID), extraDisks) { //skip main bootdisk and extraDisks if disk.ID == bootDiskId || findInExtraDisks(uint(disk.ID), extraDisks) { //skip main bootdisk and extraDisks
continue continue
} }
permanently, ok := ctx.Value(DiskKey(strconv.Itoa(int(disk.ID)))).(bool) // get permamently from Create or Update context
if !ok {
permanently = getPermanentlyByDiskID(d, disk.ID) // get permanently from state when Read is not after Create/Update
}
temp := map[string]interface{}{ temp := map[string]interface{}{
"disk_name": disk.Name, "disk_name": disk.Name,
"disk_id": disk.ID, "disk_id": disk.ID,
"disk_type": disk.Type, "disk_type": disk.Type,
"sep_id": disk.SepID, "sep_id": disk.SepID,
"shareable": disk.Shareable, "shareable": disk.Shareable,
"size_max": disk.SizeMax, "size_max": disk.SizeMax,
"size_used": disk.SizeUsed, "size_used": disk.SizeUsed,
"pool": disk.Pool, "pool": disk.Pool,
"desc": disk.Description, "desc": disk.Description,
"image_id": disk.ImageID, "image_id": disk.ImageID,
"size": disk.SizeMax, "size": disk.SizeMax,
"permanently": permanently,
} }
res = append(res, temp) res = append(res, temp)
} }
sort.Slice(res, func(i, j int) bool { sort.Slice(res, func(i, j int) bool {
return res[i]["disk_id"].(uint64) < res[j]["disk_id"].(uint64) return res[i]["disk_id"].(uint64) < res[j]["disk_id"].(uint64)
}) })
@ -264,6 +273,21 @@ func flattenComputeDisksDemo(disksList compute.ListComputeDisks, extraDisks []in
return res return res
} }
// getPermanentlyByDiskID gets permanently value of specific disk (by diskId) from disks current state
func getPermanentlyByDiskID(d *schema.ResourceData, diskId uint64) bool {
disks := d.Get("disks").([]interface{})
for _, diskItem := range disks {
disk := diskItem.(map[string]interface{})
if uint64(disk["disk_id"].(int)) == diskId {
return disk["permanently"].(bool)
}
}
log.Infof("getPermanentlyByDiskID: disk with id %d not found in state", diskId)
return false
}
func flattenNetwork(interfaces compute.ListInterfaces) []map[string]interface{} { func flattenNetwork(interfaces compute.ListInterfaces) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(interfaces)) res := make([]map[string]interface{}, 0, len(interfaces))
@ -288,7 +312,7 @@ func findBootDisk(disks compute.ListComputeDisks) *compute.ItemComputeDisk {
return nil return nil
} }
func flattenCompute(d *schema.ResourceData, computeRec compute.RecordCompute) error { func flattenCompute(ctx context.Context, d *schema.ResourceData, computeRec compute.RecordCompute) error {
// This function expects that compFacts string contains response from API compute/get, // This function expects that compFacts string contains response from API compute/get,
// i.e. detailed information about compute instance. // i.e. detailed information about compute instance.
// //
@ -322,7 +346,7 @@ func flattenCompute(d *schema.ResourceData, computeRec compute.RecordCompute) er
d.Set("deleted_time", computeRec.DeletedTime) d.Set("deleted_time", computeRec.DeletedTime)
d.Set("description", computeRec.Description) d.Set("description", computeRec.Description)
d.Set("devices", string(devices)) d.Set("devices", string(devices))
err := d.Set("disks", flattenComputeDisksDemo(computeRec.Disks, d.Get("extra_disks").(*schema.Set).List(), bootDisk.ID)) err := d.Set("disks", flattenComputeDisksDemo(ctx, d, computeRec.Disks, d.Get("extra_disks").(*schema.Set).List(), bootDisk.ID))
if err != nil { if err != nil {
return err return err
} }
@ -658,7 +682,7 @@ func flattenSnapshotList(computeSnapshotUsages *compute.ListSnapShots) []map[str
for _, computeUsage := range computeSnapshotUsages.Data { for _, computeUsage := range computeSnapshotUsages.Data {
temp := map[string]interface{}{ temp := map[string]interface{}{
"disks": computeUsage.Disks, "disks": computeUsage.Disks,
"guid": computeUsage.GUID, "guid": computeUsage.GUID,
"label": computeUsage.Label, "label": computeUsage.Label,
"timestamp": computeUsage.Timestamp, "timestamp": computeUsage.Timestamp,
} }
@ -703,4 +727,4 @@ func flattenPCIDevice(m []interface{}) []string {
} }
} }
return output return output
} }

@ -40,6 +40,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/compute" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/compute"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/disks"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/kvmppc" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/kvmppc"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/kvmx86" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudapi/kvmx86"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
@ -47,12 +48,16 @@ import (
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/dc" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/dc"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/statefuncs" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/statefuncs"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/status" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/status"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/validators"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
) )
// DiskKey is custom string type to set up context Key for Disk ID
type DiskKey string
func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceComputeCreate: called for Compute name %q, RG ID %d", d.Get("name").(string), d.Get("rg_id").(int)) log.Debugf("resourceComputeCreate: called for Compute name %q, RG ID %d", d.Get("name").(string), d.Get("rg_id").(int))
c := m.(*controller.ControllerCfg) c := m.(*controller.ControllerCfg)
@ -307,11 +312,13 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
req.ImageID = uint64(diskConv["image_id"].(int)) req.ImageID = uint64(diskConv["image_id"].(int))
} }
_, err := c.CloudAPI().Compute().DiskAdd(ctx, req) diskId, err := c.CloudAPI().Compute().DiskAdd(ctx, req)
if err != nil { if err != nil {
cleanup = true cleanup = true
return diag.FromErr(err) return diag.FromErr(err)
} }
ctx = context.WithValue(ctx, DiskKey(strconv.Itoa(int(diskId))), diskConv["permanently"].(bool))
} }
} }
} }
@ -541,7 +548,7 @@ func resourceComputeRead(ctx context.Context, d *schema.ResourceData, m interfac
} }
} }
if err = flattenCompute(d, computeRec); err != nil { if err = flattenCompute(ctx, d, computeRec); err != nil {
return diag.FromErr(err) return diag.FromErr(err)
} }
@ -747,14 +754,23 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
if d.HasChange("disks") { if d.HasChange("disks") {
deletedDisks := make([]interface{}, 0) deletedDisks := make([]interface{}, 0)
addedDisks := make([]interface{}, 0) addedDisks := make([]interface{}, 0)
updatedDisks := make([]interface{}, 0) resizedDisks := make([]interface{}, 0)
renamedDisks := make([]interface{}, 0)
// save permanently in disks based on disk_id to context
for _, diskItemInterface := range d.Get("disks").([]interface{}) {
diskItem := diskItemInterface.(map[string]interface{})
diskId := diskItem["disk_id"].(int)
permanently := diskItem["permanently"].(bool)
ctx = context.WithValue(ctx, DiskKey(strconv.Itoa(diskId)), permanently)
}
oldDisks, newDisks := d.GetChange("disks") oldDisks, newDisks := d.GetChange("disks")
oldConv := oldDisks.([]interface{}) oldConv := oldDisks.([]interface{})
newConv := newDisks.([]interface{}) newConv := newDisks.([]interface{})
for _, el := range oldConv { for _, el := range oldConv {
if !isContainsDisk(newConv, el) { if !isContainsDisk(newConv, el) && !isRenameDisk(newConv, el) && !isResizeDisk(newConv, el) {
flag := false flag := false
extraDisks := d.Get("extra_disks").(*schema.Set).List() extraDisks := d.Get("extra_disks").(*schema.Set).List()
delDisk := el.(map[string]interface{}) delDisk := el.(map[string]interface{})
@ -778,10 +794,12 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
for _, el := range newConv { for _, el := range newConv {
if !isContainsDisk(oldConv, el) { if !isContainsDisk(oldConv, el) {
addedDisks = append(addedDisks, el) addedDisks = append(addedDisks, el)
} else { }
if isChangeDisk(oldConv, el) { if isResizeDisk(oldConv, el) {
updatedDisks = append(updatedDisks, el) resizedDisks = append(resizedDisks, el)
} }
if isRenameDisk(oldConv, el) {
renamedDisks = append(renamedDisks, el)
} }
} }
@ -850,15 +868,17 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
if diskConv["image_id"].(int) != 0 { if diskConv["image_id"].(int) != 0 {
req.ImageID = uint64(diskConv["image_id"].(int)) req.ImageID = uint64(diskConv["image_id"].(int))
} }
_, err := c.CloudAPI().Compute().DiskAdd(ctx, req) diskId, err := c.CloudAPI().Compute().DiskAdd(ctx, req)
if err != nil { if err != nil {
return diag.FromErr(err) return diag.FromErr(err)
} }
ctx = context.WithValue(ctx, DiskKey(strconv.Itoa(int(diskId))), diskConv["permanently"].(bool))
} }
} }
if len(updatedDisks) > 0 { if len(resizedDisks) > 0 {
for _, disk := range updatedDisks { for _, disk := range resizedDisks {
diskConv := disk.(map[string]interface{}) diskConv := disk.(map[string]interface{})
if diskConv["disk_type"].(string) == "B" { if diskConv["disk_type"].(string) == "B" {
continue continue
@ -875,6 +895,22 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
} }
} }
} }
if len(renamedDisks) > 0 {
for _, disk := range renamedDisks {
diskConv := disk.(map[string]interface{})
req := disks.RenameRequest{
DiskID: uint64(diskConv["disk_id"].(int)),
Name: diskConv["disk_name"].(string),
}
_, err := c.CloudAPI().Disks().Rename(ctx, req)
if err != nil {
return diag.FromErr(err)
}
}
}
} }
if d.HasChange("started") { if d.HasChange("started") {
@ -1398,7 +1434,7 @@ func resourceComputeUpdate(ctx context.Context, d *schema.ResourceData, m interf
return warnings.Get() return warnings.Get()
} }
func isChangeDisk(els []interface{}, el interface{}) bool { func isResizeDisk(els []interface{}, el interface{}) bool {
for _, elOld := range els { for _, elOld := range els {
elOldConv := elOld.(map[string]interface{}) elOldConv := elOld.(map[string]interface{})
elConv := el.(map[string]interface{}) elConv := el.(map[string]interface{})
@ -1410,11 +1446,23 @@ func isChangeDisk(els []interface{}, el interface{}) bool {
return false return false
} }
func isRenameDisk(els []interface{}, el interface{}) bool {
for _, elOld := range els {
elOldConv := elOld.(map[string]interface{})
elConv := el.(map[string]interface{})
if elOldConv["disk_id"].(int) == elConv["disk_id"].(int) &&
elOldConv["disk_name"].(string) != elConv["disk_name"].(string) {
return true
}
}
return false
}
func isContainsDisk(els []interface{}, el interface{}) bool { func isContainsDisk(els []interface{}, el interface{}) bool {
for _, elOld := range els { for _, elOld := range els {
elOldConv := elOld.(map[string]interface{}) elOldConv := elOld.(map[string]interface{})
elConv := el.(map[string]interface{}) elConv := el.(map[string]interface{})
if elOldConv["disk_name"].(string) == elConv["disk_name"].(string) { if elOldConv["disk_id"].(int) == elConv["disk_id"].(int) {
return true return true
} }
} }
@ -1505,7 +1553,7 @@ func disksSubresourceSchemaMake() map[string]*schema.Schema {
"permanently": { "permanently": {
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
Default: true, Default: false,
Description: "Disk deletion status", Description: "Disk deletion status",
}, },
"disk_id": { "disk_id": {
@ -1634,10 +1682,13 @@ func ResourceComputeSchemaMake() map[string]*schema.Schema {
Description: "Number of CPUs to allocate to this compute instance.", Description: "Number of CPUs to allocate to this compute instance.",
}, },
"ram": { "ram": {
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
ValidateFunc: validation.IntAtLeast(constants.MinRamPerCompute), ValidateFunc: validation.All(
Description: "Amount of RAM in MB to allocate to this compute instance.", validation.IntAtLeast(constants.MinRamPerCompute),
validators.DivisibleBy(constants.RAMDivisibility),
),
Description: "Amount of RAM in MB to allocate to this compute instance.",
}, },
"image_id": { "image_id": {
Type: schema.TypeInt, Type: schema.TypeInt,
@ -1686,7 +1737,7 @@ func ResourceComputeSchemaMake() map[string]*schema.Schema {
}, },
"value": { "value": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Optional: true,
Description: "value that must match the key to be taken into account when analyzing this rule", Description: "value that must match the key to be taken into account when analyzing this rule",
}, },
}, },
@ -1722,7 +1773,7 @@ func ResourceComputeSchemaMake() map[string]*schema.Schema {
}, },
"value": { "value": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Optional: true,
Description: "value that must match the key to be taken into account when analyzing this rule", Description: "value that must match the key to be taken into account when analyzing this rule",
}, },
}, },

@ -82,8 +82,17 @@ func dataSourceRgAffinityGroupsListSchemaMake() map[string]*schema.Schema {
"ids": { "ids": {
Type: schema.TypeList, Type: schema.TypeList,
Computed: true, Computed: true,
Elem: &schema.Schema{ Elem: &schema.Resource{
Type: schema.TypeInt, Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeInt,
Computed: true,
},
"node_id": {
Type: schema.TypeInt,
Computed: true,
},
},
}, },
}, },
}, },

@ -461,7 +461,7 @@ func flattenRgListLb(listLb *rg.ListLB) []map[string]interface{} {
} }
func flattenRgListPfw(listPfw *rg.ListPortForwards) []map[string]interface{} { func flattenRgListPfw(listPfw *rg.ListPortForwards) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len (listPfw.Data)) res := make([]map[string]interface{}, 0, len(listPfw.Data))
for _, pfw := range listPfw.Data { for _, pfw := range listPfw.Data {
temp := map[string]interface{}{ temp := map[string]interface{}{
"public_port_end": pfw.PublicPortEnd, "public_port_end": pfw.PublicPortEnd,
@ -538,10 +538,25 @@ func flattenRgAffinityGroupComputes(list rg.ListAffinityGroupsComputes) []map[st
func flattenRgListGroups(list *rg.ListAffinityGroups) []map[string]interface{} { func flattenRgListGroups(list *rg.ListAffinityGroups) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(list.Data)) res := make([]map[string]interface{}, 0, len(list.Data))
for groupKey, groupVal := range list.Data { for _, groupVal := range list.Data {
for label, ag := range groupVal {
temp := map[string]interface{}{
"label": label,
"ids": flattenRgAffinityListGroup(ag),
}
res = append(res, temp)
}
}
return res
}
func flattenRgAffinityListGroup(list rg.ListAffinityGroup) []map[string]interface{} {
res := make([]map[string]interface{}, 0, len(list))
for _, ag := range list {
temp := map[string]interface{}{ temp := map[string]interface{}{
"label": groupKey, "id": ag.ID,
"ids": groupVal, "node_id": ag.NodeID,
} }
res = append(res, temp) res = append(res, temp)
} }
@ -564,10 +579,10 @@ func flattenRGResourceConsumptionList(rg *rg.ListResourceConsumption) []map[stri
res := make([]map[string]interface{}, 0, len(rg.Data)) res := make([]map[string]interface{}, 0, len(rg.Data))
for _, rc := range rg.Data { for _, rc := range rg.Data {
temp := map[string]interface{}{ temp := map[string]interface{}{
"consumed": flattenResource(rc.Consumed), "consumed": flattenResource(rc.Consumed),
"reserved": flattenResource(rc.Reserved), "reserved": flattenResource(rc.Reserved),
"resource_limits": flattenRgResourceLimits(rc.ResourceLimits), "resource_limits": flattenRgResourceLimits(rc.ResourceLimits),
"rg_id": rc.RGID, "rg_id": rc.RGID,
} }
res = append(res, temp) res = append(res, temp)
} }

@ -33,7 +33,10 @@ package k8s
import ( import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/k8s" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/k8s"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/validators"
) )
func nodeMasterDefault() k8s.MasterGroup { func nodeMasterDefault() k8s.MasterGroup {
@ -114,9 +117,13 @@ func nodeK8sSubresourceSchemaMake() map[string]*schema.Schema {
}, },
"ram": { "ram": {
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
ForceNew: true, //ForceNew: true,
ValidateFunc: validation.All(
validation.IntAtLeast(constants.MinRamPerCompute),
validators.DivisibleBy(constants.RAMDivisibility),
),
Description: "Node RAM in MB.", Description: "Node RAM in MB.",
}, },

@ -36,10 +36,12 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/k8s" "repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/k8s"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/validators"
) )
func resourceK8sWgCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { func resourceK8sWgCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
@ -178,10 +180,14 @@ func resourceK8sWgSchemaMake() map[string]*schema.Schema {
}, },
"ram": { "ram": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
ForceNew: true, //ForceNew: true,
Default: 1024, Default: 1024,
ValidateFunc: validation.All(
validation.IntAtLeast(constants.MinRamPerCompute),
validators.DivisibleBy(constants.RAMDivisibility),
),
Description: "Worker node RAM in MB.", Description: "Worker node RAM in MB.",
}, },

@ -43,6 +43,7 @@ import (
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/statefuncs" "repository.basistech.ru/BASIS/terraform-provider-decort/internal/statefuncs"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/validators"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@ -386,10 +387,13 @@ func ResourceCompute() *schema.Resource {
}, },
"ram": { "ram": {
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
ValidateFunc: validation.IntAtLeast(constants.MinRamPerCompute), ValidateFunc: validation.All(
Description: "Amount of RAM in MB to allocate to this compute instance.", validation.IntAtLeast(constants.MinRamPerCompute),
validators.DivisibleBy(constants.RAMDivisibility),
),
Description: "Amount of RAM in MB to allocate to this compute instance.",
}, },
"image_id": { "image_id": {

@ -0,0 +1,22 @@
package validators
import (
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func DivisibleBy(divisibility int) schema.SchemaValidateFunc {
return func(i interface{}, k string) (warnings []string, errors []error) {
total, ok := i.(int)
if !ok {
errors = append(errors, fmt.Errorf("expected type of %s to be integer", k))
return warnings, errors
}
if total % divisibility != 0 {
errors = append(errors, fmt.Errorf("expected value of %s to be divisible by %d", k, divisibility))
}
return warnings, errors
}
}

@ -47,7 +47,7 @@ resource "decort_bservice" "b" {
#доступность сервиса #доступность сервиса
#необязательный параметр #необязательный параметр
#тип - булев тип #тип - булев тип
#используется при редактировании ресурса #используется при редактировании и создании ресурса
#по-умолачанию - false #по-умолачанию - false
#enable = true #enable = true
@ -78,7 +78,7 @@ resource "decort_bservice" "b" {
#старт сервиса #старт сервиса
#необязательный параметр #необязательный параметр
#тип - булев тип #тип - булев тип
#используется при редактировании ресурса #используется при редактировании и создании ресурса
#по-умолачанию - false #по-умолачанию - false
#start = false #start = false

@ -278,6 +278,11 @@ resource "decort_k8s" "cluster" {
# тип - файл # тип - файл
oidc_cert = file("ca.crt") oidc_cert = file("ca.crt")
# команда destroy удаляет кластер без возможности восстановления
# опциональный параметр
# тип - булев тип
permanently = true
} }
output "test_cluster" { output "test_cluster" {

@ -90,6 +90,12 @@ resource "decort_k8s_cp" "cp" {
# Опциональный параметр # Опциональный параметр
# bool # bool
with_lb = true with_lb = true
# команда destroy удаляет кластер без возможности восстановления
# опциональный параметр
# тип - булев тип
permanently = true
} }
output "cp_out" { output "cp_out" {

@ -160,7 +160,7 @@ resource "decort_kvmvm" "comp" {
key = "testkey" key = "testkey"
#ключ правила #ключ правила
#обязательный параметр #необязательный параметр
#тип строка #тип строка
value = "testvalue" value = "testvalue"
} }
@ -194,7 +194,7 @@ resource "decort_kvmvm" "comp" {
key = "testkey" key = "testkey"
#ключ правила #ключ правила
#обязательный параметр #необязательный параметр
#тип строка #тип строка
value = "testvalue" value = "testvalue"
} }

@ -25,32 +25,95 @@ provider "decort" {
allow_unverified_ssl = true allow_unverified_ssl = true
} }
resource "decort_disk" "acl" { resource "decort_disk" "disk" {
#id аккаунта
#обязательный параметр
#тип - число
account_id = 88366 account_id = 88366
#gid
#обязательный параметр
#тип - число
gid = 212 gid = 212
#название диска диска
#обязательный параметр
#тип - строка
disk_name = "super-disk-re" disk_name = "super-disk-re"
#максимальный размер диска
#обязательный параметр
#тип - число
#значение по умолчанию 10
size_max = 20 size_max = 20
restore = true
permanently = true
reason = "delete"
iotune {
read_bytes_sec = 0
read_bytes_sec_max = 0
read_iops_sec = 0
read_iops_sec_max = 0
size_iops_sec = 0
total_bytes_sec = 0
total_bytes_sec_max = 0
total_iops_sec = 3000
total_iops_sec_max = 0
write_bytes_sec = 0
write_bytes_sec_max = 0
write_iops_sec = 0
write_iops_sec_max = 0
}
#описание диска
#опциональный параметр
#тип - строка
#desc = "description"
#тип диска
#опциональный параметр
#тип - строка
#возможные значения "D", "B", "T"
#type = "D"
#sep id
#опциональный параметр
#тип - число
#значение по умолчанию 0
#sep_id = 1
#название pool
#опциональный параметр
#тип - строка
#pool = 1
#флаг для восстановления диска
#опциональный параметр
#тип - булев
#restore = true
#флаг для удаления диска
#опциональный параметр
#тип - булев
#permanently = true
#причина удаления диска
#опциональный параметр
#тип - строка
#reason = "delete"
#флаг поделиться диском
#опциональный параметр
#тип - булев
#shareable = true
#флаг отсоединения диска от машины перед удалением
#опциональный параметр
#тип - булев
#detach = true
#настройки лимитов операций записи/чтения с диска
#опциональный параметр
#тип - блок, тип вложенных полей - число
# iotune {
# read_bytes_sec = 0
# read_bytes_sec_max = 0
# read_iops_sec = 0
# read_iops_sec_max = 0
# size_iops_sec = 0
# total_bytes_sec = 0
# total_bytes_sec_max = 0
# total_iops_sec = 3000
# total_iops_sec_max = 0
# write_bytes_sec = 0
# write_bytes_sec_max = 0
# write_iops_sec = 0
# write_iops_sec_max = 0
# }
} }
output "test" { output "test" {
value = decort_disk.acl value = decort_disk.disk
} }

@ -18,12 +18,10 @@
@echo off @echo off
FOR %%f IN (bin\*) DO ( cd /d "%~dp0"
if "%%~xf" == ".exe" ( pushd .\bin\
set filename=bin\%%~nf for %%f in (*.exe) do (
) else ( set filename=%%~nf
set filename=%%f
)
) )
for /F "tokens=1,2,3,4 delims=_" %%a in ("%filename%") do ( for /F "tokens=1,2,3,4 delims=_" %%a in ("%filename%") do (
@ -32,27 +30,16 @@ for /F "tokens=1,2,3,4 delims=_" %%a in ("%filename%") do (
set arch=%%d set arch=%%d
) )
if "%os%" neq "windows" (
echo Unable to find provider executable, is it moved or renamed?
pause
exit /b
)
set provider_path=%appdata%\terraform.d\plugins\basis\decort\decort\%version%\%os%_%arch%\ set provider_path=%appdata%\terraform.d\plugins\basis\decort\decort\%version%\%os%_%arch%\
if exist %provider_path% ( if exist %provider_path% (
echo Provider directory already exists, checking for decort provider executable.. echo Provider directory already exists, checking for decort provider executable..
dir /b /s /a "%provider_path%" | findstr .>nul || ( copy /y %filename%.exe %provider_path%
copy %filename% %provider_path%\terraform-provider-decort.exe
if errorlevel 1 ( if errorlevel 1 (
pause pause
exit /b exit /b
) )
call :print_success call :print_success
pause
exit /b
)
echo DECORT provider version %version% is already installed. Exiting.
pause pause
exit /b exit /b
) else ( ) else (
@ -62,7 +49,7 @@ if exist %provider_path% (
pause pause
exit /b exit /b
) )
copy %filename% %provider_path%\terraform-provider-decort.exe copy %filename%.exe %provider_path%
if errorlevel 1 ( if errorlevel 1 (
pause pause
exit /b exit /b
@ -84,4 +71,4 @@ echo source = "basis/decort/decort"
echo } echo }
echo } echo }
echo } echo }
goto:eof goto:eof

@ -47,7 +47,7 @@ install () {
then then
echo "Provider directory already exists, checking for decort provider executable.." echo "Provider directory already exists, checking for decort provider executable.."
if [[ ! "$(ls -A $plugins_dir$provider_path)" ]]; then if [[ ! "$(ls -A $plugins_dir$provider_path)" ]]; then
cp bin/terraform-provider-decort_$version\_$os\_$arch $plugins_dir$provider_path/terraform-provider-decort cp bin/terraform-provider-decort_$version\_$os\_$arch $plugins_dir$provider_path/terraform-provider-decort_$version/$os\_$arch
print_info print_info
else else
echo "DECORT provider version $version is already installed. Exiting.." echo "DECORT provider version $version is already installed. Exiting.."
@ -56,7 +56,7 @@ install () {
else else
echo "Creating provider directory.." echo "Creating provider directory.."
mkdir -p $plugins_dir/$provider_path mkdir -p $plugins_dir/$provider_path
cp bin/terraform-provider-decort_$version\_$os\_$arch $plugins_dir$provider_path/terraform-provider-decort cp bin/terraform-provider-decort_$version\_$os\_$arch $plugins_dir$provider_path/terraform-provider-decort_$version/$os\_$arch
echo "DECORT provider version $version has been successfully installed" echo "DECORT provider version $version has been successfully installed"
print_info print_info
fi fi

Loading…
Cancel
Save