package utilities
import (
"context"
"fmt"
"strconv"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/k8ci"
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/client"
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/service/cloudbroker/k8ci/models"
"repository.basistech.ru/BASIS/terraform-provider-dynamix/internal/status"
)
func CreateRequestResourceK8CI ( ctx context . Context , plan * models . ResourceK8CIModel ) ( k8ci . CreateRequest , diag . Diagnostics ) {
tflog . Info ( ctx , "Start CreateRequestResourceK8CI" , map [ string ] any {
"name" : plan . Name . ValueString ( ) ,
} )
// set up required parameters in resource group create request
createReq := k8ci . CreateRequest {
Name : plan . Name . ValueString ( ) ,
Version : plan . Version . ValueString ( ) ,
MasterDriver : plan . MasterDriver . ValueString ( ) ,
WorkerDriver : plan . WorkerDriver . ValueString ( ) ,
MaxMasterCount : uint64 ( plan . MaxMasterCount . ValueInt64 ( ) ) ,
MaxWorkerCount : uint64 ( plan . MaxWorkerCount . ValueInt64 ( ) ) ,
MasterImageID : uint64 ( plan . MasterImageId . ValueInt64 ( ) ) ,
WorkerImageID : uint64 ( plan . WorkerImageId . ValueInt64 ( ) ) ,
}
networkPlugins := make ( [ ] string , 0 , len ( plan . NetworkPlugins . Elements ( ) ) )
for _ , plugin := range plan . NetworkPlugins . Elements ( ) {
networkPlugins = append ( networkPlugins , plugin . ( types . String ) . ValueString ( ) )
}
createReq . NetworkPlugins = networkPlugins
if ! plan . Description . IsNull ( ) {
createReq . Description = plan . Description . ValueString ( )
}
if ! plan . SharedWith . IsNull ( ) {
sharedWith := make ( [ ] uint64 , 0 , len ( plan . SharedWith . Elements ( ) ) )
for _ , shared := range plan . SharedWith . Elements ( ) {
sharedWith = append ( sharedWith , uint64 ( shared . ( types . Int64 ) . ValueInt64 ( ) ) )
}
createReq . SharedWith = sharedWith
}
return createReq , nil
}
func K8CIResourceEnableDisable ( ctx context . Context , plan * models . ResourceK8CIModel , c * client . Client ) diag . Diagnostics {
tflog . Info ( ctx , "EnableDisable k8ci with ID" , map [ string ] any { "k8ci_id" : plan . Id . ValueString ( ) } )
diags := diag . Diagnostics { }
k8ciid , err := strconv . ParseUint ( plan . Id . ValueString ( ) , 10 , 64 )
if err != nil {
diags . AddError ( "Cannot parsed ID k8ci from state" , err . Error ( ) )
return diags
}
if plan . Enabled . IsNull ( ) || plan . Enabled . ValueBool ( ) {
tflog . Info ( ctx , "Enable k8ci with ID" , map [ string ] any { "k8ci_id" : plan . Id . ValueString ( ) } )
_ , err := c . CloudBroker ( ) . K8CI ( ) . Enable ( ctx , k8ci . EnableRequest { K8CIID : k8ciid } )
if err != nil {
diags . AddError ( "K8CIResourceEnableDisable: error to enable k8ci" , err . Error ( ) )
return diags
}
} else {
tflog . Info ( ctx , "Disable k8ci with ID" , map [ string ] any { "k8ci_id" : plan . Id . ValueString ( ) } )
_ , err := c . CloudBroker ( ) . K8CI ( ) . Disable ( ctx , k8ci . DisableRequest { K8CIID : k8ciid } )
if err != nil {
diags . AddError ( "K8CIResourceEnableDisable: error to disable k8ci" , err . Error ( ) )
return diags
}
}
return diags
}
func K8CIResourceCheckPresence ( ctx context . Context , plan * models . ResourceK8CIModel , c * client . Client ) ( * k8ci . RecordK8CI , diag . Diagnostics ) {
tflog . Info ( ctx , fmt . Sprintf ( "K8CIResourceCheckPresence: Get info about k8ci with ID - %v" , plan . Id . ValueString ( ) ) )
diags := diag . Diagnostics { }
k8ciid , err := strconv . ParseUint ( plan . Id . ValueString ( ) , 10 , 64 )
if err != nil {
diags . AddError ( "Cannot parsed ID k8ci from state" , err . Error ( ) )
return nil , diags
}
recordK8ci , err := c . CloudBroker ( ) . K8CI ( ) . Get ( ctx , k8ci . GetRequest { K8CIID : k8ciid } )
if err != nil {
diags . AddError ( fmt . Sprintf ( "Cannot get info about k8ci with ID %v" , k8ciid ) , err . Error ( ) )
return nil , diags
}
tflog . Info ( ctx , "K8CIResourceCheckPresence: response from CloudBroker().K8CI().Get" , map [ string ] any { "k8ci_id" : k8ciid , "response" : recordK8ci } )
return recordK8ci , nil
}
func K8CIReadStatus ( ctx context . Context , plan * models . ResourceK8CIModel , c * client . Client ) diag . Diagnostics {
tflog . Info ( ctx , "Read status k8ci with ID" , map [ string ] any { "k8ci_id" : plan . Id . ValueString ( ) } )
diags := diag . Diagnostics { }
k8ciid , err := strconv . ParseUint ( plan . Id . ValueString ( ) , 10 , 64 )
if err != nil {
diags . AddError ( "Cannot parsed ID k8ci from state" , err . Error ( ) )
return diags
}
k8ciItem , err := c . CloudBroker ( ) . K8CI ( ) . Get ( ctx , k8ci . GetRequest { K8CIID : k8ciid } )
if err != nil {
diags . AddError ( fmt . Sprintf ( "Cannot get info about k8ci with ID %v" , k8ciItem ) , err . Error ( ) )
return diags
}
switch k8ciItem . Status {
case status . Modeled :
diags . AddError ( "Error:" , fmt . Sprintf ( "The k8ci is in status: %s, please, contact support for more information" , k8ciItem . Status ) )
return diags
case status . Deleted :
if plan . Restore . ValueBool ( ) || plan . Restore . IsNull ( ) {
diags = K8CIRestore ( ctx , plan , c )
if diags . HasError ( ) {
tflog . Error ( ctx , "Error restore K8CI" , map [ string ] any { "k8ci_id" : plan . Id . ValueString ( ) } )
return diags
}
} else {
diags . AddError ( "k8ci in status Deleted:" , "please clean state, or restore k8ci" )
return diags
}
diags = K8CIResourceEnableDisable ( ctx , plan , c )
if diags . HasError ( ) {
tflog . Error ( ctx , "Error enable/disable k8ci" , map [ string ] any { "k8ci_id" : plan . Id . ValueString ( ) } )
return diags
}
case status . Destroying :
diags . AddError ( "Error:" , fmt . Sprintf ( "The k8ci is in progress with status: %s" , k8ciItem . Status ) )
return diags
case status . Destroyed :
diags . AddError ( "Error:" , "The resource cannot be updated because it has been destroyed" )
return diags
}
tflog . Info ( ctx , "Read status k8ci successfully" , map [ string ] any { "k8ci_id" : plan . Id . ValueString ( ) } )
return diags
}
func K8CIRestore ( ctx context . Context , plan * models . ResourceK8CIModel , c * client . Client ) diag . Diagnostics {
tflog . Info ( ctx , "Restore k8ci with ID" , map [ string ] any { "k8ci_id" : plan . Id . ValueString ( ) } )
diags := diag . Diagnostics { }
k8ciid , err := strconv . ParseUint ( plan . Id . ValueString ( ) , 10 , 64 )
if err != nil {
diags . AddError ( "Cannot parsed ID k8ci from state" , err . Error ( ) )
return diags
}
_ , err = c . CloudBroker ( ) . K8CI ( ) . Restore ( ctx , k8ci . RestoreRequest { K8CIID : k8ciid } )
if err != nil {
diags . AddError ( fmt . Sprintf ( "Cannot restore k8ci with ID - %s" , plan . Id . ValueString ( ) ) , err . Error ( ) )
return diags
}
tflog . Info ( ctx , "Restore k8ci successfully" , map [ string ] any { "k8ci_id" : plan . Id . ValueString ( ) } )
return diags
}
func K8CIIUpdateVarChecks ( plan * models . ResourceK8CIModel , state * models . ResourceK8CIModel ) diag . Diagnostics {
diags := diag . Diagnostics { }
if ! plan . Name . Equal ( state . Name ) {
diags . AddError (
"Update resourceK8CI: Invalid input Name" ,
fmt . Sprintf ( "block Name must not be changed for resource with k8ci_id %s" , plan . Id . ValueString ( ) ) ,
)
return diags
}
if ! plan . Version . Equal ( state . Version ) {
diags . AddError (
"Update resourceK8CI: Invalid input Version" ,
fmt . Sprintf ( "block Version must not be changed for resource with k8ci_id %s" , plan . Id . ValueString ( ) ) ,
)
return diags
}
if ! plan . MasterDriver . Equal ( state . MasterDriver ) {
diags . AddError (
"Update resourceK8CI: Invalid MasterDriver" ,
fmt . Sprintf ( "block MasterDriver must not be changed for resource with k8ci_id %s" , plan . Id . ValueString ( ) ) ,
)
return diags
}
if ! plan . MasterImageId . Equal ( state . MasterImageId ) {
diags . AddError (
"Update resourceK8CI: Invalid MasterImageId" ,
fmt . Sprintf ( "block MasterImageId must not be changed for resource with k8ci_id %s" , plan . Id . ValueString ( ) ) ,
)
return diags
}
if ! plan . MaxMasterCount . Equal ( state . MaxMasterCount ) {
diags . AddError (
"Update resourceK8CI: Invalid MaxMasterCount" ,
fmt . Sprintf ( "block MaxMasterCount must not be changed for resource with k8ci_id %s" , plan . Id . ValueString ( ) ) ,
)
return diags
}
if ! plan . MaxWorkerCount . Equal ( state . MaxWorkerCount ) {
diags . AddError (
"Update resourceK8CI: Invalid MaxWorkerCount" ,
fmt . Sprintf ( "block MaxWorkerCount must not be changed for resource with k8ci_id %s" , plan . Id . ValueString ( ) ) ,
)
return diags
}
if ! plan . NetworkPlugins . Equal ( state . NetworkPlugins ) {
diags . AddError (
"Update resourceK8CI: Invalid NetworkPlugins" ,
fmt . Sprintf ( "block NetworkPlugins must not be changed for resource with k8ci_id %s" , plan . Id . ValueString ( ) ) ,
)
return diags
}
if ! plan . WorkerDriver . Equal ( state . WorkerDriver ) {
diags . AddError (
"Update resourceK8CI: Invalid WorkerDriver" ,
fmt . Sprintf ( "block WorkerDriver must not be changed for resource with k8ci_id %s" , plan . Id . ValueString ( ) ) ,
)
return diags
}
if ! plan . WorkerImageId . Equal ( state . WorkerImageId ) {
diags . AddError (
"Update resourceK8CI: Invalid WorkerImageId" ,
fmt . Sprintf ( "block WorkerImageId must not be changed for resource with k8ci_id %s" , plan . Id . ValueString ( ) ) ,
)
return diags
}
return nil
}
func K8CISharedWithUpdate ( ctx context . Context , plan * models . ResourceK8CIModel , state * models . ResourceK8CIModel , c * client . Client ) diag . Diagnostics {
diags := diag . Diagnostics { }
k8ciid , err := strconv . ParseUint ( state . Id . ValueString ( ) , 10 , 64 )
if err != nil {
diags . AddError ( "K8CISharedWithUpdate: cannot parsed ID k8ci from state" , err . Error ( ) )
return diags
}
addSet , removeSet := difference ( state . SharedWith , plan . SharedWith )
for _ , account := range addSet {
accountId := uint64 ( account . ( types . Int64 ) . ValueInt64 ( ) )
tflog . Info ( ctx , fmt . Sprintf ( "K8CISharedWithUpdate: Start add account with ID - %d to sharedWith access list to k8ci with ID - %d" , accountId , k8ciid ) )
req := k8ci . AccessAddRequest {
K8CIID : k8ciid ,
AccountId : accountId ,
}
res , err := c . CloudBroker ( ) . K8CI ( ) . AccessAdd ( ctx , req )
tflog . Info ( ctx , "K8CISharedWithUpdate: response from CloudBroker().K8CI().AccessAdd" , map [ string ] any { "k8ci_id" : plan . Id . ValueString ( ) , "response" : res } )
if err != nil {
diags . AddError ( fmt . Sprintf ( "K8CISharedWithUpdate: Cannot add account with ID - %d" , accountId ) , err . Error ( ) )
}
}
if diags . HasError ( ) {
tflog . Error ( ctx , "K8CISharedWithUpdate: Errors occurred while managing add accounts" )
return diags
}
for _ , account := range removeSet {
accountId := uint64 ( account . ( types . Int64 ) . ValueInt64 ( ) )
tflog . Info ( ctx , fmt . Sprintf ( "K8CISharedWithUpdate: Start remove account with ID - %d from sharedWith access list to k8ci with ID - %d" , accountId , k8ciid ) )
req := k8ci . AccessRemoveRequest {
K8CIID : k8ciid ,
AccountId : accountId ,
}
res , err := c . CloudBroker ( ) . K8CI ( ) . AccessRemove ( ctx , req )
tflog . Info ( ctx , "K8CISharedWithUpdate: response from CloudBroker().K8CI().AccessRemove" , map [ string ] any { "k8ci_id" : plan . Id . ValueString ( ) , "response" : res } )
if err != nil {
diags . AddError ( fmt . Sprintf ( "K8CISharedWithUpdate: Cannot remove account with ID - %d" , accountId ) , err . Error ( ) )
}
}
if diags . HasError ( ) {
tflog . Error ( ctx , "K8CISharedWithUpdate: Errors occurred while managing remove accounts" )
return diags
}
tflog . Info ( ctx , "K8CISharedWithUpdate: sharedWith access list is successfully update" , map [ string ] any { "k8ci_id" : k8ciid } )
return nil
}
// difference returns lists added and removed values
func difference ( oldSet , newSet types . List ) ( added , removed [ ] any ) {
oldMap := make ( map [ interface { } ] struct { } )
newMap := make ( map [ interface { } ] struct { } )
for _ , elem := range oldSet . Elements ( ) {
oldMap [ elem ] = struct { } { }
}
for _ , elem := range newSet . Elements ( ) {
newMap [ elem ] = struct { } { }
}
for elem := range newMap {
if _ , found := oldMap [ elem ] ; ! found {
added = append ( added , elem )
}
}
for elem := range oldMap {
if _ , found := newMap [ elem ] ; ! found {
removed = append ( removed , elem )
}
}
return
}