gos_tech_4.4.3 3.6.0
KasimBaybikov 2 years ago
parent e3e7e7bd89
commit 9bad8a6947

@ -1,10 +1,23 @@
## Version 3.5.2
## Version 3.6.0
### Features
- Add new datasource decort_kvmvm_snapshot_usage
- Add the ability to change the size in the 'disks' block in the decort_kvmvm resource. Now when you change 'size' field in the block, the disk size on the platform will also be changed
- Added validation for required fields in the following resources:
- disks
- lb
- image
- bservice
- vins
- k8s
- k8s_wg
- lb_frontend
- lb_frontend_bind
- lb_backed
- lb_backend_server
- Added status handlers in create/update functions (where present)
## Bug Fix
- rule "release" in Makefile don't create the necessary archives
- field "register_computes" in resource decort_resgroup is not used when creating the resource
- removed unused optional fields in datasources
### Bug Fixes
- Fixed state inconsistency in the following resources/data sources:
- data_source_account
- resource_k8s
- resource_k8s_wg
- resource_account

@ -8,7 +8,7 @@ ZIPDIR = ./zip
BINARY=${NAME}.exe
WORKPATH= ./examples/terraform.d/plugins/${HOSTNAME}/${NAMESPACE}/${NAMESPACE}/${VERSION}/${OS_ARCH}
MAINPATH = ./cmd/decort/
VERSION=3.5.2
VERSION=3.6.0
#OS_ARCH=darwin_amd64
OS_ARCH=windows_amd64
#OS_ARCH=linux_amd64

@ -80,7 +80,7 @@ terraform init
3. Склонируйте репозиторий с провайдером, выполнив команду:
```bash
git clone https://repository.basistech.ru/BASIS/terraform-provider-decort.git
git clone https://repository.basistech.ru/BASIS/terraform-provider-decort
```
4. Перейдите в скачанную папку с провайдером и выполните команду

@ -82,7 +82,7 @@ The Provider will automatically install on your computer from the terrafrom regi
3. Clone provider's repo:
```bash
git clone https://repository.basistech.ru/BASIS/terraform-provider-decort.git
git clone https://github.com/rudecs/terraform-provider-decort.git
```
4. Change directory to clone provider's and execute next command

@ -34,12 +34,11 @@ package account
import (
"context"
"strconv"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"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/flattens"
)
func dataSourceAccountRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
@ -48,147 +47,103 @@ func dataSourceAccountRead(ctx context.Context, d *schema.ResourceData, m interf
return diag.FromErr(err)
}
id := uuid.New()
d.SetId(id.String())
d.Set("dc_location", acc.DCLocation)
d.Set("resources", flattenAccResources(acc.Resources))
d.Set("ckey", acc.CKey)
d.Set("meta", flattens.FlattenMeta(acc.Meta))
d.Set("acl", flattenAccAcl(acc.Acl))
d.Set("company", acc.Company)
d.Set("companyurl", acc.CompanyUrl)
d.Set("created_by", acc.CreatedBy)
d.Set("created_time", acc.CreatedTime)
d.Set("deactivation_time", acc.DeactiovationTime)
d.Set("deleted_by", acc.DeletedBy)
d.Set("deleted_time", acc.DeletedTime)
d.Set("displayname", acc.DisplayName)
d.Set("guid", acc.GUID)
d.Set("account_id", acc.ID)
d.Set("account_name", acc.Name)
d.Set("resource_limits", flattenRgResourceLimits(acc.ResourceLimits))
d.Set("send_access_emails", acc.SendAccessEmails)
d.Set("service_account", acc.ServiceAccount)
d.Set("status", acc.Status)
d.Set("updated_time", acc.UpdatedTime)
d.Set("version", acc.Version)
d.Set("vins", acc.Vins)
d.Set("vinses", acc.Vinses)
d.Set("computes", flattenAccComputes(acc.Computes))
d.Set("machines", flattenAccMachines(acc.Machines))
return nil
}
func flattenAccComputes(acs Computes) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
temp := map[string]interface{}{
"started": acs.Started,
"stopped": acs.Stopped,
}
res = append(res, temp)
return res
}
func flattenAccMachines(ams Machines) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
temp := map[string]interface{}{
"running": ams.Running,
"halted": ams.Halted,
}
res = append(res, temp)
return res
}
flattenAccount(d, *acc)
d.SetId(strconv.Itoa(acc.ID))
func flattenAccAcl(acls []AccountAclRecord) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for _, acls := range acls {
temp := map[string]interface{}{
"can_be_deleted": acls.CanBeDeleted,
"explicit": acls.IsExplicit,
"guid": acls.Guid,
"right": acls.Rights,
"status": acls.Status,
"type": acls.Type,
"user_group_id": acls.UgroupID,
}
res = append(res, temp)
}
return res
return nil
}
func flattenRgResourceLimits(rl ResourceLimits) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
temp := map[string]interface{}{
"cu_c": rl.CUC,
"cu_d": rl.CUD,
"cu_i": rl.CUI,
"cu_m": rl.CUM,
"cu_np": rl.CUNP,
"gpu_units": rl.GpuUnits,
func aclSchemaMake() map[string]*schema.Schema {
res := map[string]*schema.Schema{
"can_be_deleted": {
Type: schema.TypeBool,
Computed: true,
},
"explicit": {
Type: schema.TypeBool,
Computed: true,
},
"guid": {
Type: schema.TypeString,
Computed: true,
},
"right": {
Type: schema.TypeString,
Computed: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"type": {
Type: schema.TypeString,
Computed: true,
},
"user_group_id": {
Type: schema.TypeString,
Computed: true,
},
}
res = append(res, temp)
return res
}
func flattenAccResources(r Resources) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
temp := map[string]interface{}{
"current": flattenAccResource(r.Current),
"reserved": flattenAccResource(r.Reserved),
}
res = append(res, temp)
return res
}
func flattenAccountSeps(seps map[string]map[string]ResourceSep) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for sepKey, sepVal := range seps {
for dataKey, dataVal := range sepVal {
temp := map[string]interface{}{
"sep_id": sepKey,
"data_name": dataKey,
"disk_size": dataVal.DiskSize,
"disk_size_max": dataVal.DiskSizeMax,
}
res = append(res, temp)
}
func resourceLimitsSchemaMake() map[string]*schema.Schema {
res := map[string]*schema.Schema{
"cu_c": {
Type: schema.TypeFloat,
Computed: true,
},
"cu_d": {
Type: schema.TypeFloat,
Computed: true,
},
"cu_i": {
Type: schema.TypeFloat,
Computed: true,
},
"cu_m": {
Type: schema.TypeFloat,
Computed: true,
},
"cu_np": {
Type: schema.TypeFloat,
Computed: true,
},
"gpu_units": {
Type: schema.TypeFloat,
Computed: true,
},
}
return res
}
func flattenAccResource(r Resource) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
temp := map[string]interface{}{
"cpu": r.CPU,
"disksize": r.Disksize,
"extips": r.Extips,
"exttraffic": r.Exttraffic,
"gpu": r.GPU,
"ram": r.RAM,
"seps": flattenAccountSeps(r.SEPs),
}
res = append(res, temp)
return res
}
func dataSourceAccountSchemaMake() map[string]*schema.Schema {
func sepsSchemaMake() map[string]*schema.Schema {
res := map[string]*schema.Schema{
"account_id": {
Type: schema.TypeInt,
Required: true,
"sep_id": {
Type: schema.TypeString,
Computed: true,
},
"dc_location": {
"data_name": {
Type: schema.TypeString,
Computed: true,
},
"resources": {
Type: schema.TypeList,
"disk_size": {
Type: schema.TypeFloat,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
},
"disk_size_max": {
Type: schema.TypeInt,
Computed: true,
},
}
return res
}
func resourcesSchemaMake() map[string]*schema.Schema {
res := map[string]*schema.Schema{
"current": {
Type: schema.TypeList,
Computed: true,
@ -219,27 +174,10 @@ func dataSourceAccountSchemaMake() map[string]*schema.Schema {
Computed: true,
},
"seps": {
Type: schema.TypeList,
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"sep_id": {
Type: schema.TypeString,
Computed: true,
},
"data_name": {
Type: schema.TypeString,
Computed: true,
},
"disk_size": {
Type: schema.TypeFloat,
Computed: true,
},
"disk_size_max": {
Type: schema.TypeInt,
Computed: true,
},
},
Schema: sepsSchemaMake(),
},
},
},
@ -275,33 +213,66 @@ func dataSourceAccountSchemaMake() map[string]*schema.Schema {
Computed: true,
},
"seps": {
Type: schema.TypeList,
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"sep_id": {
Type: schema.TypeString,
Computed: true,
Schema: sepsSchemaMake(),
},
"data_name": {
Type: schema.TypeString,
Computed: true,
},
"disk_size": {
Type: schema.TypeFloat,
Computed: true,
},
"disk_size_max": {
Type: schema.TypeInt,
Computed: true,
},
},
}
return res
}
func computesSchemaMake() map[string]*schema.Schema {
res := map[string]*schema.Schema{
"started": {
Type: schema.TypeInt,
Computed: true,
},
"stopped": {
Type: schema.TypeInt,
Computed: true,
},
}
return res
}
func machinesSchemaMake() map[string]*schema.Schema {
res := map[string]*schema.Schema{
"halted": {
Type: schema.TypeInt,
Computed: true,
},
"running": {
Type: schema.TypeInt,
Computed: true,
},
}
return res
}
func dataSourceAccountSchemaMake() map[string]*schema.Schema {
res := map[string]*schema.Schema{
"account_id": {
Type: schema.TypeInt,
Required: true,
},
"dc_location": {
Type: schema.TypeString,
Computed: true,
},
"resources": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: resourcesSchemaMake(),
},
},
"ckey": {
@ -319,36 +290,7 @@ func dataSourceAccountSchemaMake() map[string]*schema.Schema {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"can_be_deleted": {
Type: schema.TypeBool,
Computed: true,
},
"explicit": {
Type: schema.TypeBool,
Computed: true,
},
"guid": {
Type: schema.TypeString,
Computed: true,
},
"right": {
Type: schema.TypeString,
Computed: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"type": {
Type: schema.TypeString,
Computed: true,
},
"user_group_id": {
Type: schema.TypeString,
Computed: true,
},
},
Schema: aclSchemaMake(),
},
},
"company": {
@ -395,32 +337,7 @@ func dataSourceAccountSchemaMake() map[string]*schema.Schema {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cu_c": {
Type: schema.TypeFloat,
Computed: true,
},
"cu_d": {
Type: schema.TypeFloat,
Computed: true,
},
"cu_i": {
Type: schema.TypeFloat,
Computed: true,
},
"cu_m": {
Type: schema.TypeFloat,
Computed: true,
},
"cu_np": {
Type: schema.TypeFloat,
Computed: true,
},
"gpu_units": {
Type: schema.TypeFloat,
Computed: true,
},
},
Schema: resourceLimitsSchemaMake(),
},
},
"send_access_emails": {
@ -454,32 +371,14 @@ func dataSourceAccountSchemaMake() map[string]*schema.Schema {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"started": {
Type: schema.TypeInt,
Computed: true,
},
"stopped": {
Type: schema.TypeInt,
Computed: true,
},
},
Schema: computesSchemaMake(),
},
},
"machines": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"halted": {
Type: schema.TypeInt,
Computed: true,
},
"running": {
Type: schema.TypeInt,
Computed: true,
},
},
Schema: machinesSchemaMake(),
},
},
"vinses": {

@ -0,0 +1,137 @@
package account
import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/flattens"
)
func flattenAccount(d *schema.ResourceData, acc AccountWithResources) error {
d.Set("dc_location", acc.DCLocation)
d.Set("resources", flattenAccResources(acc.Resources))
d.Set("ckey", acc.CKey)
d.Set("meta", flattens.FlattenMeta(acc.Meta))
d.Set("acl", flattenAccAcl(acc.Acl))
d.Set("company", acc.Company)
d.Set("companyurl", acc.CompanyUrl)
d.Set("created_by", acc.CreatedBy)
d.Set("created_time", acc.CreatedTime)
d.Set("deactivation_time", acc.DeactiovationTime)
d.Set("deleted_by", acc.DeletedBy)
d.Set("deleted_time", acc.DeletedTime)
d.Set("displayname", acc.DisplayName)
d.Set("guid", acc.GUID)
d.Set("account_id", acc.ID)
d.Set("account_name", acc.Name)
d.Set("resource_limits", flattenRgResourceLimits(acc.ResourceLimits))
d.Set("send_access_emails", acc.SendAccessEmails)
d.Set("service_account", acc.ServiceAccount)
d.Set("status", acc.Status)
d.Set("updated_time", acc.UpdatedTime)
d.Set("version", acc.Version)
d.Set("vins", acc.Vins)
d.Set("vinses", acc.Vinses)
d.Set("computes", flattenAccComputes(acc.Computes))
d.Set("machines", flattenAccMachines(acc.Machines))
if username, ok := d.GetOk("username"); ok {
d.Set("username", username)
} else {
d.Set("username", acc.Acl[0].UgroupID)
}
return nil
}
func flattenAccComputes(acs Computes) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
temp := map[string]interface{}{
"started": acs.Started,
"stopped": acs.Stopped,
}
res = append(res, temp)
return res
}
func flattenAccMachines(ams Machines) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
temp := map[string]interface{}{
"running": ams.Running,
"halted": ams.Halted,
}
res = append(res, temp)
return res
}
func flattenAccAcl(acls []AccountAclRecord) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for _, acls := range acls {
temp := map[string]interface{}{
"can_be_deleted": acls.CanBeDeleted,
"explicit": acls.IsExplicit,
"guid": acls.Guid,
"right": acls.Rights,
"status": acls.Status,
"type": acls.Type,
"user_group_id": acls.UgroupID,
}
res = append(res, temp)
}
return res
}
func flattenRgResourceLimits(rl ResourceLimits) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
temp := map[string]interface{}{
"cu_c": rl.CUC,
"cu_d": rl.CUD,
"cu_i": rl.CUI,
"cu_m": rl.CUM,
"cu_np": rl.CUNP,
"gpu_units": rl.GpuUnits,
}
res = append(res, temp)
return res
}
func flattenAccResources(r Resources) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
temp := map[string]interface{}{
"current": flattenAccResource(r.Current),
"reserved": flattenAccResource(r.Reserved),
}
res = append(res, temp)
return res
}
func flattenAccountSeps(seps map[string]map[string]ResourceSep) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for sepKey, sepVal := range seps {
for dataKey, dataVal := range sepVal {
temp := map[string]interface{}{
"sep_id": sepKey,
"data_name": dataKey,
"disk_size": dataVal.DiskSize,
"disk_size_max": dataVal.DiskSizeMax,
}
res = append(res, temp)
}
}
return res
}
func flattenAccResource(r Resource) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
temp := map[string]interface{}{
"cpu": r.CPU,
"disksize": r.Disksize,
"extips": r.Extips,
"exttraffic": r.Exttraffic,
"gpu": r.GPU,
"ram": r.RAM,
"seps": flattenAccountSeps(r.SEPs),
}
res = append(res, temp)
return res
}

@ -43,7 +43,7 @@ import (
log "github.com/sirupsen/logrus"
"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/flattens"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/status"
)
func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
@ -122,13 +122,10 @@ func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, m interf
return diag.FromErr(err)
}
d.SetId(accountId)
d.Set("account_id", accountId)
accIdParsed, _ := strconv.Atoi(accountId)
diagnostics := resourceAccountRead(ctx, d, m)
if diagnostics != nil {
return diagnostics
}
d.SetId(accountId)
d.Set("account_id", accIdParsed)
urlValues = &url.Values{}
@ -167,44 +164,52 @@ func resourceAccountCreate(ctx context.Context, d *schema.ResourceData, m interf
}
}
return nil
return resourceAccountRead(ctx, d, m)
}
func resourceAccountRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceAccountRead")
log.Debugf("resourceAccountRead: called for account with ID: %v", d.Id())
c := m.(*controller.ControllerCfg)
acc, err := utilityAccountCheckPresence(ctx, d, m)
if acc == nil {
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
d.Set("dc_location", acc.DCLocation)
d.Set("resources", flattenAccResources(acc.Resources))
d.Set("ckey", acc.CKey)
d.Set("meta", flattens.FlattenMeta(acc.Meta))
d.Set("acl", flattenAccAcl(acc.Acl))
d.Set("company", acc.Company)
d.Set("companyurl", acc.CompanyUrl)
d.Set("created_by", acc.CreatedBy)
d.Set("created_time", acc.CreatedTime)
d.Set("deactivation_time", acc.DeactiovationTime)
d.Set("deleted_by", acc.DeletedBy)
d.Set("deleted_time", acc.DeletedTime)
d.Set("displayname", acc.DisplayName)
d.Set("guid", acc.GUID)
d.Set("account_id", acc.ID)
d.Set("account_name", acc.Name)
d.Set("resource_limits", flattenRgResourceLimits(acc.ResourceLimits))
d.Set("send_access_emails", acc.SendAccessEmails)
d.Set("service_account", acc.ServiceAccount)
d.Set("status", acc.Status)
d.Set("updated_time", acc.UpdatedTime)
d.Set("version", acc.Version)
d.Set("vins", acc.Vins)
d.Set("vinses", acc.Vinses)
d.Set("computes", flattenAccComputes(acc.Computes))
d.Set("machines", flattenAccMachines(acc.Machines))
hasChanged := false
switch acc.Status {
case status.Destroyed:
d.SetId("")
return resourceAccountCreate(ctx, d, m)
case status.Destroying:
return diag.Errorf("The account is in progress with status: %s", acc.Status)
case status.Deleted:
urlValues := &url.Values{}
urlValues.Add("accountId", d.Id())
_, err := c.DecortAPICall(ctx, "POST", accountRestoreAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
hasChanged = true
case status.Disabled:
log.Debugf("The account is in status: %s, troubles may occur with update. Please, enable account first.", acc.Status)
case status.Confirmed:
}
if hasChanged {
acc, err = utilityAccountCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
}
flattenAccount(d, *acc)
return nil
}
@ -234,11 +239,49 @@ func resourceAccountDelete(ctx context.Context, d *schema.ResourceData, m interf
return nil
}
func resourceAccountEdit(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
func resourceAccountUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceAccountEdit")
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
acc, err := utilityAccountCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
hasChanged := false
switch acc.Status {
case status.Destroyed:
d.SetId("")
return resourceAccountCreate(ctx, d, m)
case status.Destroying:
return diag.Errorf("The account is in progress with status: %s", acc.Status)
case status.Deleted:
urlVal := &url.Values{}
urlVal.Add("accountId", d.Id())
_, err := c.DecortAPICall(ctx, "POST", accountRestoreAPI, urlVal)
if err != nil {
return diag.FromErr(err)
}
hasChanged = true
case status.Disabled:
log.Debugf("The account is in status: %s, troubles may occur with update. Please, enable account first.", acc.Status)
case status.Confirmed:
}
if hasChanged {
acc, err = utilityAccountCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
}
if d.HasChange("enable") {
api := accountDisableAPI
enable := d.Get("enable").(bool)
@ -424,7 +467,7 @@ func resourceAccountEdit(ctx context.Context, d *schema.ResourceData, m interfac
}
return nil
return resourceAccountRead(ctx, d, m)
}
func isContainsUser(els []interface{}, el interface{}) bool {
@ -553,7 +596,6 @@ func resourceAccountSchemaMake() map[string]*schema.Schema {
},
"account_id": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"dc_location": {
@ -564,120 +606,7 @@ func resourceAccountSchemaMake() map[string]*schema.Schema {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"current": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cpu": {
Type: schema.TypeInt,
Computed: true,
},
"disksize": {
Type: schema.TypeFloat,
Computed: true,
},
"extips": {
Type: schema.TypeInt,
Computed: true,
},
"exttraffic": {
Type: schema.TypeInt,
Computed: true,
},
"gpu": {
Type: schema.TypeInt,
Computed: true,
},
"ram": {
Type: schema.TypeInt,
Computed: true,
},
"seps": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"sep_id": {
Type: schema.TypeString,
Computed: true,
},
"data_name": {
Type: schema.TypeString,
Computed: true,
},
"disk_size": {
Type: schema.TypeFloat,
Computed: true,
},
"disk_size_max": {
Type: schema.TypeInt,
Computed: true,
},
},
},
},
},
},
},
"reserved": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cpu": {
Type: schema.TypeInt,
Computed: true,
},
"disksize": {
Type: schema.TypeFloat,
Computed: true,
},
"extips": {
Type: schema.TypeInt,
Computed: true,
},
"exttraffic": {
Type: schema.TypeInt,
Computed: true,
},
"gpu": {
Type: schema.TypeInt,
Computed: true,
},
"ram": {
Type: schema.TypeInt,
Computed: true,
},
"seps": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"sep_id": {
Type: schema.TypeString,
Computed: true,
},
"data_name": {
Type: schema.TypeString,
Computed: true,
},
"disk_size": {
Type: schema.TypeFloat,
Computed: true,
},
"disk_size_max": {
Type: schema.TypeInt,
Computed: true,
},
},
},
},
},
},
},
},
Schema: resourcesSchemaMake(),
},
},
"ckey": {
@ -695,36 +624,7 @@ func resourceAccountSchemaMake() map[string]*schema.Schema {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"can_be_deleted": {
Type: schema.TypeBool,
Computed: true,
},
"explicit": {
Type: schema.TypeBool,
Computed: true,
},
"guid": {
Type: schema.TypeString,
Computed: true,
},
"right": {
Type: schema.TypeString,
Computed: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"type": {
Type: schema.TypeString,
Computed: true,
},
"user_group_id": {
Type: schema.TypeString,
Computed: true,
},
},
Schema: aclSchemaMake(),
},
},
"company": {
@ -790,32 +690,14 @@ func resourceAccountSchemaMake() map[string]*schema.Schema {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"started": {
Type: schema.TypeInt,
Computed: true,
},
"stopped": {
Type: schema.TypeInt,
Computed: true,
},
},
Schema: computesSchemaMake(),
},
},
"machines": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"halted": {
Type: schema.TypeInt,
Computed: true,
},
"running": {
Type: schema.TypeInt,
Computed: true,
},
},
Schema: machinesSchemaMake(),
},
},
"vinses": {
@ -831,7 +713,7 @@ func ResourceAccount() *schema.Resource {
CreateContext: resourceAccountCreate,
ReadContext: resourceAccountRead,
UpdateContext: resourceAccountEdit,
UpdateContext: resourceAccountUpdate,
DeleteContext: resourceAccountDelete,
Importer: &schema.ResourceImporter{

@ -34,8 +34,8 @@ package bservice
import (
"context"
"strconv"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
@ -47,68 +47,11 @@ func dataSourceBasicServiceRead(ctx context.Context, d *schema.ResourceData, m i
return diag.FromErr(err)
}
id := uuid.New()
d.SetId(id.String())
d.Set("account_id", bs.AccountId)
d.Set("account_name", bs.AccountName)
d.Set("base_domain", bs.BaseDomain)
d.Set("computes", flattenBasicServiceComputes(bs.Computes))
d.Set("cpu_total", bs.CPUTotal)
d.Set("created_by", bs.CreatedBy)
d.Set("created_time", bs.CreatedTime)
d.Set("deleted_by", bs.DeletedBy)
d.Set("deleted_time", bs.DeletedTime)
d.Set("disk_total", bs.DiskTotal)
d.Set("gid", bs.GID)
d.Set("groups", bs.Groups)
d.Set("groups_name", bs.GroupsName)
d.Set("guid", bs.GUID)
d.Set("milestones", bs.Milestones)
d.Set("service_name", bs.Name)
d.Set("parent_srv_id", bs.ParentSrvId)
d.Set("parent_srv_type", bs.ParentSrvType)
d.Set("ram_total", bs.RamTotal)
d.Set("rg_id", bs.RGID)
d.Set("rg_name", bs.RGName)
d.Set("snapshots", flattenBasicServiceSnapshots(bs.Snapshots))
d.Set("ssh_key", bs.SSHKey)
d.Set("ssh_user", bs.SSHUser)
d.Set("status", bs.Status)
d.Set("tech_status", bs.TechStatus)
d.Set("updated_by", bs.UpdatedBy)
d.Set("updated_time", bs.UpdatedTime)
d.Set("user_managed", bs.UserManaged)
return nil
}
d.SetId(strconv.Itoa(bs.ID))
func flattenBasicServiceComputes(bscs BasicServiceComputes) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for _, bsc := range bscs {
temp := map[string]interface{}{
"compgroup_id": bsc.CompGroupId,
"compgroup_name": bsc.CompGroupName,
"compgroup_role": bsc.CompGroupRole,
"id": bsc.ID,
"name": bsc.Name,
}
res = append(res, temp)
}
flattenService(d, bs)
return res
}
func flattenBasicServiceSnapshots(bsrvss BasicServiceSnapshots) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for _, bsrvs := range bsrvss {
temp := map[string]interface{}{
"guid": bsrvs.GUID,
"label": bsrvs.Label,
"timestamp": bsrvs.Timestamp,
"valid": bsrvs.Valid,
}
res = append(res, temp)
}
return res
return nil
}
func dataSourceBasicServiceSchemaMake() map[string]*schema.Schema {

@ -0,0 +1,66 @@
package bservice
import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
func flattenService(d *schema.ResourceData, bs *BasicServiceExtend) {
d.Set("account_id", bs.AccountId)
d.Set("account_name", bs.AccountName)
d.Set("base_domain", bs.BaseDomain)
d.Set("computes", flattenBasicServiceComputes(bs.Computes))
d.Set("cpu_total", bs.CPUTotal)
d.Set("created_by", bs.CreatedBy)
d.Set("created_time", bs.CreatedTime)
d.Set("deleted_by", bs.DeletedBy)
d.Set("deleted_time", bs.DeletedTime)
d.Set("disk_total", bs.DiskTotal)
d.Set("gid", bs.GID)
d.Set("groups", bs.Groups)
d.Set("groups_name", bs.GroupsName)
d.Set("guid", bs.GUID)
d.Set("milestones", bs.Milestones)
d.Set("service_name", bs.Name)
d.Set("service_id", bs.ID)
d.Set("parent_srv_id", bs.ParentSrvId)
d.Set("parent_srv_type", bs.ParentSrvType)
d.Set("ram_total", bs.RamTotal)
d.Set("rg_id", bs.RGID)
d.Set("rg_name", bs.RGName)
d.Set("snapshots", flattenBasicServiceSnapshots(bs.Snapshots))
d.Set("ssh_key", bs.SSHKey)
d.Set("ssh_user", bs.SSHUser)
d.Set("status", bs.Status)
d.Set("tech_status", bs.TechStatus)
d.Set("updated_by", bs.UpdatedBy)
d.Set("updated_time", bs.UpdatedTime)
d.Set("user_managed", bs.UserManaged)
}
func flattenBasicServiceComputes(bscs BasicServiceComputes) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for _, bsc := range bscs {
temp := map[string]interface{}{
"compgroup_id": bsc.CompGroupId,
"compgroup_name": bsc.CompGroupName,
"compgroup_role": bsc.CompGroupRole,
"id": bsc.ID,
"name": bsc.Name,
}
res = append(res, temp)
}
return res
}
func flattenBasicServiceSnapshots(bsrvss BasicServiceSnapshots) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for _, bsrvs := range bsrvss {
temp := map[string]interface{}{
"guid": bsrvs.GUID,
"label": bsrvs.Label,
"timestamp": bsrvs.Timestamp,
"valid": bsrvs.Valid,
}
res = append(res, temp)
}
return res
}

@ -42,6 +42,7 @@ import (
log "github.com/sirupsen/logrus"
"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/status"
)
func resourceBasicServiceCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
@ -50,6 +51,15 @@ func resourceBasicServiceCreate(ctx context.Context, d *schema.ResourceData, m i
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
haveRGID, err := existRGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveRGID {
return diag.Errorf("resourceBasicServiceCreate: can't create basic service because RGID %d is not allowed or does not exist", d.Get("rg_id").(int))
}
urlValues.Add("name", d.Get("service_name").(string))
urlValues.Add("rgId", strconv.Itoa(d.Get("rg_id").(int)))
@ -65,8 +75,10 @@ func resourceBasicServiceCreate(ctx context.Context, d *schema.ResourceData, m i
return diag.FromErr(err)
}
serviceIdParsed, _ := strconv.Atoi(serviceId)
d.SetId(serviceId)
d.Set("service_id", serviceId)
d.Set("service_id", serviceIdParsed)
diagnostics := resourceBasicServiceRead(ctx, d, m)
if diagnostics != nil {
@ -79,42 +91,55 @@ func resourceBasicServiceCreate(ctx context.Context, d *schema.ResourceData, m i
func resourceBasicServiceRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceBasicServiceRead")
c := m.(*controller.ControllerCfg)
bs, err := utilityBasicServiceCheckPresence(ctx, d, m)
if bs == nil {
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
d.Set("account_id", bs.AccountId)
d.Set("account_name", bs.AccountName)
d.Set("base_domain", bs.BaseDomain)
d.Set("computes", flattenBasicServiceComputes(bs.Computes))
d.Set("cpu_total", bs.CPUTotal)
d.Set("created_by", bs.CreatedBy)
d.Set("created_time", bs.CreatedTime)
d.Set("deleted_by", bs.DeletedBy)
d.Set("deleted_time", bs.DeletedTime)
d.Set("disk_total", bs.DiskTotal)
d.Set("gid", bs.GID)
d.Set("groups", bs.Groups)
d.Set("groups_name", bs.GroupsName)
d.Set("guid", bs.GUID)
d.Set("milestones", bs.Milestones)
d.Set("service_name", bs.Name)
d.Set("service_id", bs.ID)
d.Set("parent_srv_id", bs.ParentSrvId)
d.Set("parent_srv_type", bs.ParentSrvType)
d.Set("ram_total", bs.RamTotal)
d.Set("rg_id", bs.RGID)
d.Set("rg_name", bs.RGName)
d.Set("snapshots", flattenBasicServiceSnapshots(bs.Snapshots))
d.Set("ssh_key", bs.SSHKey)
d.Set("ssh_user", bs.SSHUser)
d.Set("status", bs.Status)
d.Set("tech_status", bs.TechStatus)
d.Set("updated_by", bs.UpdatedBy)
d.Set("updated_time", bs.UpdatedTime)
d.Set("user_managed", bs.UserManaged)
hasChanged := false
switch bs.Status {
case status.Modeled:
return diag.Errorf("The basic service is in status: %s, please, contact support for more information", bs.Status)
case status.Created:
case status.Enabled:
case status.Enabling:
case status.Disabled:
log.Debugf("The basic service is in status: %s, troubles can occur with the update. Please, enable bservice first.", bs.Status)
case status.Disabling:
log.Debugf("The basic service is in status: %s, troubles can occur with the update.", bs.Status)
case status.Deleted:
urlVal := &url.Values{}
urlVal.Add("serviceId", d.Id())
_, err := c.DecortAPICall(ctx, "POST", bserviceRestoreAPI, urlVal)
if err != nil {
return diag.FromErr(err)
}
hasChanged = true
case status.Deleting:
case status.Destroyed:
d.SetId("")
return resourceBasicServiceCreate(ctx, d, m)
case status.Destroying:
return diag.Errorf("The basic service is in progress with status: %s", bs.Status)
case status.Restoring:
case status.Reconfiguring:
}
if hasChanged {
bs, err = utilityBasicServiceCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
}
flattenService(d, bs)
return nil
}
@ -144,10 +169,65 @@ func resourceBasicServiceDelete(ctx context.Context, d *schema.ResourceData, m i
return nil
}
func resourceBasicServiceEdit(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
func resourceBasicServiceUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceBasicServiceEdit")
c := m.(*controller.ControllerCfg)
haveRGID, err := existRGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveRGID {
return diag.Errorf("resourceBasicServiceUpdate: can't create basic service because RGID %d is not allowed or does not exist", d.Get("rg_id").(int))
}
bs, err := utilityBasicServiceCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
hasChanged := false
switch bs.Status {
case status.Modeled:
return diag.Errorf("The basic service is in status: %s, please, contact support for more information", bs.Status)
case status.Created:
case status.Enabled:
case status.Enabling:
case status.Disabled:
log.Debugf("The basic service is in status: %s, troubles can occur with the update. Please, enable bservice first.", bs.Status)
case status.Disabling:
log.Debugf("The basic service is in status: %s, troubles can occur with the update.", bs.Status)
case status.Deleted:
urlVal := &url.Values{}
urlVal.Add("serviceId", d.Id())
_, err := c.DecortAPICall(ctx, "POST", bserviceRestoreAPI, urlVal)
if err != nil {
return diag.FromErr(err)
}
hasChanged = true
case status.Deleting:
case status.Destroyed:
d.SetId("")
return resourceBasicServiceCreate(ctx, d, m)
case status.Destroying:
return diag.Errorf("The basic service is in progress with status: %s", bs.Status)
case status.Restoring:
case status.Reconfiguring:
}
if hasChanged {
bs, err = utilityBasicServiceCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
}
urlValues := &url.Values{}
if d.HasChange("enable") {
api := bserviceDisableAPI
@ -508,7 +588,7 @@ func ResourceBasicService() *schema.Resource {
CreateContext: resourceBasicServiceCreate,
ReadContext: resourceBasicServiceRead,
UpdateContext: resourceBasicServiceEdit,
UpdateContext: resourceBasicServiceUpdate,
DeleteContext: resourceBasicServiceDelete,
Importer: &schema.ResourceImporter{

@ -0,0 +1,42 @@
package bservice
import (
"context"
"encoding/json"
"net/url"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
)
func existRGID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
rgList := []struct {
ID int `json:"id"`
}{}
rgListAPI := "/restmachine/cloudapi/rg/list"
rgListRaw, err := c.DecortAPICall(ctx, "POST", rgListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(rgListRaw), &rgList)
if err != nil {
return false, err
}
haveRG := false
rgId := d.Get("rg_id").(int)
for _, rg := range rgList {
if rg.ID == rgId {
haveRG = true
break
}
}
return haveRG, nil
}

@ -34,7 +34,6 @@ package disks
import (
"context"
"encoding/json"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@ -42,117 +41,6 @@ import (
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
)
func flattenDiskComputes(computes map[string]string) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for computeKey, computeVal := range computes {
temp := map[string]interface{}{
"compute_id": computeKey,
"compute_name": computeVal,
}
res = append(res, temp)
}
return res
}
func flattenIOTune(iot IOTune) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
temp := map[string]interface{}{
"read_bytes_sec": iot.ReadBytesSec,
"read_bytes_sec_max": iot.ReadBytesSecMax,
"read_iops_sec": iot.ReadIopsSec,
"read_iops_sec_max": iot.ReadIopsSecMax,
"size_iops_sec": iot.SizeIopsSec,
"total_bytes_sec": iot.TotalBytesSec,
"total_bytes_sec_max": iot.TotalBytesSecMax,
"total_iops_sec": iot.TotalIopsSec,
"total_iops_sec_max": iot.TotalIopsSecMax,
"write_bytes_sec": iot.WriteBytesSec,
"write_bytes_sec_max": iot.WriteBytesSecMax,
"write_iops_sec": iot.WriteIopsSec,
"write_iops_sec_max": iot.WriteIopsSecMax,
}
res = append(res, temp)
return res
}
func flattenDiskList(dl DisksList) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for _, disk := range dl {
diskAcl, _ := json.Marshal(disk.Acl)
temp := map[string]interface{}{
"account_id": disk.AccountID,
"account_name": disk.AccountName,
"acl": string(diskAcl),
"computes": flattenDiskComputes(disk.Computes),
"boot_partition": disk.BootPartition,
"created_time": disk.CreatedTime,
"deleted_time": disk.DeletedTime,
"desc": disk.Desc,
"destruction_time": disk.DestructionTime,
"devicename": disk.DeviceName,
"disk_path": disk.DiskPath,
"gid": disk.GridID,
"guid": disk.GUID,
"disk_id": disk.ID,
"image_id": disk.ImageID,
"images": disk.Images,
"iotune": flattenIOTune(disk.IOTune),
"iqn": disk.IQN,
"login": disk.Login,
"machine_id": disk.MachineId,
"machine_name": disk.MachineName,
"milestones": disk.Milestones,
"disk_name": disk.Name,
"order": disk.Order,
"params": disk.Params,
"parent_id": disk.ParentId,
"passwd": disk.Passwd,
"pci_slot": disk.PciSlot,
"pool": disk.Pool,
"present_to": disk.PresentTo,
"purge_attempts": disk.PurgeAttempts,
"purge_time": disk.PurgeTime,
"reality_device_number": disk.RealityDeviceNumber,
"reference_id": disk.ReferenceId,
"res_id": disk.ResID,
"res_name": disk.ResName,
"role": disk.Role,
"sep_id": disk.SepID,
"sep_type": disk.SepType,
"shareable": disk.Shareable,
"size_max": disk.SizeMax,
"size_used": disk.SizeUsed,
"snapshots": flattenDiskSnapshotList(disk.Snapshots),
"status": disk.Status,
"tech_status": disk.TechStatus,
"type": disk.Type,
"vmid": disk.VMID,
}
res = append(res, temp)
}
return res
}
func flattenDiskSnapshotList(sl SnapshotList) []interface{} {
res := make([]interface{}, 0)
for _, snapshot := range sl {
temp := map[string]interface{}{
"guid": snapshot.Guid,
"label": snapshot.Label,
"res_id": snapshot.ResId,
"snap_set_guid": snapshot.SnapSetGuid,
"snap_set_time": snapshot.SnapSetTime,
"timestamp": snapshot.TimeStamp,
}
res = append(res, temp)
}
return res
}
func dataSourceDiskListRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
diskList, err := utilityDiskListCheckPresence(ctx, d, m, disksListAPI)
if err != nil {

@ -0,0 +1,166 @@
package disks
import (
"encoding/json"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func flattenDisk(d *schema.ResourceData, disk Disk) {
diskAcl, _ := json.Marshal(disk.Acl)
d.Set("account_id", disk.AccountID)
d.Set("account_name", disk.AccountName)
d.Set("acl", string(diskAcl))
d.Set("boot_partition", disk.BootPartition)
d.Set("computes", flattenDiskComputes(disk.Computes))
d.Set("created_time", disk.CreatedTime)
d.Set("deleted_time", disk.DeletedTime)
d.Set("desc", disk.Desc)
d.Set("destruction_time", disk.DestructionTime)
d.Set("devicename", disk.DeviceName)
d.Set("disk_path", disk.DiskPath)
d.Set("gid", disk.GridID)
d.Set("guid", disk.GUID)
d.Set("disk_id", disk.ID)
d.Set("image_id", disk.ImageID)
d.Set("images", disk.Images)
d.Set("iotune", flattenIOTune(disk.IOTune))
d.Set("iqn", disk.IQN)
d.Set("login", disk.Login)
d.Set("milestones", disk.Milestones)
d.Set("disk_name", disk.Name)
d.Set("order", disk.Order)
d.Set("params", disk.Params)
d.Set("parent_id", disk.ParentId)
d.Set("passwd", disk.Passwd)
d.Set("pci_slot", disk.PciSlot)
d.Set("pool", disk.Pool)
d.Set("present_to", disk.PresentTo)
d.Set("purge_attempts", disk.PurgeAttempts)
d.Set("purge_time", disk.PurgeTime)
d.Set("reality_device_number", disk.RealityDeviceNumber)
d.Set("reference_id", disk.ReferenceId)
d.Set("res_id", disk.ResID)
d.Set("res_name", disk.ResName)
d.Set("role", disk.Role)
d.Set("sep_id", disk.SepID)
d.Set("sep_type", disk.SepType)
d.Set("size_max", disk.SizeMax)
d.Set("size_used", disk.SizeUsed)
d.Set("shareable", disk.Shareable)
d.Set("snapshots", flattenDiskSnapshotList(disk.Snapshots))
d.Set("status", disk.Status)
d.Set("tech_status", disk.TechStatus)
d.Set("type", disk.Type)
d.Set("vmid", disk.VMID)
}
func flattenDiskSnapshotList(sl SnapshotList) []interface{} {
res := make([]interface{}, 0)
for _, snapshot := range sl {
temp := map[string]interface{}{
"guid": snapshot.Guid,
"label": snapshot.Label,
"res_id": snapshot.ResId,
"snap_set_guid": snapshot.SnapSetGuid,
"snap_set_time": snapshot.SnapSetTime,
"timestamp": snapshot.TimeStamp,
}
res = append(res, temp)
}
return res
}
func flattenDiskList(dl DisksList) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for _, disk := range dl {
diskAcl, _ := json.Marshal(disk.Acl)
temp := map[string]interface{}{
"account_id": disk.AccountID,
"account_name": disk.AccountName,
"acl": string(diskAcl),
"computes": flattenDiskComputes(disk.Computes),
"boot_partition": disk.BootPartition,
"created_time": disk.CreatedTime,
"deleted_time": disk.DeletedTime,
"desc": disk.Desc,
"destruction_time": disk.DestructionTime,
"devicename": disk.DeviceName,
"disk_path": disk.DiskPath,
"gid": disk.GridID,
"guid": disk.GUID,
"disk_id": disk.ID,
"image_id": disk.ImageID,
"images": disk.Images,
"iotune": flattenIOTune(disk.IOTune),
"iqn": disk.IQN,
"login": disk.Login,
"machine_id": disk.MachineId,
"machine_name": disk.MachineName,
"milestones": disk.Milestones,
"disk_name": disk.Name,
"order": disk.Order,
"params": disk.Params,
"parent_id": disk.ParentId,
"passwd": disk.Passwd,
"pci_slot": disk.PciSlot,
"pool": disk.Pool,
"present_to": disk.PresentTo,
"purge_attempts": disk.PurgeAttempts,
"purge_time": disk.PurgeTime,
"reality_device_number": disk.RealityDeviceNumber,
"reference_id": disk.ReferenceId,
"res_id": disk.ResID,
"res_name": disk.ResName,
"role": disk.Role,
"sep_id": disk.SepID,
"sep_type": disk.SepType,
"shareable": disk.Shareable,
"size_max": disk.SizeMax,
"size_used": disk.SizeUsed,
"snapshots": flattenDiskSnapshotList(disk.Snapshots),
"status": disk.Status,
"tech_status": disk.TechStatus,
"type": disk.Type,
"vmid": disk.VMID,
}
res = append(res, temp)
}
return res
}
func flattenIOTune(iot IOTune) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
temp := map[string]interface{}{
"read_bytes_sec": iot.ReadBytesSec,
"read_bytes_sec_max": iot.ReadBytesSecMax,
"read_iops_sec": iot.ReadIopsSec,
"read_iops_sec_max": iot.ReadIopsSecMax,
"size_iops_sec": iot.SizeIopsSec,
"total_bytes_sec": iot.TotalBytesSec,
"total_bytes_sec_max": iot.TotalBytesSecMax,
"total_iops_sec": iot.TotalIopsSec,
"total_iops_sec_max": iot.TotalIopsSecMax,
"write_bytes_sec": iot.WriteBytesSec,
"write_bytes_sec_max": iot.WriteBytesSecMax,
"write_iops_sec": iot.WriteIopsSec,
"write_iops_sec_max": iot.WriteIopsSecMax,
}
res = append(res, temp)
return res
}
func flattenDiskComputes(computes map[string]string) []map[string]interface{} {
res := make([]map[string]interface{}, 0)
for computeKey, computeVal := range computes {
temp := map[string]interface{}{
"compute_id": computeKey,
"compute_name": computeVal,
}
res = append(res, temp)
}
return res
}

@ -0,0 +1,77 @@
package disks
import (
"context"
"encoding/json"
"net/url"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
)
func existAccountID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
accountList := []struct {
ID int `json:"id"`
}{}
accountListAPI := "/restmachine/cloudapi/account/list"
accountListRaw, err := c.DecortAPICall(ctx, "POST", accountListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(accountListRaw), &accountList)
if err != nil {
return false, err
}
haveAccount := false
myAccount := d.Get("account_id").(int)
for _, account := range accountList {
if account.ID == myAccount {
haveAccount = true
break
}
}
return haveAccount, nil
}
func existGID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
locationList := []struct {
GID int `json:"gid"`
}{}
locationsListAPI := "/restmachine/cloudapi/locations/list"
locationListRaw, err := c.DecortAPICall(ctx, "POST", locationsListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(locationListRaw), &locationList)
if err != nil {
return false, err
}
haveGID := false
gid := d.Get("gid").(int)
for _, location := range locationList {
if location.GID == gid {
haveGID = true
break
}
}
return haveGID, nil
}

@ -34,17 +34,16 @@ package disks
import (
"context"
"encoding/json"
"fmt"
"net/url"
"strconv"
"strings"
log "github.com/sirupsen/logrus"
"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/dc"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/status"
log "github.com/sirupsen/logrus"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@ -55,10 +54,26 @@ func resourceDiskCreate(ctx context.Context, d *schema.ResourceData, m interface
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("accountId", fmt.Sprintf("%d", d.Get("account_id").(int)))
urlValues.Add("gid", fmt.Sprintf("%d", d.Get("gid").(int)))
haveAccount, err := existAccountID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveAccount {
return diag.Errorf("resourceDiskCreate: can't create Disk because AccountID %d is not allowed or does not exist", d.Get("account_id").(int))
}
haveGID, err := existGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveGID {
return diag.Errorf("resourceDiskCreate: can't create Disk because GID %d is not allowed or does not exist", d.Get("gid").(int))
}
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
urlValues.Add("gid", strconv.Itoa(d.Get("gid").(int)))
urlValues.Add("name", d.Get("disk_name").(string))
urlValues.Add("size", fmt.Sprintf("%d", d.Get("size_max").(int)))
urlValues.Add("size", strconv.Itoa(d.Get("size_max").(int)))
if typeRaw, ok := d.GetOk("type"); ok {
urlValues.Add("type", strings.ToUpper(typeRaw.(string)))
} else {
@ -85,7 +100,7 @@ func resourceDiskCreate(ctx context.Context, d *schema.ResourceData, m interface
urlValues = &url.Values{}
d.SetId(diskId) // update ID of the resource to tell Terraform that the disk resource exists
d.SetId(diskId)
if iotuneRaw, ok := d.GetOk("iotune"); ok {
iot := iotuneRaw.([]interface{})[0]
@ -136,19 +151,18 @@ func resourceDiskRead(ctx context.Context, d *schema.ResourceData, m interface{}
warnings := dc.Warnings{}
disk, err := utilityDiskCheckPresence(ctx, d, m)
if disk == nil {
d.SetId("")
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
return nil
}
hasChangeState := false
if disk.Status == status.Destroyed || disk.Status == status.Purged {
switch disk.Status {
case status.Destroyed, status.Purged:
d.Set("disk_id", 0)
return resourceDiskCreate(ctx, d, m)
} else if disk.Status == status.Deleted {
case status.Deleted:
hasChangeState = true
urlValues.Add("diskId", d.Id())
urlValues.Add("reason", d.Get("reason").(string))
@ -157,79 +171,84 @@ func resourceDiskRead(ctx context.Context, d *schema.ResourceData, m interface{}
if err != nil {
warnings.Add(err)
}
case status.Assigned:
case status.Modeled:
return diag.Errorf("The disk is in status: %s, please, contact support for more information", disk.Status)
case status.Creating:
case status.Created:
case status.Allocated:
case status.Unallocated:
}
if hasChangeState {
urlValues = &url.Values{}
disk, err = utilityDiskCheckPresence(ctx, d, m)
if disk == nil {
d.SetId("")
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
return nil
}
}
diskAcl, _ := json.Marshal(disk.Acl)
d.Set("account_id", disk.AccountID)
d.Set("account_name", disk.AccountName)
d.Set("acl", string(diskAcl))
d.Set("boot_partition", disk.BootPartition)
d.Set("computes", flattenDiskComputes(disk.Computes))
d.Set("created_time", disk.CreatedTime)
d.Set("deleted_time", disk.DeletedTime)
d.Set("desc", disk.Desc)
d.Set("destruction_time", disk.DestructionTime)
d.Set("devicename", disk.DeviceName)
d.Set("disk_path", disk.DiskPath)
d.Set("gid", disk.GridID)
d.Set("guid", disk.GUID)
d.Set("disk_id", disk.ID)
d.Set("image_id", disk.ImageID)
d.Set("images", disk.Images)
d.Set("iotune", flattenIOTune(disk.IOTune))
d.Set("iqn", disk.IQN)
d.Set("login", disk.Login)
d.Set("milestones", disk.Milestones)
d.Set("disk_name", disk.Name)
d.Set("order", disk.Order)
d.Set("params", disk.Params)
d.Set("parent_id", disk.ParentId)
d.Set("passwd", disk.Passwd)
d.Set("pci_slot", disk.PciSlot)
d.Set("pool", disk.Pool)
d.Set("present_to", disk.PresentTo)
d.Set("purge_attempts", disk.PurgeAttempts)
d.Set("purge_time", disk.PurgeTime)
d.Set("reality_device_number", disk.RealityDeviceNumber)
d.Set("reference_id", disk.ReferenceId)
d.Set("res_id", disk.ResID)
d.Set("res_name", disk.ResName)
d.Set("role", disk.Role)
d.Set("sep_id", disk.SepID)
d.Set("sep_type", disk.SepType)
d.Set("size_max", disk.SizeMax)
d.Set("size_used", disk.SizeUsed)
d.Set("shareable", disk.Shareable)
d.Set("snapshots", flattenDiskSnapshotList(disk.Snapshots))
d.Set("status", disk.Status)
d.Set("tech_status", disk.TechStatus)
d.Set("type", disk.Type)
d.Set("vmid", disk.VMID)
flattenDisk(d, *disk)
return warnings.Get()
}
func resourceDiskUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := m.(*controller.ControllerCfg)
warnings := dc.Warnings{}
urlValues := &url.Values{}
haveAccount, err := existAccountID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveAccount {
return diag.Errorf("resourceDiskUpdate: can't update Disk because AccountID %d is not allowed or does not exist", d.Get("account_id").(int))
}
haveGID, err := existGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveGID {
return diag.Errorf("resourceDiskUpdate: can't update Disk because GID %d is not allowed or does not exist", d.Get("gid").(int))
}
disk, err := utilityDiskCheckPresence(ctx, d, m)
if disk == nil {
if err != nil {
return diag.FromErr(err)
}
return nil
hasChangeState := false
switch disk.Status {
case status.Destroyed, status.Purged:
d.Set("disk_id", 0)
return resourceDiskCreate(ctx, d, m)
case status.Deleted:
hasChangeState = true
urlValues.Add("diskId", d.Id())
urlValues.Add("reason", d.Get("reason").(string))
_, err := c.DecortAPICall(ctx, "POST", disksRestoreAPI, urlValues)
if err != nil {
warnings.Add(err)
}
case status.Assigned:
case status.Modeled:
return diag.Errorf("The disk is in status: %s, please, contact support for more information", disk.Status)
case status.Creating:
case status.Created:
case status.Allocated:
case status.Unallocated:
}
if hasChangeState {
disk, err = utilityDiskCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
}
if d.HasChange("size_max") {
@ -238,7 +257,7 @@ func resourceDiskUpdate(ctx context.Context, d *schema.ResourceData, m interface
log.Debugf("resourceDiskUpdate: resizing disk ID %s - %d GB -> %d GB",
d.Id(), oldSize.(int), newSize.(int))
urlValues.Add("diskId", d.Id())
urlValues.Add("size", fmt.Sprintf("%d", newSize.(int)))
urlValues.Add("size", strconv.Itoa(newSize.(int)))
_, err := c.DecortAPICall(ctx, "POST", disksResizeAPI, urlValues)
if err != nil {
return diag.FromErr(err)
@ -310,12 +329,10 @@ func resourceDiskUpdate(ctx context.Context, d *schema.ResourceData, m interface
func resourceDiskDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
disk, err := utilityDiskCheckPresence(ctx, d, m)
if disk == nil {
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
return nil
}
if disk.Status == status.Destroyed || disk.Status == status.Purged {
return nil
}
@ -363,13 +380,6 @@ func resourceDiskSchemaMake() map[string]*schema.Schema {
Computed: true,
Description: "Pool for disk location",
},
"present_to": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeInt,
},
},
"sep_id": {
Type: schema.TypeInt,
Optional: true,
@ -412,85 +422,6 @@ func resourceDiskSchemaMake() map[string]*schema.Schema {
Optional: true,
Computed: true,
},
"disk_id": {
Type: schema.TypeInt,
Computed: true,
Description: "Disk ID. Duplicates the value of the ID parameter",
},
"account_name": {
Type: schema.TypeString,
Computed: true,
Description: "The name of the subscriber '(account') to whom this disk belongs",
},
"acl": {
Type: schema.TypeString,
Computed: true,
},
"boot_partition": {
Type: schema.TypeInt,
Computed: true,
Description: "Number of disk partitions",
},
"computes": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"compute_id": {
Type: schema.TypeString,
Computed: true,
},
"compute_name": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
"created_time": {
Type: schema.TypeInt,
Computed: true,
Description: "Created time",
},
"deleted_time": {
Type: schema.TypeInt,
Computed: true,
Description: "Deleted time",
},
"destruction_time": {
Type: schema.TypeInt,
Computed: true,
Description: "Time of final deletion",
},
"devicename": {
Type: schema.TypeString,
Computed: true,
Description: "Name of the device",
},
"disk_path": {
Type: schema.TypeString,
Computed: true,
Description: "Disk path",
},
"guid": {
Type: schema.TypeInt,
Computed: true,
Description: "Disk ID on the storage side",
},
"image_id": {
Type: schema.TypeInt,
Computed: true,
Description: "Image ID",
},
"images": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Description: "IDs of images using the disk",
},
"iotune": {
Type: schema.TypeList,
Optional: true,
@ -579,6 +510,91 @@ func resourceDiskSchemaMake() map[string]*schema.Schema {
},
},
},
"present_to": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeInt,
},
},
"disk_id": {
Type: schema.TypeInt,
Computed: true,
Description: "Disk ID. Duplicates the value of the ID parameter",
},
"account_name": {
Type: schema.TypeString,
Computed: true,
Description: "The name of the subscriber '(account') to whom this disk belongs",
},
"acl": {
Type: schema.TypeString,
Computed: true,
},
"boot_partition": {
Type: schema.TypeInt,
Computed: true,
Description: "Number of disk partitions",
},
"computes": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"compute_id": {
Type: schema.TypeString,
Computed: true,
},
"compute_name": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
"created_time": {
Type: schema.TypeInt,
Computed: true,
Description: "Created time",
},
"deleted_time": {
Type: schema.TypeInt,
Computed: true,
Description: "Deleted time",
},
"destruction_time": {
Type: schema.TypeInt,
Computed: true,
Description: "Time of final deletion",
},
"devicename": {
Type: schema.TypeString,
Computed: true,
Description: "Name of the device",
},
"disk_path": {
Type: schema.TypeString,
Computed: true,
Description: "Disk path",
},
"guid": {
Type: schema.TypeInt,
Computed: true,
Description: "Disk ID on the storage side",
},
"image_id": {
Type: schema.TypeInt,
Computed: true,
Description: "Image ID",
},
"images": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Description: "IDs of images using the disk",
},
"iqn": {
Type: schema.TypeString,
Computed: true,

@ -39,21 +39,20 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
log "github.com/sirupsen/logrus"
)
func resourceDiskSnapshotCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
urlValues := &url.Values{}
c := m.(*controller.ControllerCfg)
disk, err := utilityDiskCheckPresence(ctx, d, m)
if disk == nil {
if err != nil {
return diag.FromErr(err)
}
return nil
}
snapshots := disk.Snapshots
snapshot := Snapshot{}
label := d.Get("label").(string)
@ -190,17 +189,17 @@ func resourceDiskSnapshotSchemaMake() map[string]*schema.Schema {
Default: false,
Description: "Needed in order to make a snapshot rollback",
},
"guid": {
Type: schema.TypeString,
Computed: true,
Description: "ID of the snapshot",
},
"timestamp": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
Description: "Snapshot time",
},
"guid": {
Type: schema.TypeString,
Computed: true,
Description: "ID of the snapshot",
},
"res_id": {
Type: schema.TypeString,
Computed: true,

@ -38,8 +38,8 @@ import (
"net/url"
"strconv"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
@ -50,11 +50,15 @@ func utilityDiskCheckPresence(ctx context.Context, d *schema.ResourceData, m int
disk := &Disk{}
if d.Get("disk_id") != nil {
if d.Get("disk_id").(int) == 0 {
urlValues.Add("diskId", d.Id())
} else {
urlValues.Add("diskId", strconv.Itoa(d.Get("disk_id").(int)))
}
} else {
urlValues.Add("diskId", strconv.Itoa(d.Get("disk_id").(int)))
}
log.Debugf("utilityDiskCheckPresence: load disk")
diskRaw, err := c.DecortAPICall(ctx, "POST", disksGetAPI, urlValues)

@ -41,59 +41,6 @@ import (
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
)
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
}
func flattenImage(d *schema.ResourceData, img *ImageExtend) {
d.Set("unc_path", img.UNCPath)
d.Set("ckey", img.CKey)
d.Set("account_id", img.AccountId)
d.Set("acl", img.Acl)
d.Set("architecture", img.Architecture)
d.Set("boot_type", img.BootType)
d.Set("bootable", img.Bootable)
d.Set("compute_ci_id", img.ComputeCiId)
d.Set("deleted_time", img.DeletedTime)
d.Set("desc", img.Description)
d.Set("drivers", img.Drivers)
d.Set("enabled", img.Enabled)
d.Set("gid", img.GridId)
d.Set("guid", img.GUID)
d.Set("history", flattenHistory(img.History))
d.Set("hot_resize", img.HotResize)
d.Set("image_id", img.Id)
d.Set("last_modified", img.LastModified)
d.Set("link_to", img.LinkTo)
d.Set("milestones", img.Milestones)
d.Set("image_name", img.Name)
d.Set("password", img.Password)
d.Set("pool_name", img.Pool)
d.Set("provider_name", img.ProviderName)
d.Set("purge_attempts", img.PurgeAttempts)
d.Set("present_to", img.PresentTo)
d.Set("res_id", img.ResId)
d.Set("rescuecd", img.RescueCD)
d.Set("sep_id", img.SepId)
d.Set("shared_with", img.SharedWith)
d.Set("size", img.Size)
d.Set("status", img.Status)
d.Set("tech_status", img.TechStatus)
d.Set("type", img.Type)
d.Set("username", img.Username)
d.Set("version", img.Version)
}
func dataSourceImageRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
image, err := utilityImageCheckPresence(ctx, d, m)
if err != nil {

@ -0,0 +1,56 @@
package image
import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
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
}
func flattenImage(d *schema.ResourceData, img *ImageExtend) {
d.Set("unc_path", img.UNCPath)
d.Set("ckey", img.CKey)
d.Set("account_id", img.AccountId)
d.Set("acl", img.Acl)
d.Set("architecture", img.Architecture)
d.Set("boot_type", img.BootType)
d.Set("bootable", img.Bootable)
d.Set("compute_ci_id", img.ComputeCiId)
d.Set("deleted_time", img.DeletedTime)
d.Set("desc", img.Description)
d.Set("drivers", img.Drivers)
d.Set("enabled", img.Enabled)
d.Set("gid", img.GridId)
d.Set("guid", img.GUID)
d.Set("history", flattenHistory(img.History))
d.Set("hot_resize", img.HotResize)
d.Set("image_id", img.Id)
d.Set("last_modified", img.LastModified)
d.Set("link_to", img.LinkTo)
d.Set("milestones", img.Milestones)
d.Set("image_name", img.Name)
d.Set("password", img.Password)
d.Set("pool_name", img.Pool)
d.Set("provider_name", img.ProviderName)
d.Set("purge_attempts", img.PurgeAttempts)
d.Set("present_to", img.PresentTo)
d.Set("res_id", img.ResId)
d.Set("rescuecd", img.RescueCD)
d.Set("sep_id", img.SepId)
d.Set("shared_with", img.SharedWith)
d.Set("size", img.Size)
d.Set("status", img.Status)
d.Set("tech_status", img.TechStatus)
d.Set("type", img.Type)
d.Set("username", img.Username)
d.Set("version", img.Version)
}

@ -0,0 +1,77 @@
package image
import (
"context"
"encoding/json"
"net/url"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
)
func existAccountID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
accountList := []struct {
ID int `json:"id"`
}{}
accountListAPI := "/restmachine/cloudapi/account/list"
accountListRaw, err := c.DecortAPICall(ctx, "POST", accountListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(accountListRaw), &accountList)
if err != nil {
return false, err
}
haveAccount := false
myAccount := d.Get("account_id").(int)
for _, account := range accountList {
if account.ID == myAccount {
haveAccount = true
break
}
}
return haveAccount, nil
}
func existGID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
locationList := []struct {
GID int `json:"gid"`
}{}
locationsListAPI := "/restmachine/cloudapi/locations/list"
locationListRaw, err := c.DecortAPICall(ctx, "POST", locationsListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(locationListRaw), &locationList)
if err != nil {
return false, err
}
haveGID := false
gid := d.Get("gid").(int)
for _, location := range locationList {
if location.GID == gid {
haveGID = true
break
}
}
return haveGID, nil
}

@ -40,14 +40,35 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/status"
)
func resourceImageCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceImageCreate: called for image %s", d.Get("name").(string))
haveGID, err := existGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveGID {
return diag.Errorf("resourceImageCreate: can't create Image because GID %d is not allowed or does not exist", d.Get("gid").(int))
}
if _, ok := d.GetOk("account_id"); ok {
haveAccountID, err := existAccountID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveAccountID {
return diag.Errorf("resourceImageCreate: can't create Image because AccountID %d is not allowed or does not exist", d.Get("account_id").(int))
}
}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("name", d.Get("name").(string))
@ -96,13 +117,7 @@ func resourceImageCreate(ctx context.Context, d *schema.ResourceData, m interfac
if architecture, ok := d.GetOk("architecture"); ok {
urlValues.Add("architecture", architecture.(string))
}
/* uncomment then OK
imageId, err := c.DecortAPICall(ctx, "POST", imageCreateAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
*/
//innovation
res, err := c.DecortAPICall(ctx, "POST", imageCreateAPI, urlValues)
if err != nil {
return diag.FromErr(err)
@ -141,41 +156,17 @@ func resourceImageRead(ctx context.Context, d *schema.ResourceData, m interface{
return diag.FromErr(err)
}
d.Set("unc_path", img.UNCPath)
d.Set("ckey", img.CKey)
d.Set("account_id", img.AccountId)
d.Set("acl", img.Acl)
d.Set("architecture", img.Architecture)
d.Set("boot_type", img.BootType)
d.Set("bootable", img.Bootable)
d.Set("compute_ci_id", img.ComputeCiId)
d.Set("deleted_time", img.DeletedTime)
d.Set("desc", img.Description)
d.Set("drivers", img.Drivers)
d.Set("enabled", img.Enabled)
d.Set("gid", img.GridId)
d.Set("guid", img.GUID)
d.Set("history", flattenHistory(img.History))
d.Set("hot_resize", img.HotResize)
d.Set("image_id", img.Id)
d.Set("last_modified", img.LastModified)
d.Set("link_to", img.LinkTo)
d.Set("milestones", img.Milestones)
d.Set("image_name", img.Name)
d.Set("password", img.Password)
d.Set("pool_name", img.Pool)
d.Set("provider_name", img.ProviderName)
d.Set("purge_attempts", img.PurgeAttempts)
d.Set("res_id", img.ResId)
d.Set("rescuecd", img.RescueCD)
d.Set("sep_id", img.SepId)
d.Set("shared_with", img.SharedWith)
d.Set("size", img.Size)
d.Set("status", img.Status)
d.Set("tech_status", img.TechStatus)
d.Set("type", img.Type)
d.Set("username", img.Username)
d.Set("version", img.Version)
switch img.Status {
case status.Modeled:
return diag.Errorf("The image is in status: %s, please, contact support for more information", img.Status)
case status.Creating:
case status.Created:
case status.Destroyed, status.Purged:
d.SetId("")
return resourceImageCreate(ctx, d, m)
}
flattenImage(d, img)
return nil
}
@ -222,9 +213,47 @@ func resourceImageEditName(ctx context.Context, d *schema.ResourceData, m interf
return nil
}
func resourceImageEdit(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
func resourceImageUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceImageEdit: called for %s, id: %s", d.Get("name").(string), d.Id())
haveGID, err := existGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveGID {
return diag.Errorf("resourceImageUpdate: can't update Image because GID %d is not allowed or does not exist", d.Get("gid").(int))
}
if _, ok := d.GetOk("account_id"); ok {
haveAccountID, err := existAccountID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveAccountID {
return diag.Errorf("resourceImageUpdate: can't update Image because AccountID %d is not allowed or does not exist", d.Get("account_id").(int))
}
}
image, err := utilityImageCheckPresence(ctx, d, m)
if image == nil {
if err != nil {
return diag.FromErr(err)
}
return nil
}
switch image.Status {
case status.Modeled:
return diag.Errorf("The image is in status: %s, please, contact support for more information", image.Status)
case status.Creating:
case status.Created:
case status.Destroyed, status.Purged:
d.SetId("")
return resourceImageCreate(ctx, d, m)
}
if d.HasChange("name") {
err := resourceImageEditName(ctx, d, m)
if err != nil {
@ -241,7 +270,7 @@ func ResourceImage() *schema.Resource {
CreateContext: resourceImageCreate,
ReadContext: resourceImageRead,
UpdateContext: resourceImageEdit,
UpdateContext: resourceImageUpdate,
DeleteContext: resourceImageDelete,
Importer: &schema.ResourceImporter{

@ -39,6 +39,8 @@ const (
K8sDeleteAPI = "/restmachine/cloudapi/k8s/delete"
K8sListAPI = "/restmachine/cloudapi/k8s/list"
K8sListDeletedAPI = "/restmachine/cloudapi/k8s/listDeleted"
K8sRestoreAPI = "/restmachine/cloudapi/k8s/restore"
K8sEnableAPI = "/restmachine/cloudapi/k8s/enable"
K8sWgCreateAPI = "/restmachine/cloudapi/k8s/workersGroupAdd"
K8sWgDeleteAPI = "/restmachine/cloudapi/k8s/workersGroupDelete"

@ -38,51 +38,21 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"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/service/cloudapi/kvmvm"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
)
func dataSourceK8sWgRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("dataSourceK8sWgRead: called with k8s id %d", d.Get("k8s_id").(int))
k8s, err := utilityDataK8sCheckPresence(ctx, d, m)
wg, workersComputeList, err := utilityDataK8sWgCheckPresence(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
d.SetId(strconv.Itoa(d.Get("wg_id").(int)))
var id int
if d.Id() != "" {
id, err = strconv.Atoi(d.Id())
if err != nil {
return diag.FromErr(err)
}
} else {
id = d.Get("wg_id").(int)
}
curWg := K8SGroup{}
for _, wg := range k8s.K8SGroups.Workers {
if wg.ID == uint64(id) {
curWg = wg
break
}
}
if curWg.ID == 0 {
return diag.Errorf("Not found wg with id: %v in k8s cluster: %v", id, k8s.ID)
}
workersComputeList := make([]kvmvm.ComputeGetResp, 0, 0)
for _, info := range curWg.DetailedInfo {
compute, err := utilityComputeCheckPresence(ctx, d, m, info.ID)
if err != nil {
return diag.FromErr(err)
}
workersComputeList = append(workersComputeList, *compute)
}
d.SetId(strconv.Itoa(d.Get("wg_id").(int)))
flattenWgData(d, curWg, workersComputeList)
flattenWg(d, *wg, workersComputeList)
return nil
}

@ -257,9 +257,13 @@ func flattenK8sList(d *schema.ResourceData, k8sItems K8SList) {
}
func flattenResourceK8s(d *schema.ResourceData, k8s K8SRecord, masters []kvmvm.ComputeGetResp, workers []kvmvm.ComputeGetResp) {
wg_name := k8s.K8SGroups.Workers[0].Name
d.Set("acl", flattenAcl(k8s.ACL))
d.Set("account_id", k8s.AccountID)
d.Set("account_name", k8s.AccountName)
d.Set("k8sci_id", k8s.CIID)
d.Set("wg_name", wg_name)
d.Set("bservice_id", k8s.BServiceID)
d.Set("created_by", k8s.CreatedBy)
d.Set("created_time", k8s.CreatedTime)
@ -268,7 +272,9 @@ func flattenResourceK8s(d *schema.ResourceData, k8s K8SRecord, masters []kvmvm.C
d.Set("k8s_ci_name", k8s.K8CIName)
d.Set("masters", flattenMasterGroup(k8s.K8SGroups.Masters, masters))
d.Set("workers", flattenK8sGroup(k8s.K8SGroups.Workers, workers))
d.Set("with_lb", k8s.LBID != 0)
d.Set("lb_id", k8s.LBID)
d.Set("name", k8s.Name)
d.Set("rg_id", k8s.RGID)
d.Set("rg_name", k8s.RGName)
d.Set("status", k8s.Status)
@ -278,7 +284,7 @@ func flattenResourceK8s(d *schema.ResourceData, k8s K8SRecord, masters []kvmvm.C
d.Set("default_wg_id", k8s.K8SGroups.Workers[0].ID)
}
func flattenWgData(d *schema.ResourceData, wg K8SGroup, computes []kvmvm.ComputeGetResp) {
func flattenWg(d *schema.ResourceData, wg K8SGroup, computes []kvmvm.ComputeGetResp) {
d.Set("annotations", wg.Annotations)
d.Set("cpu", wg.CPU)
d.Set("detailed_info", flattenDetailedInfo(wg.DetailedInfo, computes))

@ -0,0 +1,143 @@
package k8s
import (
"context"
"encoding/json"
"net/url"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
)
func existK8sID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
k8sList := []struct {
ID int `json:"id"`
}{}
k8sListAPI := "/restmachine/cloudapi/k8s/list"
k8sListRaw, err := c.DecortAPICall(ctx, "POST", k8sListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(k8sListRaw), &k8sList)
if err != nil {
return false, err
}
haveK8s := false
k8sID := d.Get("k8s_id").(int)
for _, k8s := range k8sList {
if k8s.ID == k8sID {
haveK8s = true
break
}
}
return haveK8s, nil
}
func existK8sCIID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
k8sciList := []struct {
ID int `json:"id"`
}{}
k8sciListAPI := "/restmachine/cloudapi/k8ci/list"
k8sciListRaw, err := c.DecortAPICall(ctx, "POST", k8sciListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(k8sciListRaw), &k8sciList)
if err != nil {
return false, err
}
haveK8sCI := false
k8sciID := d.Get("k8sci_id").(int)
for _, k8ci := range k8sciList {
if k8ci.ID == k8sciID {
haveK8sCI = true
break
}
}
return haveK8sCI, nil
}
func existRGID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
rgList := []struct {
ID int `json:"id"`
}{}
rgListAPI := "/restmachine/cloudapi/rg/list"
rgListRaw, err := c.DecortAPICall(ctx, "POST", rgListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(rgListRaw), &rgList)
if err != nil {
return false, err
}
haveRG := false
rgId := d.Get("rg_id").(int)
for _, rg := range rgList {
if rg.ID == rgId {
haveRG = true
break
}
}
return haveRG, nil
}
func existExtNetID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
extNetID := d.Get("extnet_id").(int)
if extNetID == 0 {
return true, nil
}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
extNetList := []struct {
ID int `json:"id"`
}{}
extNetListAPI := "/restmachine/cloudapi/extnet/list"
extNetListRaw, err := c.DecortAPICall(ctx, "POST", extNetListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(extNetListRaw), &extNetList)
if err != nil {
return false, err
}
haveExtNet := false
for _, extNet := range extNetList {
if extNet.ID == extNetID {
haveExtNet = true
break
}
}
return haveExtNet, nil
}

@ -43,15 +43,45 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
log "github.com/sirupsen/logrus"
"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/service/cloudapi/kvmvm"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/status"
)
func resourceK8sCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceK8sCreate: called with name %s, rg %d", d.Get("name").(string), d.Get("rg_id").(int))
haveRGID, err := existRGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveRGID {
return diag.Errorf("resourceK8sCreate: can't create k8s cluster because RGID %d is not allowed or does not exist", d.Get("rg_id").(int))
}
haveK8sciID, err := existK8sCIID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveK8sciID {
return diag.Errorf("resourceK8sCreate: can't create k8s cluster because K8sCIID %d is not allowed or does not exist", d.Get("k8sci_id").(int))
}
if _, ok := d.GetOk("extnet_id"); ok {
haveExtNetID, err := existExtNetID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveExtNetID {
return diag.Errorf("resourceK8sCreate: can't create k8s cluster because ExtNetID %d is not allowed or does not exist", d.Get("extnet_id").(int))
}
}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("name", d.Get("name").(string))
@ -158,12 +188,61 @@ func resourceK8sCreate(ctx context.Context, d *schema.ResourceData, m interface{
}
func resourceK8sRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
k8s, err := utilityK8sCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
c := m.(*controller.ControllerCfg)
hasChanged := false
switch k8s.Status {
case status.Modeled:
return diag.Errorf("The k8s cluster is in status: %s, please, contact support for more information", k8s.Status)
case status.Creating:
case status.Created:
case status.Deleting:
case status.Deleted:
urlVal := &url.Values{}
urlVal.Add("k8sId", d.Id())
k8s, err := utilityDataK8sCheckPresence(ctx, d, m)
_, err := c.DecortAPICall(ctx, "POST", K8sRestoreAPI, urlVal)
if err != nil {
return diag.FromErr(err)
}
_, err = c.DecortAPICall(ctx, "POST", K8sEnableAPI, urlVal)
if err != nil {
return diag.FromErr(err)
}
hasChanged = true
case status.Destroying:
return diag.Errorf("The k8s cluster is in progress with status: %s", k8s.Status)
case status.Destroyed:
d.SetId("")
return resourceK8sCreate(ctx, d, m)
case status.Enabling:
case status.Enabled:
case status.Disabling:
case status.Disabled:
log.Debugf("The k8s cluster is in status: %s, troubles may occur with update. Please, enable compute first.", k8s.Status)
case status.Restoring:
}
if hasChanged {
k8s, err = utilityK8sCheckPresence(ctx, d, m)
if k8s == nil {
d.SetId("")
if err != nil {
return diag.FromErr(err)
}
return nil
}
}
k8sList, err := utilityK8sListCheckPresence(ctx, d, m, K8sListAPI)
if err != nil {
d.SetId("")
@ -201,7 +280,6 @@ func resourceK8sRead(ctx context.Context, d *schema.ResourceData, m interface{})
flattenResourceK8s(d, *k8s, masterComputeList, workersComputeList)
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("lbId", strconv.FormatUint(k8s.LBID, 10))
@ -233,6 +311,76 @@ func resourceK8sUpdate(ctx context.Context, d *schema.ResourceData, m interface{
c := m.(*controller.ControllerCfg)
haveRGID, err := existRGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveRGID {
return diag.Errorf("resourceK8sUpdate: can't update k8s cluster because RGID %d is not allowed or does not exist", d.Get("rg_id").(int))
}
haveK8sciID, err := existK8sCIID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveK8sciID {
return diag.Errorf("resourceK8sUpdate: can't update k8s cluster because K8sCIID %d is not allowed or does not exist", d.Get("k8sci_id").(int))
}
k8s, err := utilityK8sCheckPresence(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
hasChanged := false
switch k8s.Status {
case status.Modeled:
return diag.Errorf("The k8s cluster is in status: %s, please, contact support for more information", k8s.Status)
case status.Creating:
case status.Created:
case status.Deleting:
case status.Deleted:
urlVal := &url.Values{}
urlVal.Add("k8sId", d.Id())
_, err := c.DecortAPICall(ctx, "POST", K8sRestoreAPI, urlVal)
if err != nil {
return diag.FromErr(err)
}
_, err = c.DecortAPICall(ctx, "POST", K8sEnableAPI, urlVal)
if err != nil {
return diag.FromErr(err)
}
hasChanged = true
case status.Destroying:
return diag.Errorf("The k8s cluster is in progress with status: %s", k8s.Status)
case status.Destroyed:
d.SetId("")
return resourceK8sCreate(ctx, d, m)
case status.Enabling:
case status.Enabled:
case status.Disabling:
case status.Disabled:
log.Debugf("The k8s cluster is in status: %s, troubles may occur with update. Please, enable compute first.", k8s.Status)
case status.Restoring:
}
if hasChanged {
k8s, err = utilityK8sCheckPresence(ctx, d, m)
if k8s == nil {
d.SetId("")
if err != nil {
return diag.FromErr(err)
}
return nil
}
}
if d.HasChange("name") {
urlValues := &url.Values{}
urlValues.Add("k8sId", d.Id())
@ -245,11 +393,6 @@ func resourceK8sUpdate(ctx context.Context, d *schema.ResourceData, m interface{
}
if d.HasChange("workers") {
k8s, err := utilityK8sCheckPresence(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
wg := k8s.K8SGroups.Workers[0]
urlValues := &url.Values{}
urlValues.Add("k8sId", d.Id())
@ -321,7 +464,6 @@ func resourceK8sSchemaMake() map[string]*schema.Schema {
"wg_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Name for first worker group created with cluster.",
},
"labels": {
@ -369,7 +511,6 @@ func resourceK8sSchemaMake() map[string]*schema.Schema {
"with_lb": {
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
Default: true,
Description: "Create k8s with load balancer if true.",
},

@ -40,15 +40,24 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
log "github.com/sirupsen/logrus"
"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/service/cloudapi/kvmvm"
log "github.com/sirupsen/logrus"
)
func resourceK8sWgCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceK8sWgCreate: called with k8s id %d", d.Get("k8s_id").(int))
haveK8sID, err := existK8sID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveK8sID {
return diag.Errorf("resourceK8sCreate: can't create k8s cluster because K8sID %d is not allowed or does not exist", d.Get("k8s_id").(int))
}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("k8sId", strconv.Itoa(d.Get("k8s_id").(int)))
@ -56,7 +65,12 @@ func resourceK8sWgCreate(ctx context.Context, d *schema.ResourceData, m interfac
urlValues.Add("workerNum", strconv.Itoa(d.Get("num").(int)))
urlValues.Add("workerCpu", strconv.Itoa(d.Get("cpu").(int)))
urlValues.Add("workerRam", strconv.Itoa(d.Get("ram").(int)))
if d.Get("disk") == nil {
urlValues.Add("workerDisk", strconv.Itoa(0))
} else {
urlValues.Add("workerDisk", strconv.Itoa(d.Get("disk").(int)))
}
resp, err := c.DecortAPICall(ctx, "POST", K8sWgCreateAPI, urlValues)
if err != nil {
@ -100,45 +114,34 @@ func resourceK8sWgCreate(ctx context.Context, d *schema.ResourceData, m interfac
func resourceK8sWgRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceK8sWgRead: called with %v", d.Id())
k8s, err := utilityDataK8sCheckPresence(ctx, d, m)
wg, err := utilityK8sWgCheckPresence(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
var id int
if d.Id() != "" {
id, err = strconv.Atoi(strings.Split(d.Id(), "#")[0])
workersComputeList := make([]kvmvm.ComputeGetResp, 0, 0)
for _, info := range wg.DetailedInfo {
compute, err := utilityComputeCheckPresence(ctx, d, m, info.ID)
if err != nil {
return diag.FromErr(err)
}
} else {
id = d.Get("wg_id").(int)
}
curWg := K8SGroup{}
for _, wg := range k8s.K8SGroups.Workers {
if wg.ID == uint64(id) {
curWg = wg
break
}
}
if curWg.ID == 0 {
return diag.Errorf("Not found wg with id: %v in k8s cluster: %v", id, k8s.ID)
workersComputeList = append(workersComputeList, *compute)
}
workersComputeList := make([]kvmvm.ComputeGetResp, 0, 0)
for _, info := range curWg.DetailedInfo {
compute, err := utilityComputeCheckPresence(ctx, d, m, info.ID)
d.Set("wg_id", wg.ID)
if strings.Contains(d.Id(), "#") {
k8sId, err := strconv.Atoi(strings.Split(d.Id(), "#")[1])
if err != nil {
return diag.FromErr(err)
}
workersComputeList = append(workersComputeList, *compute)
}
d.Set("k8s_id", k8sId)
} else {
d.Set("k8s_id", d.Get("k8s_id"))
}
d.SetId(strings.Split(d.Id(), "#")[0])
d.Set("k8s_id", k8s.ID)
d.Set("wg_id", curWg.ID)
flattenWgData(d, curWg, workersComputeList)
flattenWg(d, *wg, workersComputeList)
return nil
}
@ -148,6 +151,15 @@ func resourceK8sWgUpdate(ctx context.Context, d *schema.ResourceData, m interfac
c := m.(*controller.ControllerCfg)
haveK8sID, err := existK8sID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveK8sID {
return diag.Errorf("resourceK8sUpdate: can't update k8s cluster because K8sID %d is not allowed or does not exist", d.Get("k8s_id").(int))
}
wg, err := utilityK8sWgCheckPresence(ctx, d, m)
if err != nil {
return diag.FromErr(err)
@ -242,8 +254,7 @@ func resourceK8sWgSchemaMake() map[string]*schema.Schema {
"disk": {
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
Default: 0,
Computed: true,
Description: "Worker node boot disk size. If unspecified or 0, size is defined by OS image size.",
},
"wg_id": {

@ -37,7 +37,6 @@ import (
"encoding/json"
"net/url"
"strconv"
"strings"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
@ -89,15 +88,8 @@ func utilityComputeCheckPresence(ctx context.Context, d *schema.ResourceData, m
func utilityDataK8sCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (*K8SRecord, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
if d.Get("k8s_id") != 0 && d.Get("k8s_id") != nil {
urlValues.Add("k8sId", strconv.Itoa(d.Get("k8s_id").(int)))
} else if id := d.Id(); id != "" {
if strings.Contains(id, "#") {
urlValues.Add("k8sId", strings.Split(d.Id(), "#")[1])
} else {
urlValues.Add("k8sId", d.Id())
}
}
k8sRaw, err := c.DecortAPICall(ctx, "POST", K8sGetAPI, urlValues)
if err != nil {
return nil, err

@ -38,15 +38,82 @@ import (
"fmt"
"net/url"
"strconv"
"strings"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/service/cloudapi/kvmvm"
)
func utilityDataK8sWgCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (*K8SGroup, []kvmvm.ComputeGetResp, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
k8sId := d.Get("k8s_id").(int)
wgId := d.Get("wg_id").(int)
urlValues.Add("k8sId", strconv.Itoa(k8sId))
k8sRaw, err := c.DecortAPICall(ctx, "POST", K8sGetAPI, urlValues)
if err != nil {
return nil, nil, err
}
k8s := K8SRecord{}
err = json.Unmarshal([]byte(k8sRaw), &k8s)
if err != nil {
return nil, nil, err
}
curWg := K8SGroup{}
for _, wg := range k8s.K8SGroups.Workers {
if wg.ID == uint64(wgId) {
curWg = wg
break
}
}
if curWg.ID == 0 {
return nil, nil, fmt.Errorf("WG with id %v in k8s cluster %v not found", wgId, k8sId)
}
workersComputeList := make([]kvmvm.ComputeGetResp, 0, 0)
for _, info := range curWg.DetailedInfo {
compute, err := utilityComputeCheckPresence(ctx, d, m, info.ID)
if err != nil {
return nil, nil, err
}
workersComputeList = append(workersComputeList, *compute)
}
return &curWg, workersComputeList, nil
}
func utilityK8sWgCheckPresence(ctx context.Context, d *schema.ResourceData, m interface{}) (*K8SGroup, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("k8sId", strconv.Itoa(d.Get("k8s_id").(int)))
var wgId int
var k8sId int
var err error
if strings.Contains(d.Id(), "#") {
wgId, err = strconv.Atoi(strings.Split(d.Id(), "#")[0])
if err != nil {
return nil, err
}
k8sId, err = strconv.Atoi(strings.Split(d.Id(), "#")[1])
if err != nil {
return nil, err
}
} else {
wgId, err = strconv.Atoi(d.Id())
if err != nil {
return nil, err
}
k8sId = d.Get("k8s_id").(int)
}
urlValues.Add("k8sId", strconv.Itoa(k8sId))
resp, err := c.DecortAPICall(ctx, "POST", K8sGetAPI, urlValues)
if err != nil {
@ -62,21 +129,11 @@ func utilityK8sWgCheckPresence(ctx context.Context, d *schema.ResourceData, m in
return nil, err
}
var id int
if d.Id() != "" {
id, err = strconv.Atoi(d.Id())
if err != nil {
return nil, err
}
} else {
id = d.Get("wg_id").(int)
}
for _, wg := range k8s.K8SGroups.Workers {
if wg.ID == uint64(id) {
if wg.ID == uint64(wgId) {
return &wg, nil
}
}
return nil, fmt.Errorf("Not found wg with id: %v in k8s cluster: %v", id, k8s.ID)
return nil, fmt.Errorf("Not found wg with id: %v in k8s cluster: %v", wgId, k8s.ID)
}

@ -82,8 +82,8 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
urlValues.Add("netType", "NONE")
urlValues.Add("start", "0") // at the 1st step create compute in a stopped state
argVal, argSet := d.GetOk("description")
if argSet {
argVal, ok := d.GetOk("description")
if ok {
urlValues.Add("desc", argVal.(string))
}
@ -138,8 +138,8 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
log.Debugf("resourceComputeCreate: creating Compute of type KVM VM x86")
}
argVal, argSet = d.GetOk("cloud_init")
if argSet {
argVal, ok = d.GetOk("cloud_init")
if ok {
// userdata must not be empty string and must not be a reserved keyword "applied"
userdata := argVal.(string)
if userdata != "" && userdata != "applied" {
@ -177,8 +177,8 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
log.Debugf("resourceComputeCreate: new simple Compute ID %d, name %s created", compId, d.Get("name").(string))
argVal, argSet = d.GetOk("extra_disks")
if argSet && argVal.(*schema.Set).Len() > 0 {
argVal, ok = d.GetOk("extra_disks")
if ok && argVal.(*schema.Set).Len() > 0 {
log.Debugf("resourceComputeCreate: calling utilityComputeExtraDisksConfigure to attach %d extra disk(s)", argVal.(*schema.Set).Len())
err = utilityComputeExtraDisksConfigure(ctx, d, m, false) // do_delta=false, as we are working on a new compute
if err != nil {
@ -187,8 +187,8 @@ func resourceComputeCreate(ctx context.Context, d *schema.ResourceData, m interf
return diag.FromErr(err)
}
}
argVal, argSet = d.GetOk("network")
if argSet && argVal.(*schema.Set).Len() > 0 {
argVal, ok = d.GetOk("network")
if ok && argVal.(*schema.Set).Len() > 0 {
log.Debugf("resourceComputeCreate: calling utilityComputeNetworksConfigure to attach %d network(s)", argVal.(*schema.Set).Len())
err = utilityComputeNetworksConfigure(ctx, d, m, false, true)
if err != nil {
@ -447,6 +447,8 @@ func resourceComputeRead(ctx context.Context, d *schema.ResourceData, m interfac
return diag.FromErr(err)
}
hasChanged := false
switch compute.Status {
case status.Deleted:
urlValues := &url.Values{}
@ -459,23 +461,28 @@ func resourceComputeRead(ctx context.Context, d *schema.ResourceData, m interfac
if err != nil {
return diag.FromErr(err)
}
hasChanged = true
case status.Destroyed:
d.SetId("")
return resourceComputeCreate(ctx, d, m)
case status.Disabled:
log.Debugf("The compute is in status: %s, may troubles can be occured with update. Please, enable compute first.", compute.Status)
log.Debugf("The compute is in status: %s, troubles may occur with update. Please, enable compute first.", compute.Status)
case status.Redeploying:
case status.Deleting:
case status.Destroying:
return diag.Errorf("The compute is in progress with status: %s", compute.Status)
case status.Modeled:
return diag.Errorf("The compute is in status: %s, please, contant the support for more information", compute.Status)
return diag.Errorf("The compute is in status: %s, please, contact support for more information", compute.Status)
}
if hasChanged {
compute, err = utilityComputeCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
}
if err = flattenCompute(d, compute); err != nil {
return diag.FromErr(err)

@ -0,0 +1,139 @@
package lb
import (
"context"
"encoding/json"
"net/url"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
)
func existLBID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
lbList := []struct {
ID int `json:"id"`
}{}
lbListAPI := "/restmachine/cloudapi/lb/list"
lbListRaw, err := c.DecortAPICall(ctx, "POST", lbListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(lbListRaw), &lbList)
if err != nil {
return false, err
}
haveLB := false
lbId := d.Get("lb_id").(int)
for _, lb := range lbList {
if lb.ID == lbId {
haveLB = true
break
}
}
return haveLB, nil
}
func existRGID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
rgList := []struct {
ID int `json:"id"`
}{}
rgListAPI := "/restmachine/cloudapi/rg/list"
rgListRaw, err := c.DecortAPICall(ctx, "POST", rgListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(rgListRaw), &rgList)
if err != nil {
return false, err
}
haveRG := false
rgId := d.Get("rg_id").(int)
for _, rg := range rgList {
if rg.ID == rgId {
haveRG = true
break
}
}
return haveRG, nil
}
func existExtNetID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
extNetList := []struct {
ID int `json:"id"`
}{}
extNetListAPI := "/restmachine/cloudapi/extnet/list"
extNetListRaw, err := c.DecortAPICall(ctx, "POST", extNetListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(extNetListRaw), &extNetList)
if err != nil {
return false, err
}
haveExtNet := false
extNetID := d.Get("extnet_id").(int)
for _, extNet := range extNetList {
if extNet.ID == extNetID {
haveExtNet = true
break
}
}
return haveExtNet, nil
}
func existViNSID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
vinsList := []struct {
ID int `json:"id"`
}{}
vinsListAPI := "/restmachine/cloudapi/vins/list"
vinsListRaw, err := c.DecortAPICall(ctx, "POST", vinsListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(vinsListRaw), &vinsList)
if err != nil {
return false, err
}
haveVins := false
vinsID := d.Get("vins_id").(int)
for _, vins := range vinsList {
if vins.ID == vinsID {
haveVins = true
break
}
}
return haveVins, nil
}

@ -42,11 +42,39 @@ import (
log "github.com/sirupsen/logrus"
"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/status"
)
func resourceLBCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceLBCreate")
haveRGID, err := existRGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveRGID {
return diag.Errorf("resourceLBCreate: can't create LB because RGID %d is not allowed or does not exist", d.Get("rg_id").(int))
}
haveExtNetID, err := existExtNetID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveExtNetID {
return diag.Errorf("resourceLBCreate: can't create LB because ExtNetID %d is not allowed or does not exist", d.Get("extnet_id").(int))
}
haveVins, err := existViNSID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveVins {
return diag.Errorf("resourceLBCreate: can't create LB because ViNSID %d is not allowed or does not exist", d.Get("vins_id").(int))
}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("name", d.Get("name").(string))
@ -100,12 +128,57 @@ func resourceLBCreate(ctx context.Context, d *schema.ResourceData, m interface{}
func resourceLBRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceLBRead")
c := m.(*controller.ControllerCfg)
lb, err := utilityLBCheckPresence(ctx, d, m)
if lb == nil {
d.SetId("")
return diag.FromErr(err)
}
hasChanged := false
switch lb.Status {
case status.Modeled:
return diag.Errorf("The LB is in status: %s, please, contact support for more information", lb.Status)
case status.Creating:
case status.Created:
case status.Deleting:
case status.Deleted:
urlValues := &url.Values{}
urlValues.Add("lbId", d.Id())
_, err := c.DecortAPICall(ctx, "POST", lbRestoreAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
_, err = c.DecortAPICall(ctx, "POST", lbEnableAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
hasChanged = true
case status.Destroying:
return diag.Errorf("The LB is in progress with status: %s", lb.Status)
case status.Destroyed:
d.SetId("")
return resourceLBCreate(ctx, d, m)
case status.Enabled:
case status.Enabling:
case status.Disabling:
case status.Disabled:
log.Debugf("The LB is in status: %s, troubles may occur with update. Please, enable LB first.", lb.Status)
case status.Restoring:
}
if hasChanged {
lb, err = utilityLBCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
}
d.Set("ha_mode", lb.HAMode)
d.Set("backends", flattenLBBackends(lb.Backends))
d.Set("created_by", lb.CreatedBy)
@ -163,11 +236,87 @@ func resourceLBDelete(ctx context.Context, d *schema.ResourceData, m interface{}
return nil
}
func resourceLBEdit(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
func resourceLBUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceLBEdit")
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
haveRGID, err := existRGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveRGID {
return diag.Errorf("resourceLBUpdate: can't update LB because RGID %d is not allowed or does not exist", d.Get("rg_id").(int))
}
haveExtNetID, err := existExtNetID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveExtNetID {
return diag.Errorf("resourceLBUpdate: can't update LB because ExtNetID %d is not allowed or does not exist", d.Get("extnet_id").(int))
}
haveVins, err := existViNSID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveVins {
return diag.Errorf("resourceLBUpdate: can't update LB because ViNSID %d is not allowed or does not exist", d.Get("vins_id").(int))
}
lb, err := utilityLBCheckPresence(ctx, d, m)
if lb == nil {
d.SetId("")
return diag.FromErr(err)
}
hasChanged := false
switch lb.Status {
case status.Modeled:
return diag.Errorf("The LB is in status: %s, please, contact support for more information", lb.Status)
case status.Creating:
case status.Created:
case status.Deleting:
case status.Deleted:
urlValues := &url.Values{}
urlValues.Add("lbId", d.Id())
_, err := c.DecortAPICall(ctx, "POST", lbRestoreAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
_, err = c.DecortAPICall(ctx, "POST", lbEnableAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
hasChanged = true
case status.Destroying:
return diag.Errorf("The LB is in progress with status: %s", lb.Status)
case status.Destroyed:
d.SetId("")
return resourceLBCreate(ctx, d, m)
case status.Enabled:
case status.Enabling:
case status.Disabling:
case status.Disabled:
log.Debugf("The LB is in status: %s, troubles may occur with update. Please, enable LB first.", lb.Status)
case status.Restoring:
}
if hasChanged {
lb, err = utilityLBCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
}
if d.HasChange("enable") {
api := lbDisableAPI
enable := d.Get("enable").(bool)
@ -262,7 +411,7 @@ func ResourceLB() *schema.Resource {
CreateContext: resourceLBCreate,
ReadContext: resourceLBRead,
UpdateContext: resourceLBEdit,
UpdateContext: resourceLBUpdate,
DeleteContext: resourceLBDelete,
Importer: &schema.ResourceImporter{

@ -49,6 +49,15 @@ import (
func resourceLBBackendCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceLBBackendCreate")
haveLBID, err := existLBID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveLBID {
return diag.Errorf("resourceLBBackendCreate: can't create LB backend because LBID %d is not allowed or does not exist", d.Get("lb_id").(int))
}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("backendName", d.Get("name").(string))
@ -82,7 +91,7 @@ func resourceLBBackendCreate(ctx context.Context, d *schema.ResourceData, m inte
urlValues.Add("weight", strconv.Itoa(weight.(int)))
}
_, err := c.DecortAPICall(ctx, "POST", lbBackendCreateAPI, urlValues)
_, err = c.DecortAPICall(ctx, "POST", lbBackendCreateAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
@ -155,11 +164,20 @@ func resourceLBBackendDelete(ctx context.Context, d *schema.ResourceData, m inte
return nil
}
func resourceLBBackendEdit(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
func resourceLBBackendUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceLBBackendEdit")
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
haveLBID, err := existLBID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveLBID {
return diag.Errorf("resourceLBBackendUpdate: can't update LB backend because LBID %d is not allowed or does not exist", d.Get("lb_id").(int))
}
urlValues.Add("backendName", d.Get("name").(string))
urlValues.Add("lbId", strconv.Itoa(d.Get("lb_id").(int)))
@ -191,7 +209,7 @@ func resourceLBBackendEdit(ctx context.Context, d *schema.ResourceData, m interf
urlValues.Add("weight", strconv.Itoa(d.Get("weight").(int)))
}
_, err := c.DecortAPICall(ctx, "POST", lbBackendUpdateAPI, urlValues)
_, err = c.DecortAPICall(ctx, "POST", lbBackendUpdateAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
@ -207,7 +225,7 @@ func ResourceLBBackend() *schema.Resource {
CreateContext: resourceLBBackendCreate,
ReadContext: resourceLBBackendRead,
UpdateContext: resourceLBBackendEdit,
UpdateContext: resourceLBBackendUpdate,
DeleteContext: resourceLBBackendDelete,
Importer: &schema.ResourceImporter{

@ -49,6 +49,15 @@ import (
func resourceLBBackendServerCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceLBBackendServerCreate")
haveLBID, err := existLBID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveLBID {
return diag.Errorf("resourceLBBackendServerCreate: can't create LB backend server because LBID %d is not allowed or does not exist", d.Get("lb_id").(int))
}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("backendName", d.Get("backend_name").(string))
@ -86,7 +95,7 @@ func resourceLBBackendServerCreate(ctx context.Context, d *schema.ResourceData,
urlValues.Add("weight", strconv.Itoa(weight.(int)))
}
_, err := c.DecortAPICall(ctx, "POST", lbBackendServerAddAPI, urlValues)
_, err = c.DecortAPICall(ctx, "POST", lbBackendServerAddAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
@ -163,11 +172,20 @@ func resourceLBBackendServerDelete(ctx context.Context, d *schema.ResourceData,
return nil
}
func resourceLBBackendServerEdit(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
func resourceLBBackendServerUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceLBBackendServerEdit")
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
haveLBID, err := existLBID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveLBID {
return diag.Errorf("resourceLBBackendServerUpdate: can't update LB backend server because LBID %d is not allowed or does not exist", d.Get("lb_id").(int))
}
urlValues.Add("backendName", d.Get("backend_name").(string))
urlValues.Add("lbId", strconv.Itoa(d.Get("lb_id").(int)))
urlValues.Add("serverName", d.Get("name").(string))
@ -202,7 +220,7 @@ func resourceLBBackendServerEdit(ctx context.Context, d *schema.ResourceData, m
urlValues.Add("weight", strconv.Itoa(d.Get("weight").(int)))
}
_, err := c.DecortAPICall(ctx, "POST", lbBackendServerUpdateAPI, urlValues)
_, err = c.DecortAPICall(ctx, "POST", lbBackendServerUpdateAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
@ -218,7 +236,7 @@ func ResourceLBBackendServer() *schema.Resource {
CreateContext: resourceLBBackendServerCreate,
ReadContext: resourceLBBackendServerRead,
UpdateContext: resourceLBBackendServerEdit,
UpdateContext: resourceLBBackendServerUpdate,
DeleteContext: resourceLBBackendServerDelete,
Importer: &schema.ResourceImporter{

@ -48,13 +48,22 @@ import (
func resourceLBFrontendCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceLBFrontendCreate")
haveLBID, err := existLBID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveLBID {
return diag.Errorf("resourceLBFrontendCreate: can't create LB frontend because LBID %d is not allowed or does not exist", d.Get("lb_id").(int))
}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("backendName", d.Get("backend_name").(string))
urlValues.Add("lbId", strconv.Itoa(d.Get("lb_id").(int)))
urlValues.Add("frontendName", d.Get("name").(string))
_, err := c.DecortAPICall(ctx, "POST", lbFrontendCreateAPI, urlValues)
_, err = c.DecortAPICall(ctx, "POST", lbFrontendCreateAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}

@ -48,6 +48,15 @@ import (
func resourceLBFrontendBindCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceLBFrontendBindCreate")
haveLBID, err := existLBID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveLBID {
return diag.Errorf("resourceLBFrontendBindCreate: can't create LB frontend bind because LBID %d is not allowed or does not exist", d.Get("lb_id").(int))
}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("frontendName", d.Get("frontend_name").(string))
@ -56,7 +65,7 @@ func resourceLBFrontendBindCreate(ctx context.Context, d *schema.ResourceData, m
urlValues.Add("bindingAddress", d.Get("address").(string))
urlValues.Add("bindingPort", strconv.Itoa(d.Get("port").(int)))
_, err := c.DecortAPICall(ctx, "POST", lbFrontendBindAPI, urlValues)
_, err = c.DecortAPICall(ctx, "POST", lbFrontendBindAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
@ -124,11 +133,20 @@ func resourceLBFrontendBindDelete(ctx context.Context, d *schema.ResourceData, m
return nil
}
func resourceLBFrontendBindEdit(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
func resourceLBFrontendBindUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
log.Debugf("resourceLBFrontendBindEdit")
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
haveLBID, err := existLBID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveLBID {
return diag.Errorf("resourceLBFrontendBindUpdate: can't update LB frontend bind because LBID %d is not allowed or does not exist", d.Get("lb_id").(int))
}
urlValues.Add("frontendName", d.Get("frontend_name").(string))
urlValues.Add("bindingName", d.Get("name").(string))
urlValues.Add("lbId", strconv.Itoa(d.Get("lb_id").(int)))
@ -141,7 +159,7 @@ func resourceLBFrontendBindEdit(ctx context.Context, d *schema.ResourceData, m i
urlValues.Add("bindingPort", strconv.Itoa(d.Get("port").(int)))
}
_, err := c.DecortAPICall(ctx, "POST", lbFrontendBindUpdateAPI, urlValues)
_, err = c.DecortAPICall(ctx, "POST", lbFrontendBindUpdateAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
@ -155,7 +173,7 @@ func ResourceLBFrontendBind() *schema.Resource {
CreateContext: resourceLBFrontendBindCreate,
ReadContext: resourceLBFrontendBindRead,
UpdateContext: resourceLBFrontendBindEdit,
UpdateContext: resourceLBFrontendBindUpdate,
DeleteContext: resourceLBFrontendBindDelete,
Importer: &schema.ResourceImporter{

@ -74,6 +74,7 @@ func existAccountID(ctx context.Context, d *schema.ResourceData, m interface{})
}
return haveAccount, nil
}
func existGID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
@ -107,6 +108,7 @@ func existGID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool,
return haveGID, nil
}
func existExtNetID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)

@ -52,13 +52,8 @@ import (
)
func resourceResgroupCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
// First validate that we have all parameters required to create the new Resource Group
// Valid account ID is required to create new resource group
// obtain Account ID by account name - it should not be zero on success
rgName, argSet := d.GetOk("name")
if !argSet {
rgName, ok := d.GetOk("name")
if !ok {
return diag.FromErr(fmt.Errorf("Cannot create new RG: missing name."))
}
@ -76,43 +71,39 @@ func resourceResgroupCreate(ctx context.Context, d *schema.ResourceData, m inter
}
*/
// all required parameters are set in the schema - we can continue with RG creation
log.Debugf("resourceResgroupCreate: called for RG name %s, account ID %d",
rgName.(string), d.Get("account_id").(int))
// Check input values
// AccountID
haveAccount, err := existAccountID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveAccount {
return diag.Errorf("resourceResgroupCreate: can't create RG bacause AccountID %d not allowed or does not exist", d.Get("account_id").(int))
return diag.Errorf("resourceResgroupCreate: can't create RG because AccountID %d is not allowed or does not exist", d.Get("account_id").(int))
}
// GID
haveGID, err := existGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveGID {
return diag.Errorf("resourceResgroupCreate: can't create RG bacause GID %d not allowed or does not exist", d.Get("gid").(int))
return diag.Errorf("resourceResgroupCreate: can't create RG because GID %d is not allowed or does not exist", d.Get("gid").(int))
}
// ExtNetID
if _, ok := d.GetOk("ext_net_id"); ok {
haveExtNet, err := existExtNetID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveExtNet {
return diag.Errorf("resourceResgroupCreate: can't create RG bacause ExtNetID %d not allowed or does not exist", d.Get("ext_net_id").(int))
return diag.Errorf("resourceResgroupCreate: can't create RG because ExtNetID %d is not allowed or does not exist", d.Get("ext_net_id").(int))
}
}
// quota settings are optional
setQuota := false
var quotaRecord QuotaRecord
argValue, argSet := d.GetOk("quota")
if argSet {
argValue, ok := d.GetOk("quota")
if ok {
log.Debugf("resourceResgroupCreate: setting Quota on RG requested")
quotaRecord = makeQuotaRecord(argValue.([]interface{}))
setQuota = true
@ -125,53 +116,51 @@ func resourceResgroupCreate(ctx context.Context, d *schema.ResourceData, m inter
urlValues = &url.Values{}
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
urlValues.Add("name", rgName.(string))
urlValues.Add("gid", strconv.Itoa(location.DefaultGridID)) // use default Grid ID, similar to disk resource mgmt convention
urlValues.Add("gid", strconv.Itoa(location.DefaultGridID))
urlValues.Add("owner", c.GetDecortUsername())
// pass quota values as set
if setQuota {
urlValues.Add("maxCPUCapacity", strconv.Itoa(quotaRecord.Cpu))
urlValues.Add("maxVDiskCapacity", strconv.Itoa(quotaRecord.Disk))
urlValues.Add("maxMemoryCapacity", fmt.Sprintf("%f", quotaRecord.Ram)) // RAM quota is float; this may change in the future
urlValues.Add("maxMemoryCapacity", fmt.Sprintf("%f", quotaRecord.Ram))
urlValues.Add("maxNetworkPeerTransfer", strconv.Itoa(quotaRecord.ExtTraffic))
urlValues.Add("maxNumPublicIP", strconv.Itoa(quotaRecord.ExtIPs))
}
// parse and handle network settings
defNetType, argSet := d.GetOk("def_net_type")
if argSet {
defNetType, ok := d.GetOk("def_net_type")
if ok {
urlValues.Add("def_net", defNetType.(string)) // NOTE: in API default network type is set by "def_net" parameter
} else {
d.Set("def_net_type", "PRIVATE")
}
ipcidr, argSet := d.GetOk("ipcidr")
if argSet {
ipcidr, ok := d.GetOk("ipcidr")
if ok {
urlValues.Add("ipcidr", ipcidr.(string))
}
description, argSet := d.GetOk("description")
if argSet {
description, ok := d.GetOk("description")
if ok {
urlValues.Add("desc", description.(string))
}
reason, argSet := d.GetOk("reason")
if argSet {
reason, ok := d.GetOk("reason")
if ok {
urlValues.Add("reason", reason.(string))
}
extNetId, argSet := d.GetOk("ext_net_id")
if argSet {
extNetId, ok := d.GetOk("ext_net_id")
if ok {
urlValues.Add("extNetId", strconv.Itoa(extNetId.(int)))
}
extIp, argSet := d.GetOk("ext_ip")
if argSet {
extIp, ok := d.GetOk("ext_ip")
if ok {
urlValues.Add("extIp", extIp.(string))
}
regComputes, argSet := d.GetOk("register_computes")
if argSet {
regComputes, ok := d.GetOk("register_computes")
if ok {
urlValues.Add("registerComputes", strconv.FormatBool(regComputes.(bool)))
}
@ -179,7 +168,8 @@ func resourceResgroupCreate(ctx context.Context, d *schema.ResourceData, m inter
if err != nil {
return diag.FromErr(err)
}
d.SetId(apiResp) // rg/create API returns ID of the newly creted resource group on success
d.SetId(apiResp)
w := dc.Warnings{}
if access, ok := d.GetOk("access"); ok {
@ -257,7 +247,6 @@ func resourceResgroupCreate(ctx context.Context, d *schema.ResourceData, m inter
}
}
// re-read newly created RG to make sure schema contains complete and up to date set of specifications
defer resourceResgroupRead(ctx, d, m)
return w.Get()
}
@ -268,23 +257,34 @@ func resourceResgroupRead(ctx context.Context, d *schema.ResourceData, m interfa
c := m.(*controller.ControllerCfg)
rgFacts, err := utilityResgroupCheckPresence(ctx, d, m)
rg, err := utilityResgroupCheckPresence(ctx, d, m)
if err != nil {
d.SetId("") // ensure ID is empty
d.SetId("")
return diag.FromErr(err)
}
switch rgFacts.Status {
hasChanged := false
switch rg.Status {
case status.Modeled:
return diag.Errorf("The resource group is in status: %s, please, contact support for more information", rg.Status)
case status.Created:
case status.Enabled:
case status.Deleted:
urlValues := &url.Values{}
urlValues.Add("rgId", d.Id())
_, err := c.DecortAPICall(ctx, "POST", RgRestoreAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
_, err = c.DecortAPICall(ctx, "POST", RgEnableAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
hasChanged = true
case status.Deleting:
case status.Destroyed:
d.SetId("")
@ -296,12 +296,14 @@ func resourceResgroupRead(ctx context.Context, d *schema.ResourceData, m interfa
case status.Enabling:
}
rgFacts, err = utilityResgroupCheckPresence(ctx, d, m)
if hasChanged {
rg, err = utilityResgroupCheckPresence(ctx, d, m)
if err != nil {
d.SetId("") // ensure ID is empty
d.SetId("")
return diag.FromErr(err)
}
return diag.FromErr(flattenResgroup(d, *rgFacts))
}
return diag.FromErr(flattenResgroup(d, *rg))
}
func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
@ -311,8 +313,6 @@ func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m inter
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
// Check input values
// AccountID
haveAccount, err := existAccountID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
@ -320,7 +320,7 @@ func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m inter
if !haveAccount {
return diag.Errorf("resourceResgroupUpdate: can't create RG bacause AccountID %d not allowed or does not exist", d.Get("account_id").(int))
}
// GID
haveGID, err := existGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
@ -328,7 +328,7 @@ func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m inter
if !haveGID {
return diag.Errorf("resourceResgroupUpdate: can't create RG bacause GID %d not allowed or does not exist", d.Get("gid").(int))
}
// ExtNetID
if _, ok := d.GetOk("ext_net_id"); ok {
haveExtNet, err := existExtNetID(ctx, d, m)
if err != nil {
@ -341,10 +341,12 @@ func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m inter
rgFacts, err := utilityResgroupCheckPresence(ctx, d, m)
if err != nil {
d.SetId("") // ensure ID is empty
d.SetId("")
return diag.FromErr(err)
}
hasChanged := false
switch rgFacts.Status {
case status.Modeled:
case status.Created:
@ -356,6 +358,12 @@ func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m inter
if err != nil {
return diag.FromErr(err)
}
_, err = c.DecortAPICall(ctx, "POST", RgEnableAPI, urlValues)
if err != nil {
return diag.FromErr(err)
}
hasChanged = true
case status.Deleting:
case status.Destroyed:
d.SetId("")
@ -366,6 +374,14 @@ func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m inter
case status.Enabled:
case status.Enabling:
}
if hasChanged {
rgFacts, err = utilityDataResgroupCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
}
/* NOTE: we do not allow changing the following attributes of an existing RG via terraform:
- def_net_type
- ipcidr
@ -393,7 +409,7 @@ func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m inter
return diag.FromErr(fmt.Errorf("resourceResgroupUpdate: RG ID %s: changing ext_net_id for existing RG is not allowed", d.Id()))
}
doGeneralUpdate := false // will be true if general RG update is necessary (API rg/update)
doGeneralUpdate := false
urlValues = &url.Values{}
urlValues.Add("rgId", d.Id())
@ -412,7 +428,7 @@ func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m inter
if quotaSet {
log.Debugf("resourceResgroupUpdate: quota specified - looking for deltas from the old quota.")
quotarecordNew := makeQuotaRecord(quotaValue.([]interface{}))
quotaValueOld, _ := d.GetChange("quota") // returns old as 1st, new as 2nd return value
quotaValueOld, _ := d.GetChange("quota")
quotarecordOld := makeQuotaRecord(quotaValueOld.([]interface{}))
log.Debug(quotaValueOld, quotarecordNew)
@ -428,7 +444,7 @@ func resourceResgroupUpdate(ctx context.Context, d *schema.ResourceData, m inter
urlValues.Add("maxVDiskCapacity", strconv.Itoa(quotarecordNew.Disk))
}
if quotarecordNew.Ram != quotarecordOld.Ram { // NB: quota on RAM is stored as float32, in units of MB
if quotarecordNew.Ram != quotarecordOld.Ram {
doGeneralUpdate = true
log.Debugf("resourceResgroupUpdate: Ram diff %f <- %f", quotarecordNew.Ram, quotarecordOld.Ram)
urlValues.Add("maxMemoryCapacity", fmt.Sprintf("%f", quotarecordNew.Ram))
@ -605,7 +621,7 @@ func ResourceRgSchemaMake() map[string]*schema.Schema {
"gid": {
Type: schema.TypeInt,
Required: true,
ForceNew: true, // change of Grid ID will require new RG
ForceNew: true,
Description: "Unique ID of the grid, where this resource group is deployed.",
},
@ -816,7 +832,7 @@ func ResourceRgSchemaMake() map[string]*schema.Schema {
Computed: true,
},
"vins": {
Type: schema.TypeList, //this is a list of ints
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeInt,
@ -825,7 +841,7 @@ func ResourceRgSchemaMake() map[string]*schema.Schema {
},
"vms": {
Type: schema.TypeList, //t his is a list of ints
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeInt,

@ -0,0 +1,146 @@
package vins
import (
"context"
"encoding/json"
"net/url"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
)
func existRGID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
rgList := []struct {
ID int `json:"id"`
}{}
rgListAPI := "/restmachine/cloudapi/rg/list"
rgListRaw, err := c.DecortAPICall(ctx, "POST", rgListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(rgListRaw), &rgList)
if err != nil {
return false, err
}
haveRG := false
rgId := d.Get("rg_id").(int)
for _, rg := range rgList {
if rg.ID == rgId {
haveRG = true
break
}
}
return haveRG, nil
}
func existExtNetID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
extNetID := d.Get("ext_net_id").(int)
if extNetID == 0 || extNetID == -1 {
return true, nil
}
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
extNetList := []struct {
ID int `json:"id"`
}{}
extNetListAPI := "/restmachine/cloudapi/extnet/list"
extNetListRaw, err := c.DecortAPICall(ctx, "POST", extNetListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(extNetListRaw), &extNetList)
if err != nil {
return false, err
}
haveExtNet := false
for _, extNet := range extNetList {
if extNet.ID == extNetID {
haveExtNet = true
break
}
}
return haveExtNet, nil
}
func existAccountID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
accountList := []struct {
ID int `json:"id"`
}{}
accountListAPI := "/restmachine/cloudapi/account/list"
accountListRaw, err := c.DecortAPICall(ctx, "POST", accountListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(accountListRaw), &accountList)
if err != nil {
return false, err
}
haveAccount := false
myAccount := d.Get("account_id").(int)
for _, account := range accountList {
if account.ID == myAccount {
haveAccount = true
break
}
}
return haveAccount, nil
}
func existGID(ctx context.Context, d *schema.ResourceData, m interface{}) (bool, error) {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
locationList := []struct {
GID int `json:"gid"`
}{}
locationsListAPI := "/restmachine/cloudapi/locations/list"
locationListRaw, err := c.DecortAPICall(ctx, "POST", locationsListAPI, urlValues)
if err != nil {
return false, err
}
err = json.Unmarshal([]byte(locationListRaw), &locationList)
if err != nil {
return false, err
}
haveGID := false
gid := d.Get("gid").(int)
for _, location := range locationList {
if location.GID == gid {
haveGID = true
break
}
}
return haveGID, nil
}

@ -38,11 +38,11 @@ import (
"net/url"
"strconv"
log "github.com/sirupsen/logrus"
"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/dc"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/status"
log "github.com/sirupsen/logrus"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@ -53,6 +53,50 @@ func resourceVinsCreate(ctx context.Context, d *schema.ResourceData, m interface
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
if _, ok := d.GetOk("rg_id"); ok {
haveRGID, err := existRGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveRGID {
return diag.Errorf("resourceVinsCreate: can't create ViNS because RGID %d is not allowed or does not exist", d.Get("rg_id").(int))
}
}
if _, ok := d.GetOk("ext_net_id"); ok {
haveExtNetID, err := existExtNetID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveExtNetID {
return diag.Errorf("resourceVinsCreate: can't create ViNS because ExtNetID %d is not allowed or does not exist", d.Get("ext_net_id").(int))
}
}
if _, ok := d.GetOk("account_id"); ok {
haveAccountID, err := existAccountID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveAccountID {
return diag.Errorf("resourceVinsCreate: can't create ViNS because AccountID %d is not allowed or does not exist", d.Get("account_id").(int))
}
}
if _, ok := d.GetOk("gid"); ok {
haveGID, err := existGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveGID {
return diag.Errorf("resourceVinsCreate: can't create ViNS because GID %d is not allowed or does not exist", d.Get("gid").(int))
}
}
rgId, rgOk := d.GetOk("rg_id")
accountId, accountIdOk := d.GetOk("account_id")
if !rgOk && !accountIdOk {
@ -164,7 +208,6 @@ func resourceVinsCreate(ctx context.Context, d *schema.ResourceData, m interface
func resourceVinsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
warnings := dc.Warnings{}
vins, err := utilityVinsCheckPresence(ctx, d, m)
@ -173,40 +216,58 @@ func resourceVinsRead(ctx context.Context, d *schema.ResourceData, m interface{}
return diag.FromErr(err)
}
isEnabled := d.Get("enable").(bool)
hasChangeState := false
if vins.Status == status.Destroyed {
switch vins.Status {
case status.Destroyed:
d.SetId("")
d.Set("vins_id", 0)
return resourceVinsCreate(ctx, d, m)
} else if vins.Status == status.Deleted {
case status.Deleted:
hasChangeState = true
urlValues := &url.Values{}
urlValues.Add("vinsId", d.Id())
_, err := c.DecortAPICall(ctx, "POST", VinsRestoreAPI, urlValues)
if err != nil {
warnings.Add(err)
}
}
urlValues = &url.Values{}
isEnabled := d.Get("enable").(bool)
if vins.Status == status.Disabled && isEnabled {
case status.Modeled:
return diag.Errorf("ViNS are in status: %s, please, contact support for more information", vins.Status)
case status.Created:
case status.Enabled:
if !isEnabled {
hasChangeState = true
urlValues := &url.Values{}
urlValues.Add("vinsId", d.Id())
_, err := c.DecortAPICall(ctx, "POST", VinsEnableAPI, urlValues)
_, err := c.DecortAPICall(ctx, "POST", VinsDisableAPI, urlValues)
if err != nil {
warnings.Add(err)
}
} else if vins.Status == status.Enabled && !isEnabled {
}
case status.Enabling:
case status.Disabled:
if isEnabled {
hasChangeState = true
urlValues := &url.Values{}
urlValues.Add("vinsId", d.Id())
_, err := c.DecortAPICall(ctx, "POST", VinsDisableAPI, urlValues)
_, err := c.DecortAPICall(ctx, "POST", VinsEnableAPI, urlValues)
if err != nil {
warnings.Add(err)
}
}
case status.Disabling:
case status.Deleting:
return diag.Errorf("ViNS are in progress with status: %s", vins.Status)
}
if hasChangeState {
vins, err = utilityVinsCheckPresence(ctx, d, m)
if err != nil {
@ -216,6 +277,7 @@ func resourceVinsRead(ctx context.Context, d *schema.ResourceData, m interface{}
}
flattenVins(d, *vins)
return warnings.Get()
}
@ -245,18 +307,131 @@ func isContinsNatRule(els []interface{}, el interface{}) bool {
func resourceVinsUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := m.(*controller.ControllerCfg)
urlValues := &url.Values{}
warnings := dc.Warnings{}
if _, ok := d.GetOk("rg_id"); ok {
haveRGID, err := existRGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveRGID {
return diag.Errorf("resourceVinsUpdate: can't update ViNS because RGID %d is not allowed or does not exist", d.Get("rg_id").(int))
}
}
if _, ok := d.GetOk("ext_net_id"); ok {
haveExtNetID, err := existExtNetID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveExtNetID {
return diag.Errorf("resourceVinsUpdate: can't update ViNS because ExtNetID %d is not allowed or does not exist", d.Get("ext_net_id").(int))
}
}
if _, ok := d.GetOk("account_id"); ok {
haveAccountID, err := existAccountID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveAccountID {
return diag.Errorf("resourceVinsUpdate: can't update ViNS because AccountID %d is not allowed or does not exist", d.Get("account_id").(int))
}
}
if _, ok := d.GetOk("gid"); ok {
haveGID, err := existGID(ctx, d, m)
if err != nil {
return diag.FromErr(err)
}
if !haveGID {
return diag.Errorf("resourceVinsUpdate: can't update ViNS because GID %d is not allowed or does not exist", d.Get("gid").(int))
}
}
vins, err := utilityVinsCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
isEnabled := d.Get("enable").(bool)
hasChangeState := false
switch vins.Status {
case status.Destroyed:
d.SetId("")
return resourceVinsCreate(ctx, d, m)
case status.Deleted:
hasChangeState = true
urlValues := &url.Values{}
urlValues.Add("vinsId", d.Id())
_, err := c.DecortAPICall(ctx, "POST", VinsRestoreAPI, urlValues)
if err != nil {
warnings.Add(err)
}
case status.Modeled:
return diag.Errorf("ViNS are in status: %s, please, contact support for more information", vins.Status)
case status.Created:
case status.Enabled:
if !isEnabled {
hasChangeState = true
urlValues := &url.Values{}
urlValues.Add("vinsId", d.Id())
_, err := c.DecortAPICall(ctx, "POST", VinsDisableAPI, urlValues)
if err != nil {
warnings.Add(err)
}
}
case status.Enabling:
case status.Disabled:
if isEnabled {
hasChangeState = true
urlValues := &url.Values{}
urlValues.Add("vinsId", d.Id())
_, err := c.DecortAPICall(ctx, "POST", VinsEnableAPI, urlValues)
if err != nil {
warnings.Add(err)
}
}
case status.Disabling:
case status.Deleting:
return diag.Errorf("ViNS are in progress with status: %s", vins.Status)
}
if hasChangeState {
vins, err = utilityVinsCheckPresence(ctx, d, m)
if err != nil {
d.SetId("")
return diag.FromErr(err)
}
}
urlValues := &url.Values{}
enableOld, enableNew := d.GetChange("enable")
if enableOld.(bool) && !enableNew.(bool) {
if !urlValues.Has("vinsId") {
urlValues.Add("vinsId", d.Id())
}
_, err := c.DecortAPICall(ctx, "POST", VinsDisableAPI, urlValues)
if err != nil {
warnings.Add(err)
}
} else if !enableOld.(bool) && enableNew.(bool) {
if !urlValues.Has("vinsId") {
urlValues.Add("vinsId", d.Id())
}
_, err := c.DecortAPICall(ctx, "POST", VinsEnableAPI, urlValues)
if err != nil {
warnings.Add(err)
@ -532,6 +707,7 @@ func resourceVinsSchemaMake() map[string]*schema.Schema {
}
rets["rg_id"] = &schema.Schema{
Type: schema.TypeInt,
Computed: true,
Optional: true,
}
rets["account_id"] = &schema.Schema{

@ -38,9 +38,9 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
log "github.com/sirupsen/logrus"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
log "github.com/sirupsen/logrus"
)
func resourceK8sWgCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
@ -62,35 +62,6 @@ func resourceK8sWgCreate(ctx context.Context, d *schema.ResourceData, m interfac
d.SetId(resp)
// This code is the supposed flow, but at the time of writing it's not yet implemented by the platfom
//urlValues = &url.Values{}
//urlValues.Add("auditId", strings.Trim(resp, `"`))
//for {
//resp, err := controller.decortAPICall("POST", AsyncTaskGetAPI, urlValues)
//if err != nil {
//return err
//}
//task := AsyncTask{}
//if err := json.Unmarshal([]byte(resp), &task); err != nil {
//return err
//}
//log.Debugf("resourceK8sCreate: workers group creating - %s", task.Stage)
//if task.Completed {
//if task.Error != "" {
//return fmt.Errorf("cannot create workers group: %v", task.Error)
//}
//d.SetId(strconv.Itoa(int(task.Result)))
//break
//}
//time.Sleep(time.Second * 5)
//}
return nil
}

@ -35,6 +35,11 @@ package status
type Status = string
var (
// An object is Confirmed
// Status available for:
// - Account
Confirmed Status = "CONFIRMED"
// The disk is linked to any Compute
// Status available for:
// - Disk
@ -45,12 +50,18 @@ var (
// - Compute
// - Disk
// - Vins
// - BasicService
// - K8s Cluster
// - Load Balancer
Enabled Status = "ENABLED"
// Enabling in process
// Status available for:
// - Disk
// - Vins
// - BasicService
// - K8s Cluster
// - Load Balancer
Enabling Status = "ENABLING"
// An object disabled for operations
@ -58,12 +69,19 @@ var (
// - Compute
// - Disk
// - Vins
// - Account
// - BasicService
// - K8s Cluster
// - Load Balancer
Disabled Status = "DISABLED"
// Disabling in process
// Status available for:
// - Disk
// - Vins
// - BasicService
// - K8s Cluster
// - Load Balancer
Disabling Status = "DISABLING"
// An object model has been created in the database
@ -72,11 +90,17 @@ var (
// - Disk
// - Compute
// - Vins
// - BasicService
// - K8s Cluster
// - Load Balancer
Modeled Status = "MODELED"
// In the process of creation
// Status available for:
// - Image
// - Disk
// - K8s Cluster
// - Load Balancer
Creating Status = "CREATING"
// An object was created successfully
@ -85,16 +109,21 @@ var (
// - Disk
// - Compute
// - Vins
// - K8s Cluster
// - BasicService
// - Load Balancer
Created Status = "CREATED"
// Physical resources are allocated for the object
// Status available for:
// - Compute
// - Disk
Allocated Status = "ALLOCATED"
// The object has released (returned to the platform) the physical resources that it occupied
// Status available for:
// - Compute
// - Disk
Unallocated Status = "UNALLOCATED"
// Destroying in progress
@ -102,6 +131,10 @@ var (
// - Disk
// - Compute
// - Vins
// - Account
// - BasicService
// - K8s Cluster
// - Load Balancer
Destroying Status = "DESTROYING"
// Permanently deleted
@ -110,23 +143,36 @@ var (
// - Disk
// - Compute
// - Vins
// - Account
// - BasicService
// - K8s Cluster
// - Load Balancer
Destroyed Status = "DESTROYED"
// Deleting in progress to Trash
// Status available for:
// - Compute
// - Vins
// - BasicService
// - K8s Cluster
// - Load Balancer
Deleting Status = "DELETING"
// Deleted to Trash
// Status available for:
// - Compute
// - Vins
// - Account
// - BasicService
// - Disk
// - K8s Cluster
// - Load Balancer
Deleted Status = "DELETED"
// Deleted from storage
// Status available for:
// - Image
// - Disk
Purged Status = "PURGED"
// Repeating deploy of the object in progress
@ -138,4 +184,16 @@ var (
// Status available for:
// - vins vnf
Stashed Status = "STASHED"
// Object is in restoration process
// Status available for:
// - BasicService
// - K8s Cluster
// - Load Balancer
Restoring Status = "RESTORING"
// Object is in reconfiguration process
// Status available for:
// - BasicService
Reconfiguring Status = "RECONFIGURING"
)

Loading…
Cancel
Save