2021-02-11 00:48:07 +03:00
/ *
Copyright ( c ) 2019 - 2021 Digital Energy Cloud Solutions . All Rights Reserved .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
/ *
2021-02-11 19:31:05 +03:00
This file is part of Terraform ( by Hashicorp ) provider for Digital Energy Cloud Orchestration
2021-02-11 00:48:07 +03:00
Technology platfom .
2021-02-11 19:31:05 +03:00
Visit https : //github.com/rudecs/terraform-provider-decort for full source code package and updates.
2021-02-11 00:48:07 +03:00
* /
package decort
import (
"fmt"
"net/url"
2021-02-12 17:32:40 +03:00
log "github.com/sirupsen/logrus"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
2021-10-02 10:15:32 +03:00
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
2021-02-11 00:48:07 +03:00
)
func resourceResgroupCreate ( d * schema . ResourceData , m interface { } ) error {
// First validate that we have all parameters required to create the new Resource Group
2021-02-11 19:31:05 +03:00
// Valid account ID is required to create new resource group
// obtain Account ID by account name - it should not be zero on success
validated_account_id , err := utilityGetAccountIdBySchema ( d , m )
if err != nil {
return err
2021-02-11 00:48:07 +03:00
}
2021-02-11 19:31:05 +03:00
2021-02-11 00:48:07 +03:00
rg_name , arg_set := d . GetOk ( "name" )
if ! arg_set {
2021-02-11 19:31:05 +03:00
return fmt . Errorf ( "Cannot create new RG: missing name." )
2021-02-11 00:48:07 +03:00
}
2021-02-11 19:31:05 +03:00
2021-04-28 20:42:28 +03:00
/ * Current version of provider works with default grid id ( same is true for disk resources )
2021-02-11 00:48:07 +03:00
grid_id , arg_set := d . GetOk ( "grid_id" )
if ! arg_set {
2021-02-11 19:31:05 +03:00
return fmt . Errorf ( "Cannot create new RG %q in account ID %d: missing Grid ID." ,
rg_name . ( string ) , validated_account_id )
2021-02-11 00:48:07 +03:00
}
2021-04-28 20:42:28 +03:00
if grid_id . ( int ) < 1 {
grid_id = DefaultGridID
}
* /
2021-02-11 00:48:07 +03:00
// all required parameters are set in the schema - we can continue with RG creation
2021-04-28 20:42:28 +03:00
log . Debugf ( "resourceResgroupCreate: called for RG name %s, account ID %d" ,
2021-02-11 19:31:05 +03:00
rg_name . ( string ) , validated_account_id )
2021-02-11 00:48:07 +03:00
// quota settings are optional
set_quota := false
2021-02-11 19:31:05 +03:00
var quota_record QuotaRecord
2021-02-12 17:32:40 +03:00
arg_value , arg_set := d . GetOk ( "quota" )
2021-02-11 00:48:07 +03:00
if arg_set {
log . Debugf ( "resourceResgroupCreate: setting Quota on RG requested" )
quota_record , _ = makeQuotaRecord ( arg_value . ( [ ] interface { } ) )
set_quota = true
}
controller := m . ( * ControllerCfg )
2021-04-28 20:42:28 +03:00
log . Debugf ( "resourceResgroupCreate: called by user %q for RG name %s, account ID %d" ,
2021-02-12 17:32:40 +03:00
controller . getDecortUsername ( ) ,
2021-04-28 20:42:28 +03:00
rg_name . ( string ) , validated_account_id )
2021-02-11 19:31:05 +03:00
2021-02-11 00:48:07 +03:00
url_values := & url . Values { }
url_values . Add ( "accountId" , fmt . Sprintf ( "%d" , validated_account_id ) )
url_values . Add ( "name" , rg_name . ( string ) )
2021-04-28 20:42:28 +03:00
url_values . Add ( "gid" , fmt . Sprintf ( "%d" , DefaultGridID ) ) // use default Grid ID, similar to disk resource mgmt convention
2021-02-12 17:32:40 +03:00
url_values . Add ( "owner" , controller . getDecortUsername ( ) )
2021-02-11 19:31:05 +03:00
2021-02-11 00:48:07 +03:00
// pass quota values as set
if set_quota {
url_values . Add ( "maxCPUCapacity" , fmt . Sprintf ( "%d" , quota_record . Cpu ) )
url_values . Add ( "maxVDiskCapacity" , fmt . Sprintf ( "%d" , quota_record . Disk ) )
2021-03-12 10:33:08 +03:00
url_values . Add ( "maxMemoryCapacity" , fmt . Sprintf ( "%f" , quota_record . Ram ) ) // RAM quota is float; this may change in the future
2021-02-11 00:48:07 +03:00
url_values . Add ( "maxNetworkPeerTransfer" , fmt . Sprintf ( "%d" , quota_record . ExtTraffic ) )
url_values . Add ( "maxNumPublicIP" , fmt . Sprintf ( "%d" , quota_record . ExtIPs ) )
// url_values.Add("???", fmt.Sprintf("%d", quota_record.GpuUnits))
}
// parse and handle network settings
2021-02-12 17:32:40 +03:00
def_net_type , arg_set := d . GetOk ( "def_net_type" )
2021-02-11 00:48:07 +03:00
if arg_set {
2021-02-12 17:32:40 +03:00
url_values . Add ( "def_net" , def_net_type . ( string ) ) // NOTE: in API default network type is set by "def_net" parameter
2021-02-11 00:48:07 +03:00
}
2021-02-12 17:32:40 +03:00
ipcidr , arg_set := d . GetOk ( "ipcidr" )
2021-02-11 00:48:07 +03:00
if arg_set {
2021-02-12 17:32:40 +03:00
url_values . Add ( "ipcidr" , ipcidr . ( string ) )
2021-02-11 00:48:07 +03:00
}
2021-02-12 17:32:40 +03:00
ext_net_id , arg_set := d . GetOk ( "ext_net_id" )
2021-02-11 00:48:07 +03:00
if arg_set {
2021-02-12 17:32:40 +03:00
url_values . Add ( "extNetId" , fmt . Sprintf ( "%d" , ext_net_id . ( int ) ) )
2021-02-11 00:48:07 +03:00
}
2021-02-12 17:32:40 +03:00
ext_ip , arg_set := d . GetOk ( "ext_ip" )
2021-02-11 00:48:07 +03:00
if arg_set {
2021-02-12 17:32:40 +03:00
url_values . Add ( "extIp" , ext_ip . ( string ) )
2021-02-11 00:48:07 +03:00
}
2021-02-11 19:31:05 +03:00
2021-02-11 00:48:07 +03:00
api_resp , err := controller . decortAPICall ( "POST" , ResgroupCreateAPI , url_values )
if err != nil {
return err
}
d . SetId ( api_resp ) // rg/create API returns ID of the newly creted resource group on success
2021-02-12 17:32:40 +03:00
// rg.ID, _ = strconv.Atoi(api_resp)
2021-02-11 00:48:07 +03:00
// re-read newly created RG to make sure schema contains complete and up to date set of specifications
return resourceResgroupRead ( d , m )
}
func resourceResgroupRead ( d * schema . ResourceData , m interface { } ) error {
2021-04-28 20:42:28 +03:00
log . Debugf ( "resourceResgroupRead: called for RG name %s, account ID %s" ,
d . Get ( "name" ) . ( string ) , d . Get ( "account_id" ) . ( int ) )
2021-02-11 00:48:07 +03:00
rg_facts , err := utilityResgroupCheckPresence ( d , m )
if rg_facts == "" {
// if empty string is returned from utilityResgroupCheckPresence then there is no
2021-02-11 19:31:05 +03:00
// such resource group and err tells so - just return it to the calling party
2021-02-11 00:48:07 +03:00
d . SetId ( "" ) // ensure ID is empty
return err
}
return flattenResgroup ( d , rg_facts )
}
func resourceResgroupUpdate ( d * schema . ResourceData , m interface { } ) error {
2021-04-28 20:42:28 +03:00
log . Debugf ( "resourceResgroupUpdate: called for RG name %s, account ID %d" ,
d . Get ( "name" ) . ( string ) , d . Get ( "account_id" ) . ( int ) )
2021-02-11 00:48:07 +03:00
2021-10-04 19:55:03 +03:00
/ * NOTE : we do not allow changing the following attributes of an existing RG via terraform :
- def_net_type
- ipcidr
- ext_net_id
- ext_ip
The following code fragment checks if any of these have been changed and generates error .
* /
for _ , attr := range [ ] string { "def_net_type" , "ipcidr" , "ext_ip" } {
attr_new , attr_old := d . GetChange ( "def_net_type" )
if attr_new . ( string ) != attr_old . ( string ) {
return fmt . Errorf ( "resourceResgroupUpdate: RG ID %s: changing %s for existing RG is not allowed" , d . Id ( ) , attr )
}
}
attr_new , attr_old := d . GetChange ( "ext_net_id" )
if attr_new . ( int ) != attr_old . ( int ) {
return fmt . Errorf ( "resourceResgroupUpdate: RG ID %s: changing ext_net_id for existing RG is not allowed" , d . Id ( ) )
}
do_general_update := false // will be true if general RG update is necessary (API rg/update)
2021-02-11 00:48:07 +03:00
controller := m . ( * ControllerCfg )
url_values := & url . Values { }
url_values . Add ( "rgId" , d . Id ( ) )
name_new , name_set := d . GetOk ( "name" )
if name_set {
log . Debugf ( "resourceResgroupUpdate: name specified - looking for deltas from the old settings." )
name_old , _ := d . GetChange ( "name" )
if name_old . ( string ) != name_new . ( string ) {
2021-10-04 19:55:03 +03:00
do_general_update = true
2021-02-11 00:48:07 +03:00
url_values . Add ( "name" , name_new . ( string ) )
}
}
2021-02-11 19:31:05 +03:00
2021-02-11 00:48:07 +03:00
quota_value , quota_set := d . GetOk ( "quota" )
if quota_set {
log . Debugf ( "resourceResgroupUpdate: quota specified - looking for deltas from the old quota." )
quotarecord_new , _ := makeQuotaRecord ( quota_value . ( [ ] interface { } ) )
2021-02-12 17:32:40 +03:00
quota_value_old , _ := d . GetChange ( "quota" ) // returns old as 1st, new as 2nd return value
2021-02-11 00:48:07 +03:00
quotarecord_old , _ := makeQuotaRecord ( quota_value_old . ( [ ] interface { } ) )
if quotarecord_new . Cpu != quotarecord_old . Cpu {
2021-10-04 19:55:03 +03:00
do_general_update = true
2021-02-11 00:48:07 +03:00
log . Debugf ( "resourceResgroupUpdate: Cpu diff %d <- %d" , quotarecord_new . Cpu , quotarecord_old . Cpu )
url_values . Add ( "maxCPUCapacity" , fmt . Sprintf ( "%d" , quotarecord_new . Cpu ) )
}
2021-02-11 19:31:05 +03:00
2021-02-11 00:48:07 +03:00
if quotarecord_new . Disk != quotarecord_old . Disk {
2021-10-04 19:55:03 +03:00
do_general_update = true
2021-02-11 00:48:07 +03:00
log . Debugf ( "resourceResgroupUpdate: Disk diff %d <- %d" , quotarecord_new . Disk , quotarecord_old . Disk )
url_values . Add ( "maxVDiskCapacity" , fmt . Sprintf ( "%d" , quotarecord_new . Disk ) )
}
2021-02-11 19:31:05 +03:00
2021-03-11 00:06:55 +03:00
if quotarecord_new . Ram != quotarecord_old . Ram { // NB: quota on RAM is stored as float32, in units of MB
2021-10-04 19:55:03 +03:00
do_general_update = true
2021-02-11 00:48:07 +03:00
log . Debugf ( "resourceResgroupUpdate: Ram diff %f <- %f" , quotarecord_new . Ram , quotarecord_old . Ram )
url_values . Add ( "maxMemoryCapacity" , fmt . Sprintf ( "%f" , quotarecord_new . Ram ) )
}
2021-02-11 19:31:05 +03:00
2021-02-11 00:48:07 +03:00
if quotarecord_new . ExtTraffic != quotarecord_old . ExtTraffic {
2021-10-04 19:55:03 +03:00
do_general_update = true
2021-02-12 17:32:40 +03:00
log . Debugf ( "resourceResgroupUpdate: ExtTraffic diff %d <- %d" , quotarecord_new . ExtTraffic , quotarecord_old . ExtTraffic )
url_values . Add ( "maxNetworkPeerTransfer" , fmt . Sprintf ( "%d" , quotarecord_new . ExtTraffic ) )
2021-02-11 00:48:07 +03:00
}
2021-02-11 19:31:05 +03:00
2021-02-11 00:48:07 +03:00
if quotarecord_new . ExtIPs != quotarecord_old . ExtIPs {
2021-10-04 19:55:03 +03:00
do_general_update = true
2021-02-11 00:48:07 +03:00
log . Debugf ( "resourceResgroupUpdate: ExtIPs diff %d <- %d" , quotarecord_new . ExtIPs , quotarecord_old . ExtIPs )
url_values . Add ( "maxNumPublicIP" , fmt . Sprintf ( "%d" , quotarecord_new . ExtIPs ) )
}
}
2021-02-24 17:34:31 +03:00
desc_new , desc_set := d . GetOk ( "description" )
2021-02-11 00:48:07 +03:00
if desc_set {
log . Debugf ( "resourceResgroupUpdate: description specified - looking for deltas from the old settings." )
2021-02-24 17:34:31 +03:00
desc_old , _ := d . GetChange ( "description" )
2021-02-11 00:48:07 +03:00
if desc_old . ( string ) != desc_new . ( string ) {
2021-10-04 19:55:03 +03:00
do_general_update = true
2021-02-11 00:48:07 +03:00
url_values . Add ( "desc" , desc_new . ( string ) )
}
}
2021-10-04 19:55:03 +03:00
if do_general_update {
2021-02-11 00:48:07 +03:00
log . Debugf ( "resourceResgroupUpdate: detected delta between new and old RG specs - updating the RG" )
_ , err := controller . decortAPICall ( "POST" , ResgroupUpdateAPI , url_values )
if err != nil {
return err
}
} else {
log . Debugf ( "resourceResgroupUpdate: no difference between old and new state - no update on the RG will be done" )
}
2021-02-11 19:31:05 +03:00
2021-02-11 00:48:07 +03:00
return resourceResgroupRead ( d , m )
}
func resourceResgroupDelete ( d * schema . ResourceData , m interface { } ) error {
// NOTE: this method forcibly destroys target resource group with flag "permanently", so there is no way to
// restore the destroyed resource group as well all Computes & VINSes that existed in it
2021-04-28 20:42:28 +03:00
log . Debugf ( "resourceResgroupDelete: called for RG name %s, account ID %s" ,
d . Get ( "name" ) . ( string ) , d . Get ( "account_id" ) . ( int ) )
2021-02-11 00:48:07 +03:00
rg_facts , err := utilityResgroupCheckPresence ( d , m )
if rg_facts == "" {
2021-02-11 19:31:05 +03:00
// the target RG does not exist - in this case according to Terraform best practice
2021-02-11 00:48:07 +03:00
// we exit from Destroy method without error
return nil
}
url_values := & url . Values { }
url_values . Add ( "rgId" , d . Id ( ) )
2021-09-16 17:06:18 +03:00
url_values . Add ( "force" , "1" )
url_values . Add ( "permanently" , "1" )
2021-02-11 00:48:07 +03:00
url_values . Add ( "reason" , "Destroyed by DECORT Terraform provider" )
controller := m . ( * ControllerCfg )
_ , err = controller . decortAPICall ( "POST" , ResgroupDeleteAPI , url_values )
if err != nil {
return err
}
return nil
}
func resourceResgroupExists ( d * schema . ResourceData , m interface { } ) ( bool , error ) {
// Reminder: according to Terraform rules, this function should NOT modify ResourceData argument
rg_facts , err := utilityResgroupCheckPresence ( d , m )
if rg_facts == "" {
if err != nil {
return false , err
}
return false , nil
}
return true , nil
}
func resourceResgroup ( ) * schema . Resource {
2021-02-11 19:31:05 +03:00
return & schema . Resource {
2021-02-11 00:48:07 +03:00
SchemaVersion : 1 ,
Create : resourceResgroupCreate ,
Read : resourceResgroupRead ,
Update : resourceResgroupUpdate ,
Delete : resourceResgroupDelete ,
Exists : resourceResgroupExists ,
2021-04-28 20:42:28 +03:00
Importer : & schema . ResourceImporter {
State : schema . ImportStatePassthrough ,
} ,
2021-02-11 19:31:05 +03:00
Timeouts : & schema . ResourceTimeout {
2021-02-11 00:48:07 +03:00
Create : & Timeout180s ,
Read : & Timeout30s ,
Update : & Timeout180s ,
Delete : & Timeout60s ,
Default : & Timeout60s ,
} ,
2021-02-11 19:31:05 +03:00
Schema : map [ string ] * schema . Schema {
2021-03-11 00:06:55 +03:00
"name" : {
2021-02-11 00:48:07 +03:00
Type : schema . TypeString ,
Required : true ,
Description : "Name of this resource group. Names are case sensitive and unique within the context of a account." ,
} ,
2021-03-11 00:06:55 +03:00
"account_id" : {
2021-02-11 19:31:05 +03:00
Type : schema . TypeInt ,
2021-04-28 20:42:28 +03:00
Required : true ,
2021-10-02 10:15:32 +03:00
ValidateFunc : validation . IntAtLeast ( 1 ) ,
2021-04-28 20:42:28 +03:00
Description : "Unique ID of the account, which this resource group belongs to." ,
2021-02-11 00:48:07 +03:00
} ,
2021-03-11 00:06:55 +03:00
"def_net_type" : {
2021-02-11 00:48:07 +03:00
Type : schema . TypeString ,
Optional : true ,
2021-02-11 19:31:05 +03:00
Default : "PRIVATE" ,
2021-10-04 19:55:03 +03:00
ValidateFunc : validation . StringInSlice ( [ ] string { "PRIVATE" , "PUBLIC" , "NONE" } , false ) ,
2021-02-11 00:48:07 +03:00
Description : "Type of the network, which this resource group will use as default for its computes - PRIVATE or PUBLIC or NONE." ,
} ,
2021-03-11 00:06:55 +03:00
"def_net_id" : {
2021-02-12 11:13:03 +03:00
Type : schema . TypeInt ,
Computed : true ,
Description : "ID of the default network for this resource group (if any)." ,
} ,
2021-03-11 00:06:55 +03:00
"ipcidr" : {
2021-02-11 00:48:07 +03:00
Type : schema . TypeString ,
Optional : true ,
2021-02-12 11:13:03 +03:00
Description : "Address of the netowrk inside the private network segment (aka ViNS) if def_net_type=PRIVATE" ,
2021-02-11 00:48:07 +03:00
} ,
2021-03-11 00:06:55 +03:00
"ext_net_id" : {
2021-02-11 00:48:07 +03:00
Type : schema . TypeInt ,
Optional : true ,
Default : 0 ,
2021-10-04 19:55:03 +03:00
Description : "ID of the external network for default ViNS. Pass 0 if def_net_type=PUBLIC or no external connection required for the defult ViNS when def_net_type=PRIVATE" ,
2021-02-11 00:48:07 +03:00
} ,
2021-03-11 00:06:55 +03:00
"ext_ip" : {
2021-02-11 00:48:07 +03:00
Type : schema . TypeString ,
Optional : true ,
2021-10-04 19:55:03 +03:00
Description : "IP address on the external netowrk to request when def_net_type=PRIVATE and ext_net_id is not 0" ,
2021-02-11 00:48:07 +03:00
} ,
2021-04-28 20:42:28 +03:00
/ * commented out , as in this version of provider we use default Grid ID
"grid_id" : {
2021-02-11 00:48:07 +03:00
Type : schema . TypeInt ,
2021-04-28 20:42:28 +03:00
Optional : true ,
Default : 0 , // if 0 is passed, default Grid ID will be used
// DefaultFunc: utilityResgroupGetDefaultGridID,
ForceNew : true , // change of Grid ID will require new RG
2021-02-11 00:48:07 +03:00
Description : "Unique ID of the grid, where this resource group is deployed." ,
} ,
2021-04-28 20:42:28 +03:00
* /
2021-02-11 00:48:07 +03:00
"quota" : {
2021-02-11 19:31:05 +03:00
Type : schema . TypeList ,
Optional : true ,
MaxItems : 1 ,
Elem : & schema . Resource {
2021-02-12 11:13:03 +03:00
Schema : quotaRgSubresourceSchemaMake ( ) ,
2021-02-11 00:48:07 +03:00
} ,
Description : "Quota settings for this resource group." ,
} ,
2021-02-24 17:34:31 +03:00
"description" : {
2021-02-11 19:31:05 +03:00
Type : schema . TypeString ,
Optional : true ,
Description : "User-defined text description of this resource group." ,
2021-02-11 00:48:07 +03:00
} ,
2021-04-28 20:42:28 +03:00
"account_name" : {
Type : schema . TypeString ,
Computed : true ,
Description : "Name of the account, which this resource group belongs to." ,
} ,
/ *
2021-02-11 19:31:05 +03:00
"status" : {
Type : schema . TypeString ,
Computed : true ,
Description : "Current status of this resource group." ,
2021-02-11 00:48:07 +03:00
} ,
"vins" : {
2021-02-11 19:31:05 +03:00
Type : schema . TypeList , // this is a list of ints
Computed : true ,
MaxItems : LimitMaxVinsPerResgroup ,
Elem : & schema . Schema {
Type : schema . TypeInt ,
2021-02-11 00:48:07 +03:00
} ,
Description : "List of VINs deployed in this resource group." ,
} ,
"computes" : {
2021-02-11 19:31:05 +03:00
Type : schema . TypeList , // this is a list of ints
Computed : true ,
Elem : & schema . Schema {
Type : schema . TypeInt ,
2021-02-11 00:48:07 +03:00
} ,
Description : "List of computes deployed in this resource group." ,
} ,
2021-03-12 10:33:08 +03:00
* /
2021-02-11 00:48:07 +03:00
} ,
}
2021-02-11 19:31:05 +03:00
}