Compare commits
No commits in common. 'main' and 'dev-old' have entirely different histories.
@ -0,0 +1,52 @@
|
|||||||
|
pipeline {
|
||||||
|
agent {
|
||||||
|
kubernetes {
|
||||||
|
yaml '''
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: alpine
|
||||||
|
image: alpine:3.15
|
||||||
|
command:
|
||||||
|
- sleep
|
||||||
|
- infinity
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stages {
|
||||||
|
stage('Dependency check') {
|
||||||
|
environment {
|
||||||
|
DEPCHECKDB = credentials('depcheck-postgres')
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
container('alpine') {
|
||||||
|
sh 'apk update && apk add openjdk11 java-postgresql-jdbc go'
|
||||||
|
dependencyCheck additionalArguments: '-f JSON -f HTML -n --enableExperimental \
|
||||||
|
-l deplog \
|
||||||
|
--dbDriverName org.postgresql.Driver \
|
||||||
|
--dbDriverPath /usr/share/java/postgresql-jdbc.jar \
|
||||||
|
--dbUser $DEPCHECKDB_USR \
|
||||||
|
--dbPassword $DEPCHECKDB_PSW \
|
||||||
|
--connectionString jdbc:postgresql://postgres-postgresql.postgres/depcheck', odcInstallation: 'depcheck'
|
||||||
|
sh 'cat deplog'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('SonarQube analysis') {
|
||||||
|
environment {
|
||||||
|
SONARSCANNER_HOME = tool 'sonarscanner'
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
withSonarQubeEnv('sonarqube') {
|
||||||
|
sh '$SONARSCANNER_HOME/bin/sonar-scanner'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('SonarQube quality gate') {
|
||||||
|
steps {
|
||||||
|
waitForQualityGate webhookSecretId: 'sonar-webhook', abortPipeline: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,123 @@
|
|||||||
|
# terraform-provider-decort
|
||||||
|
Terraform provider for Digital Energy Cloud Orchestration Technology (DECORT) platform
|
||||||
|
|
||||||
|
NOTE: provider rc-1.25 is designed for DECORT API 3.7.x. For older API versions please use:
|
||||||
|
- DECORT API 3.6.x versions - provider version rc-1.10
|
||||||
|
- DECORT API versions prior to 3.6.0 - Terraform DECS provider (https://github.com/rudecs/terraform-provider-decs)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Work with Compute instances,
|
||||||
|
- Work with disks,
|
||||||
|
- Work with k8s,
|
||||||
|
- Work with image,
|
||||||
|
- Work with reource groups,
|
||||||
|
- Work with VINS,
|
||||||
|
- Work with pfw,
|
||||||
|
- Work with accounts,
|
||||||
|
- Work with snapshots,
|
||||||
|
- Work with pcidevice.
|
||||||
|
- Work with sep,
|
||||||
|
- Work with vgpu,
|
||||||
|
- Work with bservice,
|
||||||
|
- Work with extnets.
|
||||||
|
|
||||||
|
This provider supports Import operations on pre-existing resources.
|
||||||
|
|
||||||
|
See user guide at https://github.com/rudecs/terraform-provider-decort/wiki
|
||||||
|
|
||||||
|
|
||||||
|
## Get Started
|
||||||
|
Two ways for starting:
|
||||||
|
1. Installing via binary packages
|
||||||
|
2. Manual installing
|
||||||
|
|
||||||
|
### Installing via binary packages
|
||||||
|
1. Download and install terraform: https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/aws-get-started
|
||||||
|
2. Create a file `main.tf` and add to it next section.
|
||||||
|
```terraform
|
||||||
|
provider "decort" {
|
||||||
|
authenticator = "oauth2"
|
||||||
|
#controller_url = <DECORT_CONTROLLER_URL>
|
||||||
|
controller_url = "https://ds1.digitalenergy.online"
|
||||||
|
#oauth2_url = <DECORT_SSO_URL>
|
||||||
|
oauth2_url = "https://sso.digitalenergy.online"
|
||||||
|
allow_unverified_ssl = true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
3. Execute next command
|
||||||
|
```
|
||||||
|
terraform init
|
||||||
|
```
|
||||||
|
The Provider will automatically install on your computer from the terrafrom registry.
|
||||||
|
|
||||||
|
### Manual installing
|
||||||
|
1. Download and install Go Programming Language: https://go.dev/dl/
|
||||||
|
2. Download and install terraform: https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/aws-get-started
|
||||||
|
3. Clone provider's repo:
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/rudecs/terraform-provider-decort.git
|
||||||
|
```
|
||||||
|
4. Change directory to clone provider's and execute next command
|
||||||
|
```bash
|
||||||
|
go build -o terraform-provider-decort
|
||||||
|
```
|
||||||
|
If you have experience with _makefile_, you can change `Makefile`'s paramters and execute next command
|
||||||
|
```bash
|
||||||
|
make build
|
||||||
|
```
|
||||||
|
5. Now move compilled file to:
|
||||||
|
Linux:
|
||||||
|
```bash
|
||||||
|
~/.terraform.d/plugins/${host_name}/${namespace}/${type}/${version}/${target}
|
||||||
|
```
|
||||||
|
Windows:
|
||||||
|
```powershell
|
||||||
|
%APPDATA%\terraform.d\plugins\${host_name}/${namespace}/${type}/${version}/${target}
|
||||||
|
```
|
||||||
|
NOTE: for Windows OS `%APP_DATA%` is a cataloge, where will place terraform files.
|
||||||
|
Example:
|
||||||
|
- host_name - digitalenergy.online
|
||||||
|
- namespace - decort
|
||||||
|
- type - decort
|
||||||
|
- version - 1.2
|
||||||
|
- target - windows_amd64
|
||||||
|
6. After all, create a file `main.tf`.
|
||||||
|
7. Add to the file next code section
|
||||||
|
```terraform
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
decort = {
|
||||||
|
version = "1.2"
|
||||||
|
source = "digitalenergy.online/decort/decort"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`version`- field for provider's version
|
||||||
|
Required
|
||||||
|
String
|
||||||
|
Note: Versions in code section and in a repository must be equal!
|
||||||
|
|
||||||
|
`source` - path to repository with provider's version
|
||||||
|
```bash
|
||||||
|
${host_name}/${namespace}/${type}
|
||||||
|
```
|
||||||
|
NOTE: all paramters must be equal to the repository path!
|
||||||
|
|
||||||
|
8. Execute command in your terminal
|
||||||
|
```bash
|
||||||
|
terraform init
|
||||||
|
```
|
||||||
|
|
||||||
|
9. If everything all right - you got green message in your terminal!
|
||||||
|
|
||||||
|
More details about the provider's building process: https://learn.hashicorp.com/tutorials/terraform/provider-use?in=terraform/providers
|
||||||
|
|
||||||
|
## Examples and Samples
|
||||||
|
- Examples: https://github.com/rudecs/terraform-provider-decort/wiki
|
||||||
|
- Samples: see in repository `samples`
|
||||||
|
|
||||||
|
Terraform schemas in:
|
||||||
|
- See in repository `docs`
|
||||||
|
|
||||||
|
Good work!
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
// LimitMaxVinsPerResgroup set maximum number of VINs instances per Resource Group
|
||||||
|
const LimitMaxVinsPerResgroup=4
|
||||||
|
|
||||||
|
// MaxSshKeysPerCompute sets maximum number of user:ssh_key pairs to authorize when creating new compute
|
||||||
|
const MaxSshKeysPerCompute=12
|
||||||
|
|
||||||
|
// MaxExtraDisksPerCompute sets maximum number of extra disks that can be added when creating new compute
|
||||||
|
const MaxExtraDisksPerCompute=12
|
||||||
|
|
||||||
|
// MaxNetworksPerCompute sets maximum number of vNICs per compute
|
||||||
|
const MaxNetworksPerCompute=8
|
||||||
|
|
||||||
|
// MaxCpusPerCompute sets maximum number of vCPUs per compute
|
||||||
|
const MaxCpusPerCompute=128
|
||||||
|
|
||||||
|
// MinRamPerCompute sets minimum amount of RAM per compute in MB
|
||||||
|
const MinRamPerCompute=128
|
||||||
@ -0,0 +1,408 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
// "time"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/dgrijalva/jwt-go"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
// "github.com/hashicorp/terraform-plugin-sdk/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
// enumerated constants that define authentication modes
|
||||||
|
const (
|
||||||
|
MODE_UNDEF = iota // this is the invalid mode - it should never be seen
|
||||||
|
MODE_LEGACY = iota
|
||||||
|
MODE_OAUTH2 = iota
|
||||||
|
MODE_JWT = iota
|
||||||
|
)
|
||||||
|
|
||||||
|
type ControllerCfg struct {
|
||||||
|
controller_url string // always required
|
||||||
|
auth_mode_code int // always required
|
||||||
|
auth_mode_txt string // always required, it is a text representation of auth mode
|
||||||
|
legacy_user string // required for legacy mode
|
||||||
|
legacy_password string // required for legacy mode
|
||||||
|
legacy_sid string // obtained from DECORT controller on successful login in legacy mode
|
||||||
|
jwt string // obtained from Outh2 provider on successful login in oauth2 mode, required in jwt mode
|
||||||
|
app_id string // required for oauth2 mode
|
||||||
|
app_secret string // required for oauth2 mode
|
||||||
|
oauth2_url string // always required
|
||||||
|
decort_username string // assigned to either legacy_user (legacy mode) or Oauth2 user (oauth2 mode) upon successful verification
|
||||||
|
cc_client *http.Client // assigned when all initial checks successfully passed
|
||||||
|
}
|
||||||
|
|
||||||
|
func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) {
|
||||||
|
// This function first will check that all required provider parameters for the
|
||||||
|
// selected authenticator mode are set correctly and initialize ControllerCfg structure
|
||||||
|
// based on the provided parameters.
|
||||||
|
//
|
||||||
|
// Next, it will check for validity of supplied credentials by initiating connection to the specified
|
||||||
|
// DECORT controller URL and, if succeeded, completes ControllerCfg structure with the rest of computed
|
||||||
|
// parameters (e.g. JWT, session ID and Oauth2 user name).
|
||||||
|
//
|
||||||
|
// The structure created by this function should be used with subsequent calls to decortAPICall() method,
|
||||||
|
// which is a DECORT authentication mode aware wrapper around standard HTTP requests.
|
||||||
|
|
||||||
|
ret_config := &ControllerCfg{
|
||||||
|
controller_url: d.Get("controller_url").(string),
|
||||||
|
auth_mode_code: MODE_UNDEF,
|
||||||
|
legacy_user: d.Get("user").(string),
|
||||||
|
legacy_password: d.Get("password").(string),
|
||||||
|
legacy_sid: "",
|
||||||
|
jwt: d.Get("jwt").(string),
|
||||||
|
app_id: d.Get("app_id").(string),
|
||||||
|
app_secret: d.Get("app_secret").(string),
|
||||||
|
oauth2_url: d.Get("oauth2_url").(string),
|
||||||
|
decort_username: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
allow_unverified_ssl := d.Get("allow_unverified_ssl").(bool)
|
||||||
|
|
||||||
|
if ret_config.controller_url == "" {
|
||||||
|
return nil, fmt.Errorf("Empty DECORT cloud controller URL provided.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// this should have already been done by StateFunc defined in Schema, but we want to be sure
|
||||||
|
ret_config.auth_mode_txt = strings.ToLower(d.Get("authenticator").(string))
|
||||||
|
|
||||||
|
switch ret_config.auth_mode_txt {
|
||||||
|
case "jwt":
|
||||||
|
if ret_config.jwt == "" {
|
||||||
|
return nil, fmt.Errorf("Authenticator mode 'jwt' specified but no JWT provided.")
|
||||||
|
}
|
||||||
|
ret_config.auth_mode_code = MODE_JWT
|
||||||
|
case "oauth2":
|
||||||
|
if ret_config.oauth2_url == "" {
|
||||||
|
return nil, fmt.Errorf("Authenticator mode 'oauth2' specified but no OAuth2 URL provided.")
|
||||||
|
}
|
||||||
|
if ret_config.app_id == "" {
|
||||||
|
return nil, fmt.Errorf("Authenticator mode 'oauth2' specified but no Application ID provided.")
|
||||||
|
}
|
||||||
|
if ret_config.app_secret == "" {
|
||||||
|
return nil, fmt.Errorf("Authenticator mode 'oauth2' specified but no Secret ID provided.")
|
||||||
|
}
|
||||||
|
ret_config.auth_mode_code = MODE_OAUTH2
|
||||||
|
case "legacy":
|
||||||
|
//
|
||||||
|
ret_config.legacy_user = d.Get("user").(string)
|
||||||
|
if ret_config.legacy_user == "" {
|
||||||
|
return nil, fmt.Errorf("Authenticator mode 'legacy' specified but no user provided.")
|
||||||
|
}
|
||||||
|
ret_config.legacy_password = d.Get("password").(string)
|
||||||
|
if ret_config.legacy_password == "" {
|
||||||
|
return nil, fmt.Errorf("Authenticator mode 'legacy' specified but no password provided.")
|
||||||
|
}
|
||||||
|
ret_config.auth_mode_code = MODE_LEGACY
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Unknown authenticator mode %q provided.", ret_config.auth_mode_txt)
|
||||||
|
}
|
||||||
|
|
||||||
|
if allow_unverified_ssl {
|
||||||
|
log.Warn("ControllerConfigure: allow_unverified_ssl is set - will not check certificates!")
|
||||||
|
transCfg := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} //nolint:gosec
|
||||||
|
ret_config.cc_client = &http.Client{
|
||||||
|
Transport: transCfg,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret_config.cc_client = &http.Client{}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ret_config.auth_mode_code {
|
||||||
|
case MODE_LEGACY:
|
||||||
|
ok, err := ret_config.validateLegacyUser()
|
||||||
|
if !ok {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret_config.decort_username = ret_config.legacy_user
|
||||||
|
case MODE_JWT:
|
||||||
|
//
|
||||||
|
ok, err := ret_config.validateJWT("")
|
||||||
|
if !ok {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
case MODE_OAUTH2:
|
||||||
|
// on success getOAuth2JWT will set config.jwt to the obtained JWT, so there is no
|
||||||
|
// need to set it once again here
|
||||||
|
_, err := ret_config.getOAuth2JWT()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// we are not verifying the JWT when parsing because actual verification is done on the
|
||||||
|
// OVC controller side. Here we do parsing solely to extract Oauth2 user name (claim "user")
|
||||||
|
// and JWT issuer name (claim "iss")
|
||||||
|
parser := jwt.Parser{}
|
||||||
|
token, _, err := parser.ParseUnverified(ret_config.jwt, jwt.MapClaims{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if claims, ok := token.Claims.(jwt.MapClaims); ok {
|
||||||
|
var tbuf bytes.Buffer
|
||||||
|
tbuf.WriteString(claims["username"].(string))
|
||||||
|
tbuf.WriteString("@")
|
||||||
|
tbuf.WriteString(claims["iss"].(string))
|
||||||
|
ret_config.decort_username = tbuf.String()
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("Failed to extract user and iss fields from JWT token in oauth2 mode.")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// FYI, this should never happen due to all above checks, but we want to be fool proof
|
||||||
|
return nil, fmt.Errorf("Unknown authenticator mode code %d provided.", ret_config.auth_mode_code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// All checks passed successfully, credentials corresponding to the selected authenticator mode
|
||||||
|
// obtained and validated.
|
||||||
|
return ret_config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config *ControllerCfg) getDecortUsername() string {
|
||||||
|
return config.decort_username
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config *ControllerCfg) getOAuth2JWT() (string, error) {
|
||||||
|
// Obtain JWT from the Oauth2 provider using application ID and application secret provided in config.
|
||||||
|
if config.auth_mode_code == MODE_UNDEF {
|
||||||
|
return "", fmt.Errorf("getOAuth2JWT method called for undefined authorization mode.")
|
||||||
|
}
|
||||||
|
if config.auth_mode_code != MODE_OAUTH2 {
|
||||||
|
return "", fmt.Errorf("getOAuth2JWT method called for incompatible authorization mode %q.", config.auth_mode_txt)
|
||||||
|
}
|
||||||
|
|
||||||
|
params := url.Values{}
|
||||||
|
params.Add("grant_type", "client_credentials")
|
||||||
|
params.Add("client_id", config.app_id)
|
||||||
|
params.Add("client_secret", config.app_secret)
|
||||||
|
params.Add("response_type", "id_token")
|
||||||
|
params.Add("validity", "3600")
|
||||||
|
params_str := params.Encode()
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", config.oauth2_url+"/v1/oauth/access_token", strings.NewReader(params_str))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
req.Header.Set("Content-Length", strconv.Itoa(len(params_str)))
|
||||||
|
|
||||||
|
resp, err := config.cc_client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
// fmt.Println("response Status:", resp.Status)
|
||||||
|
// fmt.Println("response Headers:", resp.Header)
|
||||||
|
// fmt.Println("response Headers:", req.URL)
|
||||||
|
return "", fmt.Errorf("getOauth2JWT: unexpected status code %d when obtaining JWT from %q for APP_ID %q, request Body %q",
|
||||||
|
resp.StatusCode, req.URL, config.app_id, params_str)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
responseData, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation successful - store JWT in the corresponding field of the ControllerCfg structure
|
||||||
|
config.jwt = strings.TrimSpace(string(responseData))
|
||||||
|
|
||||||
|
return config.jwt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config *ControllerCfg) validateJWT(jwt string) (bool, error) {
|
||||||
|
/*
|
||||||
|
Validate JWT against DECORT controller. JWT can be supplied as argument to this method. If empty string supplied as
|
||||||
|
argument, JWT will be taken from config attribute.
|
||||||
|
DECORT controller URL will always be taken from the config attribute assigned at instantiation.
|
||||||
|
Validation is accomplished by attempting API call that lists accounts for the invoking user.
|
||||||
|
*/
|
||||||
|
if jwt == "" {
|
||||||
|
if config.jwt == "" {
|
||||||
|
return false, fmt.Errorf("validateJWT method called, but no meaningful JWT provided.")
|
||||||
|
}
|
||||||
|
jwt = config.jwt
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.oauth2_url == "" {
|
||||||
|
return false, fmt.Errorf("validateJWT method called, but no OAuth2 URL provided.")
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", config.controller_url+"/restmachine/cloudapi/accounts/list", nil)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Authorization", fmt.Sprintf("bearer %s", jwt))
|
||||||
|
// req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
// req.Header.Set("Content-Length", strconv.Itoa(0))
|
||||||
|
|
||||||
|
resp, err := config.cc_client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return false, fmt.Errorf("validateJWT: unexpected status code %d when validating JWT against %q.",
|
||||||
|
resp.StatusCode, req.URL)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config *ControllerCfg) validateLegacyUser() (bool, error) {
|
||||||
|
/*
|
||||||
|
Validate legacy user by obtaining a session key, which will be used for authenticating subsequent API calls
|
||||||
|
to DECORT controller.
|
||||||
|
If successful, the session key is stored in config.legacy_sid and true is returned. If unsuccessful for any
|
||||||
|
reason, the method will return false and error.
|
||||||
|
*/
|
||||||
|
if config.auth_mode_code == MODE_UNDEF {
|
||||||
|
return false, fmt.Errorf("validateLegacyUser method called for undefined authorization mode.")
|
||||||
|
}
|
||||||
|
if config.auth_mode_code != MODE_LEGACY {
|
||||||
|
return false, fmt.Errorf("validateLegacyUser method called for incompatible authorization mode %q.", config.auth_mode_txt)
|
||||||
|
}
|
||||||
|
|
||||||
|
params := url.Values{}
|
||||||
|
params.Add("username", config.legacy_user)
|
||||||
|
params.Add("password", config.legacy_password)
|
||||||
|
params_str := params.Encode()
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", config.controller_url+"/restmachine/cloudapi/users/authenticate", strings.NewReader(params_str))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
req.Header.Set("Content-Length", strconv.Itoa(len(params_str)))
|
||||||
|
|
||||||
|
resp, err := config.cc_client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return false, fmt.Errorf("validateLegacyUser: unexpected status code %d when validating legacy user %q against %q.",
|
||||||
|
resp.StatusCode, config.legacy_user, config.controller_url)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
responseData, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation successful - keep session ID for future use
|
||||||
|
config.legacy_sid = string(responseData)
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config *ControllerCfg) decortAPICall(method string, api_name string, url_values *url.Values) (json_resp string, err error) { //nolint:unparam
|
||||||
|
// This is a convenience wrapper around standard HTTP request methods that is aware of the
|
||||||
|
// authorization mode for which the provider was initialized and compiles request accordingly.
|
||||||
|
|
||||||
|
if config.cc_client == nil {
|
||||||
|
// this should never happen if ClientConfig was properly called prior to decortAPICall
|
||||||
|
return "", fmt.Errorf("decortAPICall method called with unconfigured DECORT cloud controller HTTP client.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example: to create api_params, one would generally do the following:
|
||||||
|
//
|
||||||
|
// data := []byte(`{"machineId": "2638"}`)
|
||||||
|
// api_params := bytes.NewBuffer(data))
|
||||||
|
//
|
||||||
|
// Or:
|
||||||
|
//
|
||||||
|
// params := url.Values{}
|
||||||
|
// params.Add("machineId", "2638")
|
||||||
|
// params.Add("username", "u")
|
||||||
|
// params.Add("password", "b")
|
||||||
|
// req, _ := http.NewRequest(method, url, strings.NewReader(params.Encode()))
|
||||||
|
//
|
||||||
|
|
||||||
|
if config.auth_mode_code == MODE_UNDEF {
|
||||||
|
return "", fmt.Errorf("decortAPICall method called for unknown authorization mode.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.auth_mode_code == MODE_LEGACY {
|
||||||
|
url_values.Add("authkey", config.legacy_sid)
|
||||||
|
}
|
||||||
|
params_str := url_values.Encode()
|
||||||
|
|
||||||
|
req, err := http.NewRequest(method, config.controller_url+api_name, strings.NewReader(params_str))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
req.Header.Set("Content-Length", strconv.Itoa(len(params_str)))
|
||||||
|
req.Header.Set("Accept", "application/json")
|
||||||
|
|
||||||
|
if config.auth_mode_code == MODE_OAUTH2 || config.auth_mode_code == MODE_JWT {
|
||||||
|
req.Header.Set("Authorization", fmt.Sprintf("bearer %s", config.jwt))
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp *http.Response
|
||||||
|
var body []byte
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
resp, err = config.cc_client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err = ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
log.Debugf("decortAPICall: %s %s\n %s", method, api_name, body)
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
return string(body), nil
|
||||||
|
} else {
|
||||||
|
if resp.StatusCode == http.StatusInternalServerError {
|
||||||
|
log.Warnf("got 500, retrying %d/5", i+1)
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("decortAPICall: unexpected status code %d when calling API %q with request Body %q. Respone:\n%s",
|
||||||
|
resp.StatusCode, req.URL, params_str, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("decortAPICall: unexpected status code %d when calling API %q with request Body %q. Respone:\n%s",
|
||||||
|
resp.StatusCode, req.URL, params_str, body)
|
||||||
|
}
|
||||||
@ -0,0 +1,417 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dataSourceAccountRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
acc, err := utilityAccountCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return 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", 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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 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,
|
||||||
|
}
|
||||||
|
res = append(res, temp)
|
||||||
|
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,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"current": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"cpu": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"disksize": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"reserved": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"cpu": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"disksize": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"ckey": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"acl": {
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"company": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"companyurl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"created_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"created_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"deactivation_time": {
|
||||||
|
Type: schema.TypeFloat,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"deleted_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"deleted_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"displayname": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"resource_limits": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"send_access_emails": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"service_account": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"updated_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"vins": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"computes": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"started": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"stopped": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"machines": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"halted": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"running": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"vinses": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceAccount() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceAccountRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceAccountSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dataSourceAccountDeletedListRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
accountDeletedList, err := utilityAccountDeletedListCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", flattenAccountList(accountDeletedList))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceAccountDeletedList() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceAccountDeletedListRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceAccountListSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenAccountDisksList(adl AccountDisksList) []map[string]interface{} {
|
||||||
|
res := make([]map[string]interface{}, 0)
|
||||||
|
for _, ad := range adl {
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"disk_id": ad.ID,
|
||||||
|
"disk_name": ad.Name,
|
||||||
|
"pool": ad.Pool,
|
||||||
|
"sep_id": ad.SepId,
|
||||||
|
"size_max": ad.SizeMax,
|
||||||
|
"type": ad.Type,
|
||||||
|
}
|
||||||
|
res = append(res, temp)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceAccountDisksListRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
accountDisksList, err := utilityAccountDisksListCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", flattenAccountDisksList(accountDisksList))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceAccountDisksListSchemaMake() map[string]*schema.Schema {
|
||||||
|
res := map[string]*schema.Schema{
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "ID of the account",
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Search Result",
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"disk_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"disk_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"pool": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"size_max": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceAccountDisksList() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceAccountDisksListRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceAccountDisksListSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,306 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenAccountList(al AccountCloudApiList) []map[string]interface{} {
|
||||||
|
res := make([]map[string]interface{}, 0)
|
||||||
|
for _, acc := range al {
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"acl": flattenRgAcl(acc.Acl),
|
||||||
|
"created_time": acc.CreatedTime,
|
||||||
|
"deleted_time": acc.DeletedTime,
|
||||||
|
"account_id": acc.ID,
|
||||||
|
"account_name": acc.Name,
|
||||||
|
"status": acc.Status,
|
||||||
|
"updated_time": acc.UpdatedTime,
|
||||||
|
}
|
||||||
|
res = append(res, temp)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/*uncomment for cloudbroker
|
||||||
|
func flattenAccountList(al AccountList) []map[string]interface{} {
|
||||||
|
res := make([]map[string]interface{}, 0)
|
||||||
|
for _, acc := range al {
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"dc_location": acc.DCLocation,
|
||||||
|
"ckey": acc.CKey,
|
||||||
|
"meta": flattenMeta(acc.Meta),
|
||||||
|
|
||||||
|
"acl": flattenRgAcl(acc.Acl),
|
||||||
|
|
||||||
|
"company": acc.Company,
|
||||||
|
"companyurl": acc.CompanyUrl,
|
||||||
|
"created_by": acc.CreatedBy,
|
||||||
|
|
||||||
|
"created_time": acc.CreatedTime,
|
||||||
|
|
||||||
|
"deactivation_time": acc.DeactiovationTime,
|
||||||
|
"deleted_by": acc.DeletedBy,
|
||||||
|
|
||||||
|
"deleted_time": acc.DeletedTime,
|
||||||
|
|
||||||
|
"displayname": acc.DisplayName,
|
||||||
|
"guid": acc.GUID,
|
||||||
|
|
||||||
|
"account_id": acc.ID,
|
||||||
|
"account_name": acc.Name,
|
||||||
|
|
||||||
|
"resource_limits": flattenRgResourceLimits(acc.ResourceLimits),
|
||||||
|
"send_access_emails": acc.SendAccessEmails,
|
||||||
|
"service_account": acc.ServiceAccount,
|
||||||
|
|
||||||
|
"status": acc.Status,
|
||||||
|
"updated_time": acc.UpdatedTime,
|
||||||
|
|
||||||
|
"version": acc.Version,
|
||||||
|
"vins": acc.Vins,
|
||||||
|
|
||||||
|
}
|
||||||
|
res = append(res, temp)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func dataSourceAccountListRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
accountList, err := utilityAccountListCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", flattenAccountList(accountList))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceAccountListSchemaMake() map[string]*schema.Schema {
|
||||||
|
res := map[string]*schema.Schema{
|
||||||
|
"page": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Page number",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Page size",
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
/*uncomment for cloudbroker
|
||||||
|
"dc_location": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"ckey": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},*/
|
||||||
|
"acl": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/*uncomment for cloudbroker
|
||||||
|
"company": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"companyurl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"created_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
"created_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
/*uncomment for cloudbroker
|
||||||
|
"deactivation_time": {
|
||||||
|
Type: schema.TypeFloat,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"deleted_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
"deleted_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
/*uncomment for cloudbroker
|
||||||
|
"displayname": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
/*uncomment for cloudbroker
|
||||||
|
"resource_limits": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"send_access_emails": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"service_account": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"updated_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
/*uncomment for cloudbroker
|
||||||
|
"version": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"vins": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceAccountList() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceAccountListRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceAccountListSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dataSourceBasicServiceDeletedListRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
basicServiceDeletedList, err := utilityBasicServiceDeletedListCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", flattenBasicServiceList(basicServiceDeletedList))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceBasicServiceDeletedList() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceBasicServiceDeletedListRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceBasicServiceListSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,372 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
// "net/url"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
// "github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parse list of all disks from API compute/get into a list of "extra disks" attached to this compute
|
||||||
|
// Extra disks are all compute disks but a boot disk.
|
||||||
|
func parseComputeDisksToExtraDisks(disks []DiskRecord) []interface{} {
|
||||||
|
// this return value will be used to d.Set("extra_disks",) item of dataSourceCompute schema,
|
||||||
|
// which is a simple list of integer disk IDs excluding boot disk ID
|
||||||
|
length := len(disks)
|
||||||
|
log.Debugf("parseComputeDisksToExtraDisks: called for %d disks", length)
|
||||||
|
|
||||||
|
if length == 0 || (length == 1 && disks[0].Type == "B") {
|
||||||
|
// the disk list is empty (which is kind of strange - diskless compute?), or
|
||||||
|
// there is only one disk in the list and it is a boot disk;
|
||||||
|
// as we skip boot disks, the result will be of 0 length anyway
|
||||||
|
return make([]interface{}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]interface{}, length-1)
|
||||||
|
idx := 0
|
||||||
|
for _, value := range disks {
|
||||||
|
if value.Type == "B" {
|
||||||
|
// skip boot disk when iterating over the list of disks
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result[idx] = value.ID
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseBootDiskSize(disks []DiskRecord) int {
|
||||||
|
// this return value will be used to d.Set("boot_disk_size",) item of dataSourceCompute schema
|
||||||
|
if len(disks) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, value := range disks {
|
||||||
|
if value.Type == "B" {
|
||||||
|
return value.SizeMax
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseBootDiskId(disks []DiskRecord) uint {
|
||||||
|
// this return value will be used to d.Set("boot_disk_id",) item of dataSourceCompute schema
|
||||||
|
if len(disks) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, value := range disks {
|
||||||
|
if value.Type == "B" {
|
||||||
|
return value.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func findBootDisk(disks []DiskRecord) (*DiskRecord, error) {
|
||||||
|
for _, d := range disks {
|
||||||
|
if d.Type == "B" {
|
||||||
|
return &d, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("boot disk not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the list of interfaces from compute/get response into a list of networks
|
||||||
|
// attached to this compute
|
||||||
|
func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord) []interface{} {
|
||||||
|
// return value will be used to d.Set("network") item of dataSourceCompute schema
|
||||||
|
length := len(ifaces)
|
||||||
|
log.Debugf("parseComputeInterfacesToNetworks: called for %d ifaces", length)
|
||||||
|
|
||||||
|
result := []interface{}{}
|
||||||
|
|
||||||
|
for _, value := range ifaces {
|
||||||
|
elem := make(map[string]interface{})
|
||||||
|
// Keys in this map should correspond to the Schema definition
|
||||||
|
// as returned by networkSubresourceSchemaMake()
|
||||||
|
elem["net_id"] = value.NetID
|
||||||
|
elem["net_type"] = value.NetType
|
||||||
|
elem["ip_address"] = value.IPAddress
|
||||||
|
elem["mac"] = value.MAC
|
||||||
|
|
||||||
|
// log.Debugf(" element %d: net_id=%d, net_type=%s", i, value.NetID, value.NetType)
|
||||||
|
|
||||||
|
result = append(result, elem)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenCompute(d *schema.ResourceData, compFacts string) error {
|
||||||
|
// This function expects that compFacts string contains response from API compute/get,
|
||||||
|
// i.e. detailed information about compute instance.
|
||||||
|
//
|
||||||
|
// NOTE: this function modifies ResourceData argument - as such it should never be called
|
||||||
|
// from resourceComputeExists(...) method
|
||||||
|
model := ComputeGetResp{}
|
||||||
|
log.Debugf("flattenCompute: ready to unmarshal string %s", compFacts)
|
||||||
|
err := json.Unmarshal([]byte(compFacts), &model)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("flattenCompute: ID %d, RG ID %d", model.ID, model.RgID)
|
||||||
|
|
||||||
|
d.SetId(fmt.Sprintf("%d", model.ID))
|
||||||
|
// d.Set("compute_id", model.ID) - we should NOT set compute_id in the schema here: if it was set - it is already set, if it wasn't - we shouldn't
|
||||||
|
d.Set("name", model.Name)
|
||||||
|
d.Set("rg_id", model.RgID)
|
||||||
|
d.Set("rg_name", model.RgName)
|
||||||
|
d.Set("account_id", model.AccountID)
|
||||||
|
d.Set("account_name", model.AccountName)
|
||||||
|
d.Set("driver", model.Driver)
|
||||||
|
d.Set("cpu", model.Cpu)
|
||||||
|
d.Set("ram", model.Ram)
|
||||||
|
// d.Set("boot_disk_size", model.BootDiskSize) - bootdiskSize key in API compute/get is always zero, so we set boot_disk_size in another way
|
||||||
|
d.Set("image_id", model.ImageID)
|
||||||
|
d.Set("description", model.Desc)
|
||||||
|
d.Set("cloud_init", "applied") // NOTE: for existing compute we hard-code this value as an indicator for DiffSuppress fucntion
|
||||||
|
// d.Set("status", model.Status)
|
||||||
|
// d.Set("tech_status", model.TechStatus)
|
||||||
|
|
||||||
|
if model.TechStatus == "STARTED" {
|
||||||
|
d.Set("started", true)
|
||||||
|
} else {
|
||||||
|
d.Set("started", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
bootDisk, err := findBootDisk(model.Disks)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("boot_disk_size", bootDisk.SizeMax)
|
||||||
|
d.Set("boot_disk_id", bootDisk.ID) // we may need boot disk ID in resize operations
|
||||||
|
d.Set("sep_id", bootDisk.SepID)
|
||||||
|
d.Set("pool", bootDisk.Pool)
|
||||||
|
|
||||||
|
if len(model.Disks) > 0 {
|
||||||
|
log.Debugf("flattenCompute: calling parseComputeDisksToExtraDisks for %d disks", len(model.Disks))
|
||||||
|
if err = d.Set("extra_disks", parseComputeDisksToExtraDisks(model.Disks)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(model.Interfaces) > 0 {
|
||||||
|
log.Debugf("flattenCompute: calling parseComputeInterfacesToNetworks for %d interfaces", len(model.Interfaces))
|
||||||
|
if err = d.Set("network", parseComputeInterfacesToNetworks(model.Interfaces)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(model.OsUsers) > 0 {
|
||||||
|
log.Debugf("flattenCompute: calling parseOsUsers for %d logins", len(model.OsUsers))
|
||||||
|
if err = d.Set("os_users", parseOsUsers(model.OsUsers)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceComputeRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
compFacts, err := utilityComputeCheckPresence(d, m)
|
||||||
|
if compFacts == "" {
|
||||||
|
// if empty string is returned from utilityComputeCheckPresence then there is no
|
||||||
|
// such Compute and err tells so - just return it to the calling party
|
||||||
|
d.SetId("") // ensure ID is empty
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return flattenCompute(d, compFacts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceCompute() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceComputeRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Name of this compute instance. NOTE: this parameter is case sensitive.",
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: consider removing compute_id from the schema, as it not practical to call this data provider if
|
||||||
|
// corresponding compute ID is already known
|
||||||
|
"compute_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "ID of the compute instance. If ID is specified, name and resource group ID are ignored.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"rg_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "ID of the resource group where this compute instance is located.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"rg_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Name of the resource group where this compute instance is located.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "ID of the account this compute instance belongs to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Name of the account this compute instance belongs to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"driver": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Hardware architecture of this compute instance.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"cpu": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Number of CPUs allocated for this compute instance.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ram": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Amount of RAM in MB allocated for this compute instance.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "ID of the OS image this compute instance is based on.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"image_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Name of the OS image this compute instance is based on.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"boot_disk_size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "This compute instance boot disk size in GB.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"boot_disk_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "This compute instance boot disk ID.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"extra_disks": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: MaxExtraDisksPerCompute,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
Description: "IDs of the extra disk(s) attached to this compute.",
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
"disks": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: dataSourceDiskSchemaMake(), // ID, type, name, size, account ID, SEP ID, SEP type, pool, status, tech status, compute ID, image ID
|
||||||
|
},
|
||||||
|
Description: "Detailed specification for all disks attached to this compute instance (including bood disk).",
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
|
"network": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
MaxItems: MaxNetworksPerCompute,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: networkSubresourceSchemaMake(),
|
||||||
|
},
|
||||||
|
Description: "Network connection(s) for this compute.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"os_users": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: osUsersSubresourceSchemaMake(),
|
||||||
|
},
|
||||||
|
Description: "Guest OS users provisioned on this compute instance.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"description": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "User-defined text description of this compute instance.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"cloud_init": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Placeholder for cloud_init parameters.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"started": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: true,
|
||||||
|
Description: "Is compute started.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
// "net/url"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
// "github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenDisk(d *schema.ResourceData, disk_facts string) error {
|
||||||
|
// This function expects disk_facts string to contain a response from disks/get API
|
||||||
|
//
|
||||||
|
// NOTE: this function modifies ResourceData argument - as such it should never be called
|
||||||
|
// from resourceDiskExists(...) method. Use utilityDiskCheckPresence instead.
|
||||||
|
|
||||||
|
log.Debugf("flattenDisk: ready to unmarshal string %s", disk_facts)
|
||||||
|
|
||||||
|
model := DiskRecord{}
|
||||||
|
|
||||||
|
err := json.Unmarshal([]byte(disk_facts), &model)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("flattenDisk: disk ID %d, disk AccountID %d", model.ID, model.AccountID)
|
||||||
|
|
||||||
|
d.SetId(fmt.Sprintf("%d", model.ID))
|
||||||
|
// d.Set("disk_id", model.ID) - we should NOT update disk_id in the schema. If it was set - it is already set, if it wasn't - we shouldn't
|
||||||
|
d.Set("name", model.Name)
|
||||||
|
d.Set("account_id", model.AccountID)
|
||||||
|
d.Set("account_name", model.AccountName)
|
||||||
|
d.Set("size", model.SizeMax)
|
||||||
|
// d.Set("sizeUsed", model.SizeUsed)
|
||||||
|
d.Set("type", model.Type)
|
||||||
|
d.Set("image_id", model.ImageID)
|
||||||
|
d.Set("sep_id", model.SepID)
|
||||||
|
d.Set("sep_type", model.SepType)
|
||||||
|
d.Set("pool", model.Pool)
|
||||||
|
// d.Set("compute_id", model.ComputeID)
|
||||||
|
|
||||||
|
d.Set("description", model.Desc)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceDiskRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
disk_facts, err := utilityDiskCheckPresence(d, m)
|
||||||
|
if disk_facts == "" {
|
||||||
|
// if empty string is returned from utilityDiskCheckPresence then there is no
|
||||||
|
// such Disk and err tells so - just return it to the calling party
|
||||||
|
d.SetId("") // ensure ID is empty
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return flattenDisk(d, disk_facts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceDiskSchemaMake() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Name of this disk. NOTE: disk names are NOT unique within an account. If disk ID is specified, disk name is ignored.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"disk_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "ID of the disk to get. If disk ID is specified, then disk name and account ID are ignored.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "ID of the account this disk belongs to. If disk ID is specified, then account ID is ignored.",
|
||||||
|
},
|
||||||
|
|
||||||
|
// The rest of the data source Disk schema are all computed
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Storage end-point provider serving this disk.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"pool": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Pool where this disk is located.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Size of the disk in GB.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Type of this disk. E.g. D for data disks, B for boot.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"description": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "User-defined text description of this disk.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Name of the account this disk belongs to. If account ID is specified, account name is ignored.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "ID of the image, which this disk was cloned from (valid for disk clones only).",
|
||||||
|
},
|
||||||
|
|
||||||
|
"sep_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Type of the storage end-point provider serving this disk.",
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
"snapshots": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource {
|
||||||
|
Schema: snapshotSubresourceSchemaMake(),
|
||||||
|
},
|
||||||
|
Description: "List of user-created snapshots for this disk."
|
||||||
|
},
|
||||||
|
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Current model status of this disk.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Current technical status of this disk.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"compute_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "ID of the compute instance where this disk is attached to, or 0 for unattached disk.",
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceDisk() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceDiskRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceDiskSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,391 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenDiskList(dl DisksListResp) []map[string]interface{} {
|
||||||
|
res := make([]map[string]interface{}, 0)
|
||||||
|
for _, disk := range dl {
|
||||||
|
diskAcl, _ := json.Marshal(disk.Acl)
|
||||||
|
diskIotune, _ := json.Marshal(disk.IOTune)
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"account_id": disk.AccountID,
|
||||||
|
"account_name": disk.AccountName,
|
||||||
|
"acl": string(diskAcl),
|
||||||
|
"boot_partition": disk.BootPartition,
|
||||||
|
"compute_id": disk.ComputeID,
|
||||||
|
"compute_name": disk.ComputeName,
|
||||||
|
"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": string(diskIotune),
|
||||||
|
"iqn": disk.IQN,
|
||||||
|
"login": disk.Login,
|
||||||
|
"machine_id": disk.MachineId,
|
||||||
|
"machine_name": disk.MachineName,
|
||||||
|
"milestones": disk.Milestones,
|
||||||
|
"name": disk.Name,
|
||||||
|
"order": disk.Order,
|
||||||
|
"params": disk.Params,
|
||||||
|
"parent_id": disk.ParentId,
|
||||||
|
"passwd": disk.Passwd,
|
||||||
|
"pci_slot": disk.PciSlot,
|
||||||
|
"pool": disk.Pool,
|
||||||
|
"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,
|
||||||
|
"size_max": disk.SizeMax,
|
||||||
|
"size_used": disk.SizeUsed,
|
||||||
|
"snapshots": flattendDiskSnapshotList(disk.Snapshots),
|
||||||
|
"status": disk.Status,
|
||||||
|
"tech_status": disk.TechStatus,
|
||||||
|
"type": disk.Type,
|
||||||
|
"vmid": disk.VMID,
|
||||||
|
"update_by": disk.UpdateBy,
|
||||||
|
}
|
||||||
|
res = append(res, temp)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattendDiskSnapshotList(sl SnapshotRecordList) []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(d *schema.ResourceData, m interface{}) error {
|
||||||
|
diskList, err := utilityDiskListCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", flattenDiskList(diskList))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceDiskListSchemaMake() map[string]*schema.Schema {
|
||||||
|
res := map[string]*schema.Schema{
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "ID of the account the disks belong to",
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "type of the disks",
|
||||||
|
},
|
||||||
|
"page": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Page number",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Page size",
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"acl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"boot_partition": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"compute_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"compute_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"created_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"deleted_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"destruction_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"devicename": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"disk_path": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"disk_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"images": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"iotune": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"iqn": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"login": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"machine_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"machine_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"order": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"parent_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"passwd": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"pci_slot": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"pool": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"purge_attempts": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"purge_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reality_device_number": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reference_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"sep_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"size_max": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"size_used": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"snapshots": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"snap_set_guid": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"snap_set_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"vmid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"update_by": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceDiskList() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceDiskListRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceDiskListSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenExtnetList(el ExtnetList) []map[string]interface{} {
|
||||||
|
res := make([]map[string]interface{}, 0)
|
||||||
|
for _, e := range el {
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"net_id": e.ID,
|
||||||
|
"ipcidr": e.IPCidr,
|
||||||
|
"name": e.Name,
|
||||||
|
}
|
||||||
|
res = append(res, temp)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceExtnetListRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
extnetList, err := utilityExtnetListCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", flattenExtnetList(extnetList))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceExtnetListSchemaMake() map[string]*schema.Schema {
|
||||||
|
res := map[string]*schema.Schema{
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "filter by account ID",
|
||||||
|
},
|
||||||
|
"page": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Page number",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Page size",
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"net_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"ipcidr": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceExtnetList() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceExtnetListRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceExtnetListSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenGrid(d *schema.ResourceData, grid *Grid) {
|
||||||
|
d.Set("name", grid.Name)
|
||||||
|
d.Set("flag", grid.Flag)
|
||||||
|
d.Set("gid", grid.Gid)
|
||||||
|
d.Set("guid", grid.Guid)
|
||||||
|
d.Set("location_code", grid.LocationCode)
|
||||||
|
d.Set("id", grid.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceGridRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
grid, err := utilityGridCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId(strconv.Itoa(grid.Id))
|
||||||
|
flattenGrid(d, grid)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceGetGridSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"grid_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"flag": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"location_code": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceGrid() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceGridRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceGetGridSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenGridList(gl GridList) []map[string]interface{} {
|
||||||
|
res := make([]map[string]interface{}, 0)
|
||||||
|
for _, item := range gl {
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"name": item.Name,
|
||||||
|
"flag": item.Flag,
|
||||||
|
"gid": item.Gid,
|
||||||
|
"guid": item.Guid,
|
||||||
|
"location_code": item.LocationCode,
|
||||||
|
"id": item.Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
res = append(res, temp)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceGridListRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
gridList, err := utilityGridListCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", flattenGridList(gridList))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceGridListSchemaMake() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"page": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "page number",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "page size",
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Description: "grid list",
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: dataSourceGridSchemaMake(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceGridSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"flag": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"location_code": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceGridList() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceGridListRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceGridListSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,311 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenImage(d *schema.ResourceData, image *Image) {
|
||||||
|
d.Set("name", image.Name)
|
||||||
|
d.Set("drivers", image.Drivers)
|
||||||
|
d.Set("url", image.Url)
|
||||||
|
d.Set("gid", image.Gid)
|
||||||
|
d.Set("image_id", image.ImageId)
|
||||||
|
d.Set("boot_type", image.Boottype)
|
||||||
|
d.Set("image_type", image.Imagetype)
|
||||||
|
d.Set("bootable", image.Bootable)
|
||||||
|
d.Set("sep_id", image.SepId)
|
||||||
|
d.Set("unc_path", image.UNCPath)
|
||||||
|
d.Set("link_to", image.LinkTo)
|
||||||
|
d.Set("status", image.Status)
|
||||||
|
d.Set("tech_status", image.TechStatus)
|
||||||
|
d.Set("version", image.Version)
|
||||||
|
d.Set("size", image.Size)
|
||||||
|
d.Set("enabled", image.Enabled)
|
||||||
|
d.Set("computeci_id", image.ComputeciId)
|
||||||
|
d.Set("pool_name", image.PoolName)
|
||||||
|
d.Set("username", image.Username)
|
||||||
|
d.Set("username_dl", image.UsernameDL)
|
||||||
|
d.Set("password", image.Password)
|
||||||
|
d.Set("password_dl", image.PasswordDL)
|
||||||
|
d.Set("account_id", image.AccountId)
|
||||||
|
d.Set("guid", image.Guid)
|
||||||
|
d.Set("milestones", image.Milestones)
|
||||||
|
d.Set("provider_name", image.ProviderName)
|
||||||
|
d.Set("purge_attempts", image.PurgeAttempts)
|
||||||
|
d.Set("reference_id", image.ReferenceId)
|
||||||
|
d.Set("res_id", image.ResId)
|
||||||
|
d.Set("res_name", image.ResName)
|
||||||
|
d.Set("rescuecd", image.Rescuecd)
|
||||||
|
d.Set("architecture", image.Architecture)
|
||||||
|
d.Set("hot_resize", image.Hotresize)
|
||||||
|
d.Set("history", flattenHistory(image.History))
|
||||||
|
d.Set("last_modified", image.LastModified)
|
||||||
|
d.Set("meta", flattenMeta(image.Meta))
|
||||||
|
d.Set("desc", image.Desc)
|
||||||
|
d.Set("shared_with", image.SharedWith)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId(strconv.Itoa(image.Guid))
|
||||||
|
flattenImage(d, image)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Name of the rescue disk",
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "URL where to download media from",
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "grid (platform) ID where this template should be create in",
|
||||||
|
},
|
||||||
|
"boot_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Boot type of image bios or uefi",
|
||||||
|
},
|
||||||
|
"image_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Image type linux, windows or other",
|
||||||
|
},
|
||||||
|
"shared_with": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"drivers": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "List of types of compute suitable for image. Example: [ \"KVM_X86\" ]",
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "meta",
|
||||||
|
},
|
||||||
|
"hot_resize": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this machine supports hot resize",
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional username for the image",
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional password for the image",
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "AccountId to make the image exclusive",
|
||||||
|
},
|
||||||
|
"username_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "username for upload binary media",
|
||||||
|
},
|
||||||
|
"password_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "password for upload binary media",
|
||||||
|
},
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "storage endpoint provider ID",
|
||||||
|
},
|
||||||
|
"pool_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "pool for image create",
|
||||||
|
},
|
||||||
|
"architecture": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "binary architecture of this image, one of X86_64 of PPC64_LE",
|
||||||
|
},
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "image id",
|
||||||
|
},
|
||||||
|
"permanently": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Whether to completely delete the image",
|
||||||
|
},
|
||||||
|
"bootable": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this image boot OS",
|
||||||
|
},
|
||||||
|
"unc_path": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "unc path",
|
||||||
|
},
|
||||||
|
"link_to": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "",
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "status",
|
||||||
|
},
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "tech atatus",
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "version",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image size",
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"computeci_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"provider_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"purge_attempts": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reference_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rescuecd": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"last_modified": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImage() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceImageRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceImageSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenImageList(il ImageList) []map[string]interface{} {
|
||||||
|
res := make([]map[string]interface{}, 0)
|
||||||
|
for _, item := range il {
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"name": item.Name,
|
||||||
|
"url": item.Url,
|
||||||
|
"gid": item.Gid,
|
||||||
|
"guid": item.Guid,
|
||||||
|
"drivers": item.Drivers,
|
||||||
|
"image_id": item.ImageId,
|
||||||
|
"boot_type": item.Boottype,
|
||||||
|
"bootable": item.Bootable,
|
||||||
|
"image_type": item.Imagetype,
|
||||||
|
"status": item.Status,
|
||||||
|
"tech_status": item.TechStatus,
|
||||||
|
"version": item.Version,
|
||||||
|
"username": item.Username,
|
||||||
|
"username_dl": item.UsernameDL,
|
||||||
|
"password": item.Password,
|
||||||
|
"password_dl": item.PasswordDL,
|
||||||
|
"purge_attempts": item.PurgeAttempts,
|
||||||
|
"architecture": item.Architecture,
|
||||||
|
"account_id": item.AccountId,
|
||||||
|
"computeci_id": item.ComputeciId,
|
||||||
|
"enabled": item.Enabled,
|
||||||
|
"reference_id": item.ReferenceId,
|
||||||
|
"res_id": item.ResId,
|
||||||
|
"res_name": item.ResName,
|
||||||
|
"rescuecd": item.Rescuecd,
|
||||||
|
"provider_name": item.ProviderName,
|
||||||
|
"milestones": item.Milestones,
|
||||||
|
"size": item.Size,
|
||||||
|
"sep_id": item.SepId,
|
||||||
|
"link_to": item.LinkTo,
|
||||||
|
"unc_path": item.UNCPath,
|
||||||
|
"pool_name": item.PoolName,
|
||||||
|
"hot_resize": item.Hotresize,
|
||||||
|
"history": flattenHistory(item.History),
|
||||||
|
"last_modified": item.LastModified,
|
||||||
|
"meta": flattenMeta(item.Meta),
|
||||||
|
"desc": item.Desc,
|
||||||
|
"shared_with": item.SharedWith,
|
||||||
|
}
|
||||||
|
res = append(res, temp)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageListRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
imageList, err := utilityImageListCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", flattenImageList(imageList))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageListSchemaMake() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "filter images by storage endpoint provider ID",
|
||||||
|
},
|
||||||
|
"shared_with": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "filter images by account ID availability",
|
||||||
|
},
|
||||||
|
"page": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "page number",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "page size",
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image list",
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: dataSourceImageSchemaMake(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageList() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceImageListRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceImageListSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenImageListStacks(_ *schema.ResourceData, stack ImageListStacks) []map[string]interface{} {
|
||||||
|
temp := make([]map[string]interface{}, 0)
|
||||||
|
for _, item := range stack {
|
||||||
|
t := map[string]interface{}{
|
||||||
|
"api_url": item.ApiURL,
|
||||||
|
"api_key": item.ApiKey,
|
||||||
|
"app_id": item.AppId,
|
||||||
|
"desc": item.Desc,
|
||||||
|
"drivers": item.Drivers,
|
||||||
|
"error": item.Error,
|
||||||
|
"guid": item.Guid,
|
||||||
|
"id": item.Id,
|
||||||
|
"images": item.Images,
|
||||||
|
"login": item.Login,
|
||||||
|
"name": item.Name,
|
||||||
|
"passwd": item.Passwd,
|
||||||
|
"reference_id": item.ReferenceId,
|
||||||
|
"status": item.Status,
|
||||||
|
"type": item.Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = append(temp, t)
|
||||||
|
}
|
||||||
|
return temp
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageListStacksRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
imageListStacks, err := utilityImageListStacksCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", flattenImageListStacks(d, imageListStacks))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageListStackSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"api_url": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"api_key": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"app_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"drivers": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"images": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"login": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"passwd": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reference_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageListStacksSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "image id",
|
||||||
|
},
|
||||||
|
"page": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "page number",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "page size",
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: dataSourceImageListStackSchemaMake(),
|
||||||
|
},
|
||||||
|
Description: "items of stacks list",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceImageListStacks() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceImageListStacksRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceImageListStacksSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dataSourcePcideviceRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
pcidevice, err := utilityPcideviceCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("ckey", pcidevice.CKey)
|
||||||
|
d.Set("meta", flattenMeta(pcidevice.Meta))
|
||||||
|
d.Set("compute_id", pcidevice.Computeid)
|
||||||
|
d.Set("description", pcidevice.Description)
|
||||||
|
d.Set("guid", pcidevice.Guid)
|
||||||
|
d.Set("hw_path", pcidevice.HwPath)
|
||||||
|
d.Set("rg_id", pcidevice.RgID)
|
||||||
|
d.Set("name", pcidevice.Name)
|
||||||
|
d.Set("stack_id", pcidevice.StackID)
|
||||||
|
d.Set("status", pcidevice.Status)
|
||||||
|
d.Set("system_name", pcidevice.SystemName)
|
||||||
|
|
||||||
|
d.SetId(strconv.Itoa(d.Get("device_id").(int)))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourcePcideviceSchemaMake() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"device_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"ckey": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"compute_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"hw_path": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rg_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"stack_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"system_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourcePcidevice() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourcePcideviceRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourcePcideviceSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenPcideviceList(pl PcideviceList) []map[string]interface{} {
|
||||||
|
res := make([]map[string]interface{}, 0)
|
||||||
|
for _, item := range pl {
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"ckey": item.CKey,
|
||||||
|
"meta": flattenMeta(item.Meta),
|
||||||
|
"compute_id": item.Computeid,
|
||||||
|
"description": item.Description,
|
||||||
|
"guid": item.Guid,
|
||||||
|
"hw_path": item.HwPath,
|
||||||
|
"device_id": item.ID,
|
||||||
|
"rg_id": item.RgID,
|
||||||
|
"name": item.Name,
|
||||||
|
"stack_id": item.StackID,
|
||||||
|
"status": item.Status,
|
||||||
|
"system_name": item.SystemName,
|
||||||
|
}
|
||||||
|
res = append(res, temp)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourcePcideviceListRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
pcideviceList, err := utilityPcideviceListCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("items", flattenPcideviceList(pcideviceList))
|
||||||
|
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourcePcideviceItem() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"ckey": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"compute_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"hw_path": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"device_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rg_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"stack_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"system_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourcePcideviceListSchemaMake() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"items": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Description: "pcidevice list",
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: dataSourcePcideviceItem(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourcePcideviceList() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourcePcideviceListRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourcePcideviceListSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
// "net/url"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
// "github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenResgroup(d *schema.ResourceData, rg_facts string) error {
|
||||||
|
// NOTE: this function modifies ResourceData argument - as such it should never be called
|
||||||
|
// from resourceRsgroupExists(...) method
|
||||||
|
// log.Debugf("%s", rg_facts)
|
||||||
|
log.Debugf("flattenResgroup: ready to decode response body from API")
|
||||||
|
details := ResgroupGetResp{}
|
||||||
|
err := json.Unmarshal([]byte(rg_facts), &details)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("flattenResgroup: decoded RG name %q / ID %d, account ID %d",
|
||||||
|
details.Name, details.ID, details.AccountID)
|
||||||
|
|
||||||
|
d.SetId(fmt.Sprintf("%d", details.ID))
|
||||||
|
d.Set("rg_id", details.ID)
|
||||||
|
d.Set("name", details.Name)
|
||||||
|
d.Set("account_name", details.AccountName)
|
||||||
|
d.Set("account_id", details.AccountID)
|
||||||
|
// d.Set("grid_id", details.GridID)
|
||||||
|
d.Set("description", details.Desc)
|
||||||
|
d.Set("status", details.Status)
|
||||||
|
d.Set("def_net_type", details.DefaultNetType)
|
||||||
|
d.Set("def_net_id", details.DefaultNetID)
|
||||||
|
/*
|
||||||
|
d.Set("vins", details.Vins)
|
||||||
|
d.Set("computes", details.Computes)
|
||||||
|
*/
|
||||||
|
|
||||||
|
log.Debugf("flattenResgroup: calling flattenQuota()")
|
||||||
|
if err = d.Set("quota", parseQuota(details.Quota)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceResgroupRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
rg_facts, err := utilityResgroupCheckPresence(d, m)
|
||||||
|
if rg_facts == "" {
|
||||||
|
// if empty string is returned from utilityResgroupCheckPresence then there is no
|
||||||
|
// such resource group and err tells so - just return it to the calling party
|
||||||
|
d.SetId("") // ensure ID is empty in this case
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return flattenResgroup(d, rg_facts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceResgroup() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceResgroupRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Name of the resource group. Names are case sensitive and unique within the context of an account.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"rg_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Unique ID of the resource group. If this ID is specified, then resource group name is ignored.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Name of the account, which this resource group belongs to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "Unique ID of the account, which this resource group belongs to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"description": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "User-defined text description of this resource group.",
|
||||||
|
},
|
||||||
|
|
||||||
|
/* commented out, as in this version of provider we use default Grid ID
|
||||||
|
"grid_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Unique ID of the grid, where this resource group is deployed.",
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
|
"quota": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: quotaRgSubresourceSchemaMake(), // this is a dictionary
|
||||||
|
},
|
||||||
|
Description: "Quota settings for this resource group.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"def_net_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Type of the default network for this resource group.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"def_net_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "ID of the default network for this resource group (if any).",
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Current status of this resource group.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"vins": {
|
||||||
|
Type: schema.TypeList, // this is a list of ints
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: LimitMaxVinsPerResgroup,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
Description: "List of VINs deployed in this resource group.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"computes": {
|
||||||
|
Type: schema.TypeList, //t his is a list of ints
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
Description: "List of computes deployed in this resource group.",
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,314 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenRgList(rgl ResgroupListResp) []map[string]interface{} {
|
||||||
|
res := make([]map[string]interface{}, 0)
|
||||||
|
for _, rg := range rgl {
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"account_id": rg.AccountID,
|
||||||
|
"account_name": rg.AccountName,
|
||||||
|
"acl": flattenRgAcl(rg.ACLs),
|
||||||
|
"created_by": rg.CreatedBy,
|
||||||
|
"created_time": rg.CreatedTime,
|
||||||
|
"def_net_id": rg.DefaultNetID,
|
||||||
|
"def_net_type": rg.DefaultNetType,
|
||||||
|
"deleted_by": rg.DeletedBy,
|
||||||
|
"deleted_time": rg.DeletedTime,
|
||||||
|
"desc": rg.Decsription,
|
||||||
|
"gid": rg.GridID,
|
||||||
|
"guid": rg.GUID,
|
||||||
|
"rg_id": rg.ID,
|
||||||
|
"lock_status": rg.LockStatus,
|
||||||
|
"milestones": rg.Milestones,
|
||||||
|
"name": rg.Name,
|
||||||
|
"register_computes": rg.RegisterComputes,
|
||||||
|
"resource_limits": flattenRgResourceLimits(rg.ResourceLimits),
|
||||||
|
"secret": rg.Secret,
|
||||||
|
"status": rg.Status,
|
||||||
|
"updated_by": rg.UpdatedBy,
|
||||||
|
"updated_time": rg.UpdatedTime,
|
||||||
|
"vins": rg.Vins,
|
||||||
|
"vms": rg.Computes,
|
||||||
|
}
|
||||||
|
res = append(res, temp)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenRgAcl(rgAcls []AccountAclRecord) []map[string]interface{} {
|
||||||
|
res := make([]map[string]interface{}, 0)
|
||||||
|
for _, rgAcl := range rgAcls {
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"explicit": rgAcl.IsExplicit,
|
||||||
|
"guid": rgAcl.Guid,
|
||||||
|
"right": rgAcl.Rights,
|
||||||
|
"status": rgAcl.Status,
|
||||||
|
"type": rgAcl.Type,
|
||||||
|
"user_group_id": rgAcl.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 dataSourceRgListRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
rgList, err := utilityRgListCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", flattenRgList(rgList))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceRgListSchemaMake() map[string]*schema.Schema {
|
||||||
|
res := map[string]*schema.Schema{
|
||||||
|
"includedeleted": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "included deleted resource groups",
|
||||||
|
},
|
||||||
|
"page": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Page number",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Page size",
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"acl": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"created_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"created_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"def_net_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"def_net_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"deleted_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"deleted_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rg_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"lock_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"register_computes": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"resource_limits": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"secret": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"updated_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"updated_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"vins": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"vms": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceRgList() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceRgListRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceRgListSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dataSourceSepRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
desSep, err := utilitySepCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
|
||||||
|
d.Set("ckey", desSep.Ckey)
|
||||||
|
d.Set("meta", flattenMeta(desSep.Meta))
|
||||||
|
d.Set("consumed_by", desSep.ConsumedBy)
|
||||||
|
d.Set("desc", desSep.Desc)
|
||||||
|
d.Set("gid", desSep.Gid)
|
||||||
|
d.Set("guid", desSep.Guid)
|
||||||
|
d.Set("sep_id", desSep.Id)
|
||||||
|
d.Set("milestones", desSep.Milestones)
|
||||||
|
d.Set("name", desSep.Name)
|
||||||
|
d.Set("obj_status", desSep.ObjStatus)
|
||||||
|
d.Set("provided_by", desSep.ProvidedBy)
|
||||||
|
d.Set("tech_status", desSep.TechStatus)
|
||||||
|
d.Set("type", desSep.Type)
|
||||||
|
data, _ := json.Marshal(desSep.Config)
|
||||||
|
d.Set("config", string(data))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceSepCSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "sep type des id",
|
||||||
|
},
|
||||||
|
"ckey": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"consumed_by": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"obj_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"provided_by": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceSep() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceSepRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceSepCSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dataSourceSepConfigRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
sepConfig, err := utilitySepConfigCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
|
||||||
|
data, _ := json.Marshal(sepConfig)
|
||||||
|
d.Set("config", string(data))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceSepConfigSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "storage endpoint provider ID",
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "sep config json string",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceSepConfig() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceSepConfigRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceSepConfigSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dataSourceSepConsumptionRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
sepCons, err := utilitySepConsumptionCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
|
||||||
|
d.Set("type", sepCons.Type)
|
||||||
|
d.Set("total", flattenSepConsumption(sepCons.Total))
|
||||||
|
d.Set("by_pool", flattenSepConsumptionPools(sepCons.ByPool))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenSepConsumptionPools(mp map[string]SepConsumptionInd) []map[string]interface{} {
|
||||||
|
sh := make([]map[string]interface{}, 0)
|
||||||
|
for k, v := range mp {
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"name": k,
|
||||||
|
"disk_count": v.DiskCount,
|
||||||
|
"disk_usage": v.DiskUsage,
|
||||||
|
"snapshot_count": v.SnapshotCount,
|
||||||
|
"snapshot_usage": v.SnapshotUsage,
|
||||||
|
"usage": v.Usage,
|
||||||
|
"usage_limit": v.UsageLimit,
|
||||||
|
}
|
||||||
|
sh = append(sh, temp)
|
||||||
|
}
|
||||||
|
return sh
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenSepConsumption(sc SepConsumptionTotal) []map[string]interface{} {
|
||||||
|
sh := make([]map[string]interface{}, 0)
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"capacity_limit": sc.CapacityLimit,
|
||||||
|
"disk_count": sc.DiskCount,
|
||||||
|
"disk_usage": sc.DiskUsage,
|
||||||
|
"snapshot_count": sc.SnapshotCount,
|
||||||
|
"snapshot_usage": sc.SnapshotUsage,
|
||||||
|
"usage": sc.Usage,
|
||||||
|
"usage_limit": sc.UsageLimit,
|
||||||
|
}
|
||||||
|
sh = append(sh, temp)
|
||||||
|
return sh
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceSepConsumptionSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "sep id",
|
||||||
|
},
|
||||||
|
"by_pool": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "pool name",
|
||||||
|
},
|
||||||
|
"disk_count": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "number of disks",
|
||||||
|
},
|
||||||
|
"disk_usage": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "disk usage",
|
||||||
|
},
|
||||||
|
"snapshot_count": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "number of snapshots",
|
||||||
|
},
|
||||||
|
"snapshot_usage": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "snapshot usage",
|
||||||
|
},
|
||||||
|
"usage": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "usage",
|
||||||
|
},
|
||||||
|
"usage_limit": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "usage limit",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Description: "consumption divided by pool",
|
||||||
|
},
|
||||||
|
"total": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"capacity_limit": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"disk_count": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "number of disks",
|
||||||
|
},
|
||||||
|
"disk_usage": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "disk usage",
|
||||||
|
},
|
||||||
|
"snapshot_count": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "number of snapshots",
|
||||||
|
},
|
||||||
|
"snapshot_usage": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "snapshot usage",
|
||||||
|
},
|
||||||
|
"usage": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "usage",
|
||||||
|
},
|
||||||
|
"usage_limit": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "usage limit",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Description: "total consumption",
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "sep type",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceSepConsumption() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceSepConsumptionRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceSepConsumptionSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dataSourceSepDiskListRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
sepDiskList, err := utilitySepDiskListCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", sepDiskList)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceSepDiskListSchemaMake() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "storage endpoint provider ID",
|
||||||
|
},
|
||||||
|
"pool_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "pool name",
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Description: "sep disk list",
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceSepDiskList() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceSepDiskListRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceSepDiskListSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func flattenSepList(sl SepList) []map[string]interface{} {
|
||||||
|
res := make([]map[string]interface{}, 0)
|
||||||
|
for _, item := range sl {
|
||||||
|
data, _ := json.Marshal(item.Config)
|
||||||
|
temp := map[string]interface{}{
|
||||||
|
"ckey": item.Ckey,
|
||||||
|
"meta": flattenMeta(item.Meta),
|
||||||
|
"consumed_by": item.ConsumedBy,
|
||||||
|
"desc": item.Desc,
|
||||||
|
"gid": item.Gid,
|
||||||
|
"guid": item.Guid,
|
||||||
|
"sep_id": item.Id,
|
||||||
|
"milestones": item.Milestones,
|
||||||
|
"name": item.Name,
|
||||||
|
"obj_status": item.ObjStatus,
|
||||||
|
"provided_by": item.ProvidedBy,
|
||||||
|
"tech_status": item.TechStatus,
|
||||||
|
"type": item.Type,
|
||||||
|
"config": string(data),
|
||||||
|
}
|
||||||
|
|
||||||
|
res = append(res, temp)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceSepListRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
sepList, err := utilitySepListCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
d.Set("items", flattenSepList(sepList))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceSepListSchemaMake() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"page": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "page number",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "page size",
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Description: "sep list",
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: dataSourceSepShortSchemaMake(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceSepShortSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"ckey": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"consumed_by": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"obj_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"provided_by": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceSepList() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceSepListRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceSepListSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dataSourceSepPoolRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
sepPool, err := utilitySepPoolCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
|
||||||
|
data, _ := json.Marshal(sepPool)
|
||||||
|
d.Set("pool", string(data))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceSepPoolSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "storage endpoint provider ID",
|
||||||
|
},
|
||||||
|
"pool_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "pool name",
|
||||||
|
},
|
||||||
|
"pool": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceSepPool() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceSepPoolRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: dataSourceSepPoolSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2020-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
// "net/url"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
// "github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
// vins_facts is a response string from API vins/get
|
||||||
|
func flattenVins(d *schema.ResourceData, vins_facts string) error {
|
||||||
|
// NOTE: this function modifies ResourceData argument - as such it should never be called
|
||||||
|
// from resourceVinsExists(...) method
|
||||||
|
// log.Debugf("flattenVins: ready to decode response body from API %s", vins_facts)
|
||||||
|
vinsRecord := VinsRecord{}
|
||||||
|
err := json.Unmarshal([]byte(vins_facts), &vinsRecord)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("flattenVins: decoded ViNS name:ID %s:%d, account ID %d, RG ID %d",
|
||||||
|
vinsRecord.Name, vinsRecord.ID, vinsRecord.AccountID, vinsRecord.RgID)
|
||||||
|
|
||||||
|
d.SetId(fmt.Sprintf("%d", vinsRecord.ID))
|
||||||
|
d.Set("name", vinsRecord.Name)
|
||||||
|
d.Set("account_id", vinsRecord.AccountID)
|
||||||
|
d.Set("account_name", vinsRecord.AccountName)
|
||||||
|
d.Set("rg_id", vinsRecord.RgID)
|
||||||
|
d.Set("description", vinsRecord.Desc)
|
||||||
|
d.Set("ipcidr", vinsRecord.IPCidr)
|
||||||
|
|
||||||
|
noExtNetConnection := true
|
||||||
|
for _, value := range vinsRecord.VNFs {
|
||||||
|
if value.Type == "GW" {
|
||||||
|
log.Debugf("flattenVins: discovered GW VNF ID %d in ViNS ID %d", value.ID, vinsRecord.ID)
|
||||||
|
extNetID, idOk := value.Config["ext_net_id"] // NOTE: unknown numbers are unmarshalled to float64. This is by design!
|
||||||
|
extNetIP, ipOk := value.Config["ext_net_ip"]
|
||||||
|
if idOk && ipOk {
|
||||||
|
log.Debugf("flattenVins: ViNS ext_net_id=%d, ext_net_ip=%s", int(extNetID.(float64)), extNetIP.(string))
|
||||||
|
d.Set("ext_ip_addr", extNetIP.(string))
|
||||||
|
d.Set("ext_net_id", int(extNetID.(float64)))
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("Failed to unmarshal VNF GW Config - structure is invalid.")
|
||||||
|
}
|
||||||
|
noExtNetConnection = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if noExtNetConnection {
|
||||||
|
d.Set("ext_ip_addr", "")
|
||||||
|
d.Set("ext_net_id", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("flattenVins: EXTRA CHECK - schema rg_id=%d, ext_net_id=%d", d.Get("rg_id").(int), d.Get("ext_net_id").(int))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceVinsRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
vinsFacts, err := utilityVinsCheckPresence(d, m)
|
||||||
|
if vinsFacts == "" {
|
||||||
|
// if empty string is returned from utilityVinsCheckPresence then there is no
|
||||||
|
// such ViNS and err tells so - just return it to the calling party
|
||||||
|
d.SetId("") // ensure ID is empty in this case
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return flattenVins(d, vinsFacts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceVins() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Read: dataSourceVinsRead,
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Name of the ViNS. Names are case sensitive and unique within the context of an account or resource group.",
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
"vins_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Unique ID of the ViNS. If ViNS ID is specified, then ViNS name, rg_id and account_id are ignored.",
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
|
"rg_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Unique ID of the resource group, where this ViNS is belongs to (for ViNS created at resource group level, 0 otherwise).",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Unique ID of the account, which this ViNS belongs to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
// the rest of attributes are computed
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Name of the account, which this ViNS belongs to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"description": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "User-defined text description of this ViNS.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ext_ip_addr": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "IP address of the external connection (valid for ViNS connected to external network, empty string otherwise).",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ext_net_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "ID of the external network this ViNS is connected to (-1 means no external connection).",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ipcidr": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Network address used by this ViNS.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Petr Krutov, <petr.krutov@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import "github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
|
||||||
|
func nodeMasterDefault() K8sNodeRecord {
|
||||||
|
return K8sNodeRecord{
|
||||||
|
Num: 1,
|
||||||
|
Cpu: 2,
|
||||||
|
Ram: 2048,
|
||||||
|
Disk: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func nodeWorkerDefault() K8sNodeRecord {
|
||||||
|
return K8sNodeRecord{
|
||||||
|
Num: 1,
|
||||||
|
Cpu: 1,
|
||||||
|
Ram: 1024,
|
||||||
|
Disk: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseNode(nodeList []interface{}) K8sNodeRecord {
|
||||||
|
node := nodeList[0].(map[string]interface{})
|
||||||
|
|
||||||
|
return K8sNodeRecord{
|
||||||
|
Num: node["num"].(int),
|
||||||
|
Cpu: node["cpu"].(int),
|
||||||
|
Ram: node["ram"].(int),
|
||||||
|
Disk: node["disk"].(int),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func nodeToResource(node K8sNodeRecord) []interface{} {
|
||||||
|
mp := make(map[string]interface{})
|
||||||
|
|
||||||
|
mp["num"] = node.Num
|
||||||
|
mp["cpu"] = node.Cpu
|
||||||
|
mp["ram"] = node.Ram
|
||||||
|
mp["disk"] = node.Disk
|
||||||
|
|
||||||
|
return []interface{}{mp}
|
||||||
|
}
|
||||||
|
|
||||||
|
func nodeK8sSubresourceSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"num": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "Number of nodes to create.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"cpu": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "Node CPU count.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ram": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "Node RAM in MB.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"disk": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "Node boot disk size in GB.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
||||||
|
// "github.com/hashicorp/terraform-plugin-sdk/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Provider() *schema.Provider {
|
||||||
|
return &schema.Provider{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"authenticator": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
StateFunc: stateFuncToLower,
|
||||||
|
ValidateFunc: validation.StringInSlice([]string{"oauth2", "legacy", "jwt"}, true), // ignore case while validating
|
||||||
|
Description: "Authentication mode to use when connecting to DECORT cloud API. Should be one of 'oauth2', 'legacy' or 'jwt'.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"oauth2_url": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
StateFunc: stateFuncToLower,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("DECORT_OAUTH2_URL", nil),
|
||||||
|
Description: "OAuth2 application URL in 'oauth2' authentication mode.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"controller_url": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
StateFunc: stateFuncToLower,
|
||||||
|
Description: "URL of DECORT Cloud controller to use. API calls will be directed to this URL.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"user": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("DECORT_USER", nil),
|
||||||
|
Description: "User name for DECORT cloud API operations in 'legacy' authentication mode.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"password": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("DECORT_PASSWORD", nil),
|
||||||
|
Description: "User password for DECORT cloud API operations in 'legacy' authentication mode.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"app_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("DECORT_APP_ID", nil),
|
||||||
|
Description: "Application ID to access DECORT cloud API in 'oauth2' authentication mode.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"app_secret": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("DECORT_APP_SECRET", nil),
|
||||||
|
Description: "Application secret to access DECORT cloud API in 'oauth2' authentication mode.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"jwt": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("DECORT_JWT", nil),
|
||||||
|
Description: "JWT to access DECORT cloud API in 'jwt' authentication mode.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"allow_unverified_ssl": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "If true, DECORT API will not verify SSL certificates. Use this with caution and in trusted environments only!",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
|
"decort_resgroup": resourceResgroup(),
|
||||||
|
"decort_kvmvm": resourceCompute(),
|
||||||
|
"decort_disk": resourceDisk(),
|
||||||
|
"decort_vins": resourceVins(),
|
||||||
|
"decort_pfw": resourcePfw(),
|
||||||
|
"decort_k8s": resourceK8s(),
|
||||||
|
"decort_k8s_wg": resourceK8sWg(),
|
||||||
|
"decort_image": resourceImage(),
|
||||||
|
"decort_virtual_image": resourceVirtualImage(),
|
||||||
|
"decort_cdrom_image": resourceCDROMImage(),
|
||||||
|
"decort_delete_images": resourceDeleteImages(),
|
||||||
|
"decort_snapshot": resourceSnapshot(),
|
||||||
|
"decort_pcidevice": resourcePcidevice(),
|
||||||
|
"decort_sep": resourceSep(),
|
||||||
|
"decort_sep_config": resourceSepConfig(),
|
||||||
|
"decort_account": resourceAccount(),
|
||||||
|
"decort_bservice": resourceBasicService(),
|
||||||
|
"decort_bservice_group": resourceBasicServiceGroup(),
|
||||||
|
},
|
||||||
|
|
||||||
|
DataSourcesMap: map[string]*schema.Resource{
|
||||||
|
"decort_account": dataSourceAccount(),
|
||||||
|
"decort_resgroup": dataSourceResgroup(),
|
||||||
|
"decort_kvmvm": dataSourceCompute(),
|
||||||
|
"decort_image": dataSourceImage(),
|
||||||
|
"decort_disk": dataSourceDisk(),
|
||||||
|
"decort_vins": dataSourceVins(),
|
||||||
|
"decort_grid": dataSourceGrid(),
|
||||||
|
"decort_grid_list": dataSourceGridList(),
|
||||||
|
"decort_image_list": dataSourceImageList(),
|
||||||
|
"decort_image_list_stacks": dataSourceImageListStacks(),
|
||||||
|
"decort_snapshot_list": dataSourceSnapshotList(),
|
||||||
|
"decort_vgpu": dataSourceVGPU(),
|
||||||
|
"decort_pcidevice": dataSourcePcidevice(),
|
||||||
|
"decort_pcidevice_list": dataSourcePcideviceList(),
|
||||||
|
"decort_sep_list": dataSourceSepList(),
|
||||||
|
"decort_sep": dataSourceSep(),
|
||||||
|
"decort_sep_consumption": dataSourceSepConsumption(),
|
||||||
|
"decort_sep_disk_list": dataSourceSepDiskList(),
|
||||||
|
"decort_sep_config": dataSourceSepConfig(),
|
||||||
|
"decort_sep_pool": dataSourceSepPool(),
|
||||||
|
"decort_disk_list": dataSourceDiskList(),
|
||||||
|
"decort_rg_list": dataSourceRgList(),
|
||||||
|
"decort_account_list": dataSourceAccountList(),
|
||||||
|
"decort_account_computes_list": dataSourceAccountComputesList(),
|
||||||
|
"decort_account_disks_list": dataSourceAccountDisksList(),
|
||||||
|
"decort_account_vins_list": dataSourceAccountVinsList(),
|
||||||
|
"decort_account_audits_list": dataSourceAccountAuditsList(),
|
||||||
|
"decort_account_rg_list": dataSourceAccountRGList(),
|
||||||
|
"decort_account_consumed_units": dataSourceAccountConsumedUnits(),
|
||||||
|
"decort_account_consumed_units_by_type": dataSourceAccountConsumedUnitsByType(),
|
||||||
|
"decort_account_reserved_units": dataSourceAccountReservedUnits(),
|
||||||
|
"decort_account_templates_list": dataSourceAccountTemplatessList(),
|
||||||
|
"decort_account_deleted_list": dataSourceAccountDeletedList(),
|
||||||
|
"decort_account_flipgroups_list": dataSourceAccountFlipGroupsList(),
|
||||||
|
"decort_bservice_list": dataSourceBasicServiceList(),
|
||||||
|
"decort_bservice": dataSourceBasicService(),
|
||||||
|
"decort_bservice_snapshot_list": dataSourceBasicServiceSnapshotList(),
|
||||||
|
"decort_bservice_group": dataSourceBasicServiceGroup(),
|
||||||
|
"decort_bservice_deleted_list": dataSourceBasicServiceDeletedList(),
|
||||||
|
"decort_extnet_list": dataSourceExtnetList(),
|
||||||
|
"decort_extnet_computes_list": dataSourceExtnetComputesList(),
|
||||||
|
"decort_extnet": dataSourceExtnet(),
|
||||||
|
"decort_extnet_default": dataSourceExtnetDefault(),
|
||||||
|
"decort_vins_list": dataSourceVinsList(),
|
||||||
|
// "decort_pfw": dataSourcePfw(),
|
||||||
|
},
|
||||||
|
|
||||||
|
ConfigureFunc: providerConfigure,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func stateFuncToLower(argval interface{}) string {
|
||||||
|
return strings.ToLower(argval.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
func stateFuncToUpper(argval interface{}) string {
|
||||||
|
return strings.ToUpper(argval.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
||||||
|
decsController, err := ControllerConfigure(d)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize global default Grid ID - it will be needed to create some resource types, e.g. disks
|
||||||
|
gridId, err := decsController.utilityLocationGetDefaultGridID()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if gridId == 0 {
|
||||||
|
return nil, fmt.Errorf("providerConfigure: invalid default Grid ID = 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
return decsController, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,794 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceAccountCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceAccountCreate")
|
||||||
|
|
||||||
|
if accountId, ok := d.GetOk("account_id"); ok {
|
||||||
|
if exists, err := resourceAccountExists(d, m); exists {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId(strconv.Itoa(accountId.(int)))
|
||||||
|
err = resourceAccountRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("provided account id does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("name", d.Get("account_name").(string))
|
||||||
|
urlValues.Add("username", d.Get("username").(string))
|
||||||
|
|
||||||
|
if emailaddress, ok := d.GetOk("emailaddress"); ok {
|
||||||
|
urlValues.Add("emailaddress", emailaddress.(string))
|
||||||
|
}
|
||||||
|
if sendAccessEmails, ok := d.GetOk("send_access_emails"); ok {
|
||||||
|
urlValues.Add("sendAccessEmails", strconv.FormatBool(sendAccessEmails.(bool)))
|
||||||
|
}
|
||||||
|
if resLimits, ok := d.GetOk("resource_limits"); ok {
|
||||||
|
resLimit := resLimits.([]interface{})[0]
|
||||||
|
resLimitConv := resLimit.(map[string]interface{})
|
||||||
|
if resLimitConv["cu_m"] != nil {
|
||||||
|
maxMemCap := int(resLimitConv["cu_m"].(float64))
|
||||||
|
if maxMemCap == 0 {
|
||||||
|
urlValues.Add("maxMemoryCapacity", strconv.Itoa(-1))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("maxMemoryCapacity", strconv.Itoa(maxMemCap))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resLimitConv["cu_d"] != nil {
|
||||||
|
maxDiskCap := int(resLimitConv["cu_d"].(float64))
|
||||||
|
if maxDiskCap == 0 {
|
||||||
|
urlValues.Add("maxVDiskCapacity", strconv.Itoa(-1))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("maxVDiskCapacity", strconv.Itoa(maxDiskCap))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resLimitConv["cu_c"] != nil {
|
||||||
|
maxCPUCap := int(resLimitConv["cu_c"].(float64))
|
||||||
|
if maxCPUCap == 0 {
|
||||||
|
urlValues.Add("maxCPUCapacity", strconv.Itoa(-1))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("maxCPUCapacity", strconv.Itoa(maxCPUCap))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if resLimitConv["cu_i"] != nil {
|
||||||
|
maxNumPublicIP := int(resLimitConv["cu_i"].(float64))
|
||||||
|
if maxNumPublicIP == 0 {
|
||||||
|
urlValues.Add("maxNumPublicIP", strconv.Itoa(-1))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("maxNumPublicIP", strconv.Itoa(maxNumPublicIP))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if resLimitConv["cu_np"] != nil {
|
||||||
|
maxNP := int(resLimitConv["cu_np"].(float64))
|
||||||
|
if maxNP == 0 {
|
||||||
|
urlValues.Add("maxNetworkPeerTransfer", strconv.Itoa(-1))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("maxNetworkPeerTransfer", strconv.Itoa(maxNP))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if resLimitConv["gpu_units"] != nil {
|
||||||
|
gpuUnits := int(resLimitConv["gpu_units"].(float64))
|
||||||
|
if gpuUnits == 0 {
|
||||||
|
urlValues.Add("gpu_units", strconv.Itoa(-1))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("gpu_units", strconv.Itoa(gpuUnits))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accountId, err := controller.decortAPICall("POST", accountCreateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(accountId)
|
||||||
|
d.Set("account_id", accountId)
|
||||||
|
|
||||||
|
err = resourceAccountRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(id.String())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAccountRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceAccountRead")
|
||||||
|
|
||||||
|
acc, err := utilityAccountCheckPresence(d, m)
|
||||||
|
if acc == nil {
|
||||||
|
d.SetId("")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("dc_location", acc.DCLocation)
|
||||||
|
d.Set("resources", flattenAccResources(acc.Resources))
|
||||||
|
d.Set("ckey", acc.CKey)
|
||||||
|
d.Set("meta", 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 resourceAccountDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceAccountDelete")
|
||||||
|
|
||||||
|
account, err := utilityAccountCheckPresence(d, m)
|
||||||
|
if account == nil {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
urlValues.Add("permanently", strconv.FormatBool(d.Get("permanently").(bool)))
|
||||||
|
|
||||||
|
_, err = controller.decortAPICall("POST", accountDeleteAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAccountExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
log.Debugf("resourceAccountExists")
|
||||||
|
|
||||||
|
account, err := utilityAccountCheckPresence(d, m)
|
||||||
|
if account == nil {
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAccountEdit(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceAccountEdit")
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
if d.HasChange("enable") {
|
||||||
|
api := accountDisableAPI
|
||||||
|
enable := d.Get("enable").(bool)
|
||||||
|
if enable {
|
||||||
|
api = accountEnableAPI
|
||||||
|
}
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", api, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("account_name") {
|
||||||
|
urlValues.Add("name", d.Get("account_name").(string))
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
_, err := c.decortAPICall("POST", accountUpdateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
if d.HasChange("resource_limits") {
|
||||||
|
resLimit := d.Get("resource_limits").([]interface{})[0]
|
||||||
|
resLimitConv := resLimit.(map[string]interface{})
|
||||||
|
|
||||||
|
if resLimitConv["cu_m"] != nil {
|
||||||
|
maxMemCap := int(resLimitConv["cu_m"].(float64))
|
||||||
|
if maxMemCap == 0 {
|
||||||
|
urlValues.Add("maxMemoryCapacity", strconv.Itoa(-1))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("maxMemoryCapacity", strconv.Itoa(maxMemCap))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resLimitConv["cu_d"] != nil {
|
||||||
|
maxDiskCap := int(resLimitConv["cu_d"].(float64))
|
||||||
|
if maxDiskCap == 0 {
|
||||||
|
urlValues.Add("maxVDiskCapacity", strconv.Itoa(-1))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("maxVDiskCapacity", strconv.Itoa(maxDiskCap))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resLimitConv["cu_c"] != nil {
|
||||||
|
maxCPUCap := int(resLimitConv["cu_c"].(float64))
|
||||||
|
if maxCPUCap == 0 {
|
||||||
|
urlValues.Add("maxCPUCapacity", strconv.Itoa(-1))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("maxCPUCapacity", strconv.Itoa(maxCPUCap))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if resLimitConv["cu_i"] != nil {
|
||||||
|
maxNumPublicIP := int(resLimitConv["cu_i"].(float64))
|
||||||
|
if maxNumPublicIP == 0 {
|
||||||
|
urlValues.Add("maxNumPublicIP", strconv.Itoa(-1))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("maxNumPublicIP", strconv.Itoa(maxNumPublicIP))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if resLimitConv["cu_np"] != nil {
|
||||||
|
maxNP := int(resLimitConv["cu_np"].(float64))
|
||||||
|
if maxNP == 0 {
|
||||||
|
urlValues.Add("maxNetworkPeerTransfer", strconv.Itoa(-1))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("maxNetworkPeerTransfer", strconv.Itoa(maxNP))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if resLimitConv["gpu_units"] != nil {
|
||||||
|
gpuUnits := int(resLimitConv["gpu_units"].(float64))
|
||||||
|
if gpuUnits == 0 {
|
||||||
|
urlValues.Add("gpu_units", strconv.Itoa(-1))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("gpu_units", strconv.Itoa(gpuUnits))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
_, err := c.decortAPICall("POST", accountUpdateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("send_access_emails") {
|
||||||
|
urlValues.Add("sendAccessEmails", strconv.FormatBool(d.Get("send_access_emails").(bool)))
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
_, err := c.decortAPICall("POST", accountUpdateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("restore") {
|
||||||
|
restore := d.Get("restore").(bool)
|
||||||
|
if restore {
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
_, err := c.decortAPICall("POST", accountRestoreAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("users") {
|
||||||
|
deletedUsers := make([]interface{}, 0)
|
||||||
|
addedUsers := make([]interface{}, 0)
|
||||||
|
updatedUsers := make([]interface{}, 0)
|
||||||
|
|
||||||
|
old, new := d.GetChange("users")
|
||||||
|
oldConv := old.([]interface{})
|
||||||
|
newConv := new.([]interface{})
|
||||||
|
for _, el := range oldConv {
|
||||||
|
if !isContainsUser(newConv, el) {
|
||||||
|
deletedUsers = append(deletedUsers, el)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, el := range newConv {
|
||||||
|
if !isContainsUser(oldConv, el) {
|
||||||
|
addedUsers = append(addedUsers, el)
|
||||||
|
} else {
|
||||||
|
if isChangedUser(oldConv, el) {
|
||||||
|
updatedUsers = append(updatedUsers, el)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(deletedUsers) > 0 {
|
||||||
|
for _, user := range deletedUsers {
|
||||||
|
userConv := user.(map[string]interface{})
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
urlValues.Add("userId", userConv["user_id"].(string))
|
||||||
|
urlValues.Add("recursivedelete", strconv.FormatBool(userConv["recursive_delete"].(bool)))
|
||||||
|
_, err := c.decortAPICall("POST", accountDeleteUserAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(addedUsers) > 0 {
|
||||||
|
for _, user := range addedUsers {
|
||||||
|
userConv := user.(map[string]interface{})
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
urlValues.Add("userId", userConv["user_id"].(string))
|
||||||
|
urlValues.Add("accesstype", strings.ToUpper(userConv["access_type"].(string)))
|
||||||
|
_, err := c.decortAPICall("POST", accountAddUserAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(updatedUsers) > 0 {
|
||||||
|
for _, user := range updatedUsers {
|
||||||
|
userConv := user.(map[string]interface{})
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
urlValues.Add("userId", userConv["user_id"].(string))
|
||||||
|
urlValues.Add("accesstype", strings.ToUpper(userConv["access_type"].(string)))
|
||||||
|
_, err := c.decortAPICall("POST", accountUpdateUserAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isContainsUser(els []interface{}, el interface{}) bool {
|
||||||
|
for _, elOld := range els {
|
||||||
|
elOldConv := elOld.(map[string]interface{})
|
||||||
|
elConv := el.(map[string]interface{})
|
||||||
|
if elOldConv["user_id"].(string) == elConv["user_id"].(string) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isChangedUser(els []interface{}, el interface{}) bool {
|
||||||
|
for _, elOld := range els {
|
||||||
|
elOldConv := elOld.(map[string]interface{})
|
||||||
|
elConv := el.(map[string]interface{})
|
||||||
|
if elOldConv["user_id"].(string) == elConv["user_id"].(string) &&
|
||||||
|
(!strings.EqualFold(elOldConv["access_type"].(string), elConv["access_type"].(string)) ||
|
||||||
|
elOldConv["recursive_delete"].(bool) != elConv["recursive_delete"].(bool)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAccountSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "account name",
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "username of owner the account",
|
||||||
|
},
|
||||||
|
"emailaddress": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "email",
|
||||||
|
},
|
||||||
|
"send_access_emails": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: true,
|
||||||
|
Description: "if true send emails when a user is granted access to resources",
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"user_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"access_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"recursive_delete": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"restore": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Description: "restore a deleted account",
|
||||||
|
},
|
||||||
|
"permanently": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "whether to completely delete the account",
|
||||||
|
},
|
||||||
|
"enable": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Description: "enable/disable account",
|
||||||
|
},
|
||||||
|
"resource_limits": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"cu_c": {
|
||||||
|
Type: schema.TypeFloat,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"cu_d": {
|
||||||
|
Type: schema.TypeFloat,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"cu_i": {
|
||||||
|
Type: schema.TypeFloat,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"cu_m": {
|
||||||
|
Type: schema.TypeFloat,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"cu_np": {
|
||||||
|
Type: schema.TypeFloat,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"gpu_units": {
|
||||||
|
Type: schema.TypeFloat,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"dc_location": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"current": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"cpu": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"disksize": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"reserved": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"cpu": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"disksize": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"ckey": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"acl": {
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"company": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"companyurl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"created_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"created_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"deactivation_time": {
|
||||||
|
Type: schema.TypeFloat,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"deleted_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"deleted_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"displayname": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"service_account": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"updated_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"vins": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"computes": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"started": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"stopped": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"machines": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"halted": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"running": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"vinses": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAccount() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceAccountCreate,
|
||||||
|
Read: resourceAccountRead,
|
||||||
|
Update: resourceAccountEdit,
|
||||||
|
Delete: resourceAccountDelete,
|
||||||
|
Exists: resourceAccountExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: resourceAccountSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,554 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceBasicServiceCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceBasicServiceCreate")
|
||||||
|
|
||||||
|
if serviceId, ok := d.GetOk("service_id"); ok {
|
||||||
|
if exists, err := resourceBasicServiceExists(d, m); exists {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(strconv.Itoa(serviceId.(int)))
|
||||||
|
d.Set("service_id", strconv.Itoa(serviceId.(int)))
|
||||||
|
err = resourceBasicServiceRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId(id.String())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("provided service id does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("name", d.Get("service_name").(string))
|
||||||
|
urlValues.Add("rgId", strconv.Itoa(d.Get("rg_id").(int)))
|
||||||
|
|
||||||
|
if sshKey, ok := d.GetOk("ssh_key"); ok {
|
||||||
|
urlValues.Add("sshKey", sshKey.(string))
|
||||||
|
}
|
||||||
|
if sshUser, ok := d.GetOk("ssh_user"); ok {
|
||||||
|
urlValues.Add("sshUser", sshUser.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceId, err := controller.decortAPICall("POST", bserviceCreateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(serviceId)
|
||||||
|
d.Set("service_id", serviceId)
|
||||||
|
|
||||||
|
err = resourceBasicServiceRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(id.String())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceBasicServiceRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceBasicServiceRead")
|
||||||
|
|
||||||
|
bs, err := utilityBasicServiceCheckPresence(d, m)
|
||||||
|
if bs == nil {
|
||||||
|
d.SetId("")
|
||||||
|
return 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)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceBasicServiceDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceBasicServiceDelete")
|
||||||
|
|
||||||
|
bs, err := utilityBasicServiceCheckPresence(d, m)
|
||||||
|
if bs == nil {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
urlValues.Add("permanently", strconv.FormatBool(d.Get("permanently").(bool)))
|
||||||
|
|
||||||
|
_, err = controller.decortAPICall("POST", bserviceDeleteAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceBasicServiceExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
log.Debugf("resourceBasicServiceExists")
|
||||||
|
|
||||||
|
bservice, err := utilityBasicServiceCheckPresence(d, m)
|
||||||
|
if bservice == nil {
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceBasicServiceEdit(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceBasicServiceEdit")
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
if d.HasChange("enable") {
|
||||||
|
api := bserviceDisableAPI
|
||||||
|
enable := d.Get("enable").(bool)
|
||||||
|
if enable {
|
||||||
|
api = bserviceEnableAPI
|
||||||
|
}
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", api, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("restore") {
|
||||||
|
restore := d.Get("restore").(bool)
|
||||||
|
if restore {
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
_, err := c.decortAPICall("POST", bserviceRestoreAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("start") {
|
||||||
|
api := bserviceStopAPI
|
||||||
|
start := d.Get("start").(bool)
|
||||||
|
if start {
|
||||||
|
api = bserviceStartAPI
|
||||||
|
}
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", api, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("snapshots") {
|
||||||
|
deletedSnapshots := make([]interface{}, 0)
|
||||||
|
addedSnapshots := make([]interface{}, 0)
|
||||||
|
updatedSnapshots := make([]interface{}, 0)
|
||||||
|
|
||||||
|
old, new := d.GetChange("snapshots")
|
||||||
|
oldConv := old.([]interface{})
|
||||||
|
newConv := new.([]interface{})
|
||||||
|
for _, el := range oldConv {
|
||||||
|
if !isContainsSnapshot(newConv, el) {
|
||||||
|
deletedSnapshots = append(deletedSnapshots, el)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, el := range newConv {
|
||||||
|
if !isContainsSnapshot(oldConv, el) {
|
||||||
|
addedSnapshots = append(addedSnapshots, el)
|
||||||
|
} else {
|
||||||
|
if isRollback(oldConv, el) {
|
||||||
|
updatedSnapshots = append(updatedSnapshots, el)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(deletedSnapshots) > 0 {
|
||||||
|
for _, snapshot := range deletedSnapshots {
|
||||||
|
snapshotConv := snapshot.(map[string]interface{})
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
urlValues.Add("label", snapshotConv["label"].(string))
|
||||||
|
_, err := c.decortAPICall("POST", bserviceSnapshotDeleteAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(addedSnapshots) > 0 {
|
||||||
|
for _, snapshot := range addedSnapshots {
|
||||||
|
snapshotConv := snapshot.(map[string]interface{})
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
urlValues.Add("label", snapshotConv["label"].(string))
|
||||||
|
_, err := c.decortAPICall("POST", bserviceSnapshotCreateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(updatedSnapshots) > 0 {
|
||||||
|
for _, snapshot := range updatedSnapshots {
|
||||||
|
snapshotConv := snapshot.(map[string]interface{})
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
urlValues.Add("label", snapshotConv["label"].(string))
|
||||||
|
_, err := c.decortAPICall("POST", bserviceSnapshotRollbackAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isContainsSnapshot(els []interface{}, el interface{}) bool {
|
||||||
|
for _, elOld := range els {
|
||||||
|
elOldConv := elOld.(map[string]interface{})
|
||||||
|
elConv := el.(map[string]interface{})
|
||||||
|
if elOldConv["guid"].(string) == elConv["guid"].(string) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isRollback(els []interface{}, el interface{}) bool {
|
||||||
|
for _, elOld := range els {
|
||||||
|
elOldConv := elOld.(map[string]interface{})
|
||||||
|
elConv := el.(map[string]interface{})
|
||||||
|
if elOldConv["guid"].(string) == elConv["guid"].(string) &&
|
||||||
|
elOldConv["rollback"].(bool) != elConv["rollback"].(bool) &&
|
||||||
|
elConv["rollback"].(bool) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceBasicServiceSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"service_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Name of the service",
|
||||||
|
},
|
||||||
|
"rg_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "ID of the Resource Group where this service will be placed",
|
||||||
|
},
|
||||||
|
"ssh_key": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "SSH key to deploy for the specified user. Same key will be deployed to all computes of the service.",
|
||||||
|
},
|
||||||
|
"ssh_user": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "name of the user to deploy SSH key for. Pass empty string if no SSH key deployment is required",
|
||||||
|
},
|
||||||
|
"permanently": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "if set to False, Basic service will be deleted to recycle bin. Otherwise destroyed immediately",
|
||||||
|
},
|
||||||
|
"enable": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "if set to False, Basic service will be deleted to recycle bin. Otherwise destroyed immediately",
|
||||||
|
},
|
||||||
|
"restore": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "Restores BasicService instance",
|
||||||
|
},
|
||||||
|
"start": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "Start service. Starting a service technically means starting computes from all service groups according to group relations",
|
||||||
|
},
|
||||||
|
"service_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"base_domain": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"computes": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"compgroup_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"compgroup_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"compgroup_role": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"cpu_total": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"created_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"created_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"deleted_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"deleted_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"disk_total": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"groups": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"groups_name": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"parent_srv_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"parent_srv_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"ram_total": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rg_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"snapshots": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rollback": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"valid": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"updated_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"updated_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"user_managed": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceBasicService() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceBasicServiceCreate,
|
||||||
|
Read: resourceBasicServiceRead,
|
||||||
|
Update: resourceBasicServiceEdit,
|
||||||
|
Delete: resourceBasicServiceDelete,
|
||||||
|
Exists: resourceBasicServiceExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: resourceBasicServiceSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,661 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceBasicServiceGroupCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceBasicServiceGroupCreate")
|
||||||
|
|
||||||
|
if compgroupId, ok := d.GetOk("compgroup_id"); ok {
|
||||||
|
if _, ok := d.GetOk("service_id"); ok {
|
||||||
|
if exists, err := resourceBasicServiceGroupExists(d, m); exists {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(strconv.Itoa(compgroupId.(int)))
|
||||||
|
d.Set("compgroup_id", strconv.Itoa(compgroupId.(int)))
|
||||||
|
err = resourceBasicServiceGroupRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId(id.String())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("provided compgroup id does not exist")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
urlValues.Add("name", d.Get("compgroup_name").(string))
|
||||||
|
|
||||||
|
urlValues.Add("count", strconv.Itoa(d.Get("comp_count").(int)))
|
||||||
|
urlValues.Add("cpu", strconv.Itoa(d.Get("cpu").(int)))
|
||||||
|
urlValues.Add("ram", strconv.Itoa(d.Get("ram").(int)))
|
||||||
|
urlValues.Add("disk", strconv.Itoa(d.Get("disk").(int)))
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
urlValues.Add("driver", strings.ToUpper(d.Get("driver").(string)))
|
||||||
|
|
||||||
|
if role, ok := d.GetOk("role"); ok {
|
||||||
|
urlValues.Add("role", role.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
if timeoutStart, ok := d.GetOk("timeout_start"); ok {
|
||||||
|
urlValues.Add("timeoutStart", strconv.Itoa(timeoutStart.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if vinses, ok := d.GetOk("vinses"); ok {
|
||||||
|
vs := vinses.([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(vs)
|
||||||
|
for i, v := range vs {
|
||||||
|
s := strconv.Itoa(v.(int))
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ","
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
urlValues.Add("vinses", temp)
|
||||||
|
}
|
||||||
|
if extnets, ok := d.GetOk("extnets"); ok {
|
||||||
|
es := extnets.([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(es)
|
||||||
|
for i, e := range es {
|
||||||
|
s := strconv.Itoa(e.(int))
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ","
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
urlValues.Add("extnets", temp)
|
||||||
|
}
|
||||||
|
|
||||||
|
compgroupId, err := controller.decortAPICall("POST", bserviceGroupAddAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(compgroupId)
|
||||||
|
d.Set("compgroup_id", compgroupId)
|
||||||
|
|
||||||
|
err = resourceBasicServiceGroupRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(id.String())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceBasicServiceGroupRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceBasicServiceGroupRead")
|
||||||
|
|
||||||
|
bsg, err := utilityBasicServiceGroupCheckPresence(d, m)
|
||||||
|
if bsg == nil {
|
||||||
|
d.SetId("")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("account_id", bsg.AccountId)
|
||||||
|
d.Set("account_name", bsg.AccountName)
|
||||||
|
d.Set("computes", flattenBSGroupComputes(bsg.Computes))
|
||||||
|
d.Set("consistency", bsg.Consistency)
|
||||||
|
d.Set("cpu", bsg.CPU)
|
||||||
|
d.Set("created_by", bsg.CreatedBy)
|
||||||
|
d.Set("created_time", bsg.CreatedTime)
|
||||||
|
d.Set("deleted_by", bsg.DeletedBy)
|
||||||
|
d.Set("deleted_time", bsg.DeletedTime)
|
||||||
|
d.Set("disk", bsg.Disk)
|
||||||
|
d.Set("driver", bsg.Driver)
|
||||||
|
d.Set("extnets", bsg.Extnets)
|
||||||
|
d.Set("gid", bsg.GID)
|
||||||
|
d.Set("guid", bsg.GUID)
|
||||||
|
d.Set("image_id", bsg.ImageId)
|
||||||
|
d.Set("milestones", bsg.Milestones)
|
||||||
|
d.Set("compgroup_name", bsg.Name)
|
||||||
|
d.Set("compgroup_id", bsg.ID)
|
||||||
|
d.Set("parents", bsg.Parents)
|
||||||
|
d.Set("ram", bsg.RAM)
|
||||||
|
d.Set("rg_id", bsg.RGID)
|
||||||
|
d.Set("rg_name", bsg.RGName)
|
||||||
|
d.Set("role", bsg.Role)
|
||||||
|
d.Set("sep_id", bsg.SepId)
|
||||||
|
d.Set("seq_no", bsg.SeqNo)
|
||||||
|
d.Set("status", bsg.Status)
|
||||||
|
d.Set("tech_status", bsg.TechStatus)
|
||||||
|
d.Set("timeout_start", bsg.TimeoutStart)
|
||||||
|
d.Set("updated_by", bsg.UpdatedBy)
|
||||||
|
d.Set("updated_time", bsg.UpdatedTime)
|
||||||
|
d.Set("vinses", bsg.Vinses)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceBasicServiceGroupDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceBasicServiceGroupDelete")
|
||||||
|
|
||||||
|
bsg, err := utilityBasicServiceGroupCheckPresence(d, m)
|
||||||
|
if bsg == nil {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
urlValues.Add("compgroupId", strconv.Itoa(d.Get("compgroup_id").(int)))
|
||||||
|
|
||||||
|
_, err = controller.decortAPICall("POST", bserviceGroupRemoveAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceBasicServiceGroupExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
log.Debugf("resourceBasicServiceGroupExists")
|
||||||
|
|
||||||
|
bserviceGroup, err := utilityBasicServiceGroupCheckPresence(d, m)
|
||||||
|
if bserviceGroup == nil {
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceBasicServiceGroupEdit(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceBasicServiceGroupEdit")
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
if d.HasChange("comp_count") {
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
urlValues.Add("compgroupId", strconv.Itoa(d.Get("compgroup_id").(int)))
|
||||||
|
urlValues.Add("count", strconv.Itoa(d.Get("comp_count").(int)))
|
||||||
|
urlValues.Add("mode", strings.ToUpper(d.Get("mode").(string)))
|
||||||
|
_, err := c.decortAPICall("POST", bserviceGroupResizeAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("start") {
|
||||||
|
api := bserviceGroupStopAPI
|
||||||
|
start := d.Get("start").(bool)
|
||||||
|
if start {
|
||||||
|
api = bserviceGroupStartAPI
|
||||||
|
} else {
|
||||||
|
urlValues.Add("force", strconv.FormatBool(d.Get("force_stop").(bool)))
|
||||||
|
}
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
urlValues.Add("compgroupId", strconv.Itoa(d.Get("compgroup_id").(int)))
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", api, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChanges("compgroup_name", "ram", "cpu", "disk", "role") {
|
||||||
|
urlValues.Add("name", d.Get("compgroup_name").(string))
|
||||||
|
urlValues.Add("cpu", strconv.Itoa(d.Get("cpu").(int)))
|
||||||
|
urlValues.Add("ram", strconv.Itoa(d.Get("ram").(int)))
|
||||||
|
urlValues.Add("disk", strconv.Itoa(d.Get("disk").(int)))
|
||||||
|
urlValues.Add("role", d.Get("role").(string))
|
||||||
|
urlValues.Add("force", strconv.FormatBool(d.Get("force_update").(bool)))
|
||||||
|
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
urlValues.Add("compgroupId", strconv.Itoa(d.Get("compgroup_id").(int)))
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", bserviceGroupUpdateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("extnets") {
|
||||||
|
extnets := d.Get("extnets").([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(extnets)
|
||||||
|
for i, e := range extnets {
|
||||||
|
s := strconv.Itoa(e.(int))
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ",\n"
|
||||||
|
} else {
|
||||||
|
s += "\n"
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
urlValues.Add("compgroupId", strconv.Itoa(d.Get("compgroup_id").(int)))
|
||||||
|
urlValues.Add("extnets", temp)
|
||||||
|
_, err := c.decortAPICall("POST", bserviceGroupUpdateExtnetAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("vinses") {
|
||||||
|
vinses := d.Get("vinses").([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(vinses)
|
||||||
|
for i, v := range vinses {
|
||||||
|
s := strconv.Itoa(v.(int))
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ",\n"
|
||||||
|
} else {
|
||||||
|
s += "\n"
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
urlValues.Add("compgroupId", strconv.Itoa(d.Get("compgroup_id").(int)))
|
||||||
|
urlValues.Add("vinses", temp)
|
||||||
|
_, err := c.decortAPICall("POST", bserviceGroupUpdateVinsAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("parents") {
|
||||||
|
deletedParents := make([]interface{}, 0)
|
||||||
|
addedParents := make([]interface{}, 0)
|
||||||
|
|
||||||
|
old, new := d.GetChange("parents")
|
||||||
|
oldConv := old.([]interface{})
|
||||||
|
newConv := new.([]interface{})
|
||||||
|
for _, el := range oldConv {
|
||||||
|
if !isContainsParent(newConv, el) {
|
||||||
|
deletedParents = append(deletedParents, el)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, el := range newConv {
|
||||||
|
if !isContainsParent(oldConv, el) {
|
||||||
|
addedParents = append(addedParents, el)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(deletedParents) > 0 {
|
||||||
|
for _, parent := range deletedParents {
|
||||||
|
parentConv := parent.(int)
|
||||||
|
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
urlValues.Add("compgroupId", strconv.Itoa(d.Get("compgroup_id").(int)))
|
||||||
|
urlValues.Add("parentId", strconv.Itoa(parentConv))
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", bserviceGroupParentRemoveAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(addedParents) > 0 {
|
||||||
|
for _, parent := range addedParents {
|
||||||
|
parentConv := parent.(int)
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
urlValues.Add("compgroupId", strconv.Itoa(d.Get("compgroup_id").(int)))
|
||||||
|
urlValues.Add("parentId", strconv.Itoa(parentConv))
|
||||||
|
_, err := c.decortAPICall("POST", bserviceGroupParentAddAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("remove_computes") {
|
||||||
|
rcs := d.Get("remove_computes").([]interface{})
|
||||||
|
if len(rcs) > 0 {
|
||||||
|
for _, rc := range rcs {
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
urlValues.Add("compgroupId", strconv.Itoa(d.Get("compgroup_id").(int)))
|
||||||
|
urlValues.Add("computeId", strconv.Itoa(rc.(int)))
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", bserviceGroupComputeRemoveAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isContainsParent(els []interface{}, el interface{}) bool {
|
||||||
|
for _, elOld := range els {
|
||||||
|
elOldConv := elOld.(int)
|
||||||
|
elConv := el.(int)
|
||||||
|
if elOldConv == elConv {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceBasicServiceGroupSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"service_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "ID of the Basic Service to add a group to",
|
||||||
|
},
|
||||||
|
"compgroup_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "name of the Compute Group to add",
|
||||||
|
},
|
||||||
|
"comp_count": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "computes number. Defines how many computes must be there in the group",
|
||||||
|
},
|
||||||
|
"cpu": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "compute CPU number. All computes in the group have the same CPU count",
|
||||||
|
},
|
||||||
|
"ram": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "compute RAM volume in MB. All computes in the group have the same RAM volume",
|
||||||
|
},
|
||||||
|
"disk": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "compute boot disk size in GB",
|
||||||
|
},
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "OS image ID to create computes from",
|
||||||
|
},
|
||||||
|
"driver": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "compute driver like a KVM_X86, KVM_PPC, etc.",
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "group role tag. Can be empty string, does not have to be unique",
|
||||||
|
},
|
||||||
|
"timeout_start": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "time of Compute Group readiness",
|
||||||
|
},
|
||||||
|
"extnets": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
Description: "list of external networks to connect computes to",
|
||||||
|
},
|
||||||
|
"vinses": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
Description: "list of ViNSes to connect computes to",
|
||||||
|
},
|
||||||
|
"mode": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: "RELATIVE",
|
||||||
|
ValidateFunc: validation.StringInSlice([]string{"RELATIVE", "ABSOLUTE"}, false),
|
||||||
|
Description: "(RELATIVE;ABSOLUTE) either delta or absolute value of computes",
|
||||||
|
},
|
||||||
|
"start": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "Start the specified Compute Group within BasicService",
|
||||||
|
},
|
||||||
|
"force_stop": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "force stop Compute Group",
|
||||||
|
},
|
||||||
|
"force_update": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "force resize Compute Group",
|
||||||
|
},
|
||||||
|
"parents": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"remove_computes": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"compgroup_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"computes": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"ip_addresses": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"os_users": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"login": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"consistency": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"created_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"created_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"deleted_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"deleted_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rg_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rg_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"seq_no": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"updated_by": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"updated_time": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceBasicServiceGroup() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceBasicServiceGroupCreate,
|
||||||
|
Read: resourceBasicServiceGroupRead,
|
||||||
|
Update: resourceBasicServiceGroupEdit,
|
||||||
|
Delete: resourceBasicServiceGroupDelete,
|
||||||
|
Exists: resourceBasicServiceGroupExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: resourceBasicServiceGroupSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,434 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/customdiff"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceCDROMImageCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceCDROMImageCreate: called for image %s", d.Get("name").(string))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
urlValues.Add("url", d.Get("url").(string))
|
||||||
|
urlValues.Add("gid", strconv.Itoa(d.Get("gid").(int)))
|
||||||
|
|
||||||
|
tstr := d.Get("drivers").([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(tstr)
|
||||||
|
for i, str := range tstr {
|
||||||
|
s := "\"" + str.(string) + "\""
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ","
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
urlValues.Add("drivers", temp)
|
||||||
|
|
||||||
|
if username, ok := d.GetOk("username"); ok {
|
||||||
|
urlValues.Add("username", username.(string))
|
||||||
|
}
|
||||||
|
if password, ok := d.GetOk("password"); ok {
|
||||||
|
urlValues.Add("password", password.(string))
|
||||||
|
}
|
||||||
|
if accountId, ok := d.GetOk("account_id"); ok {
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(accountId.(int)))
|
||||||
|
}
|
||||||
|
if usernameDL, ok := d.GetOk("username_dl"); ok {
|
||||||
|
urlValues.Add("usernameDL", usernameDL.(string))
|
||||||
|
}
|
||||||
|
if passwordDL, ok := d.GetOk("password_dl"); ok {
|
||||||
|
urlValues.Add("passwordDL", passwordDL.(string))
|
||||||
|
}
|
||||||
|
if sepId, ok := d.GetOk("sep_id"); ok {
|
||||||
|
urlValues.Add("sepId", strconv.Itoa(sepId.(int)))
|
||||||
|
}
|
||||||
|
if poolName, ok := d.GetOk("pool_name"); ok {
|
||||||
|
urlValues.Add("pool_name", poolName.(string))
|
||||||
|
}
|
||||||
|
if architecture, ok := d.GetOk("architecture"); ok {
|
||||||
|
urlValues.Add("architecture", architecture.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
imageId, err := controller.decortAPICall("POST", imageCreateCDROMAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(imageId)
|
||||||
|
d.Set("image_id", imageId)
|
||||||
|
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(strconv.Itoa(image.ImageId))
|
||||||
|
d.Set("bootable", image.Bootable)
|
||||||
|
//d.Set("image_id", image.ImageId)
|
||||||
|
|
||||||
|
err = resourceImageRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceCDROMImageDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceCDROMImageDelete: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if image == nil {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
|
||||||
|
if permanently, ok := d.GetOk("permanently"); ok {
|
||||||
|
urlValues.Add("permanently", strconv.FormatBool(permanently.(bool)))
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = controller.decortAPICall("POST", imageDeleteCDROMAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceCDROMImageSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Name of the rescue disk",
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "URL where to download ISO from",
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "grid (platform) ID where this template should be create in",
|
||||||
|
},
|
||||||
|
"boot_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Boot type of image bios or uefi",
|
||||||
|
},
|
||||||
|
"image_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Image type linux, windows or other",
|
||||||
|
},
|
||||||
|
"drivers": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Required: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "List of types of compute suitable for image. Example: [ \"KVM_X86\" ]",
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "meta",
|
||||||
|
},
|
||||||
|
"hot_resize": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this machine supports hot resize",
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional username for the image",
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional password for the image",
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "AccountId to make the image exclusive",
|
||||||
|
},
|
||||||
|
"username_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "username for upload binary media",
|
||||||
|
},
|
||||||
|
"password_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "password for upload binary media",
|
||||||
|
},
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "storage endpoint provider ID",
|
||||||
|
},
|
||||||
|
"pool_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "pool for image create",
|
||||||
|
},
|
||||||
|
"architecture": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "binary architecture of this image, one of X86_64 of PPC64_LE",
|
||||||
|
},
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image id",
|
||||||
|
},
|
||||||
|
"permanently": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Whether to completely delete the image",
|
||||||
|
},
|
||||||
|
"bootable": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this image boot OS",
|
||||||
|
},
|
||||||
|
"unc_path": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "unc path",
|
||||||
|
},
|
||||||
|
"link_to": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "",
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "status",
|
||||||
|
},
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "tech atatus",
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "version",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image size",
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"computeci_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"provider_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"purge_attempts": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reference_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rescuecd": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"shared_with": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"enabled_stacks": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceCDROMImage() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceCDROMImageCreate,
|
||||||
|
Read: resourceImageRead,
|
||||||
|
Update: resourceImageEdit,
|
||||||
|
Delete: resourceCDROMImageDelete,
|
||||||
|
Exists: resourceImageExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
CustomizeDiff: customdiff.All(
|
||||||
|
customdiff.IfValueChange("enabled", func(old, new, meta interface{}) bool {
|
||||||
|
return old.(bool) != new.(bool)
|
||||||
|
}, resourceImageChangeEnabled),
|
||||||
|
customdiff.IfValueChange("name", func(old, new, meta interface{}) bool {
|
||||||
|
return old.(string) != new.(string) && old.(string) != ""
|
||||||
|
}, resourceImageEditName),
|
||||||
|
customdiff.IfValueChange("shared_with", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.([]interface{})
|
||||||
|
n := new.([]interface{})
|
||||||
|
|
||||||
|
if len(o) != len(n) {
|
||||||
|
return true
|
||||||
|
} else if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
for i, v := range n {
|
||||||
|
if v.(int) == o[i].(int) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count == 0
|
||||||
|
}, resourceImageShare),
|
||||||
|
customdiff.IfValueChange("computeci_id", func(old, new, meta interface{}) bool {
|
||||||
|
return old.(int) != new.(int)
|
||||||
|
}, resourceImageChangeComputeci),
|
||||||
|
customdiff.IfValueChange("enabled_stacks", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.([]interface{})
|
||||||
|
n := new.([]interface{})
|
||||||
|
|
||||||
|
if len(o) != len(n) {
|
||||||
|
return true
|
||||||
|
} else if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
for i, v := range n {
|
||||||
|
if v.(string) == o[i].(string) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count == 0
|
||||||
|
}, resourceImageUpdateNodes),
|
||||||
|
),
|
||||||
|
|
||||||
|
Schema: resourceCDROMImageSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,570 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cloudInitDiffSupperss(key, oldVal, newVal string, d *schema.ResourceData) bool {
|
||||||
|
if oldVal == "" && newVal != "applied" {
|
||||||
|
// if old value for "cloud_init" resource is empty string, it means that we are creating new compute
|
||||||
|
// and there is a chance that the user will want custom cloud init parameters - so we check if
|
||||||
|
// cloud_init is explicitly set in TF file by making sure that its new value is different from "applied",
|
||||||
|
// which is a reserved key word.
|
||||||
|
log.Debugf("cloudInitDiffSupperss: key=%s, oldVal=%q, newVal=%q -> suppress=FALSE", key, oldVal, newVal)
|
||||||
|
return false // there is a difference between stored and new value
|
||||||
|
}
|
||||||
|
log.Debugf("cloudInitDiffSupperss: key=%s, oldVal=%q, newVal=%q -> suppress=TRUE", key, oldVal, newVal)
|
||||||
|
return true // suppress difference
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
// we assume all mandatory parameters it takes to create a comptue instance are properly
|
||||||
|
// specified - we rely on schema "Required" attributes to let Terraform validate them for us
|
||||||
|
|
||||||
|
log.Debugf("resourceComputeCreate: called for Compute name %q, RG ID %d", d.Get("name").(string), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
// create basic Compute (i.e. without extra disks and network connections - those will be attached
|
||||||
|
// by subsequent individual API calls).
|
||||||
|
// creating Compute is a multi-step workflow, which may fail at some step, so we use "partial" feature of Terraform
|
||||||
|
d.Partial(true)
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("rgId", fmt.Sprintf("%d", d.Get("rg_id").(int)))
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
urlValues.Add("cpu", fmt.Sprintf("%d", d.Get("cpu").(int)))
|
||||||
|
urlValues.Add("ram", fmt.Sprintf("%d", d.Get("ram").(int)))
|
||||||
|
urlValues.Add("imageId", fmt.Sprintf("%d", d.Get("image_id").(int)))
|
||||||
|
urlValues.Add("bootDisk", fmt.Sprintf("%d", d.Get("boot_disk_size").(int)))
|
||||||
|
urlValues.Add("netType", "NONE") // at the 1st step create isolated compute
|
||||||
|
urlValues.Add("start", "0") // at the 1st step create compute in a stopped state
|
||||||
|
|
||||||
|
argVal, argSet := d.GetOk("description")
|
||||||
|
if argSet {
|
||||||
|
urlValues.Add("desc", argVal.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
if sepID, ok := d.GetOk("sep_id"); ok {
|
||||||
|
urlValues.Add("sepId", strconv.Itoa(sepID.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if pool, ok := d.GetOk("pool"); ok {
|
||||||
|
urlValues.Add("pool", pool.(string))
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
sshKeysVal, sshKeysSet := d.GetOk("ssh_keys")
|
||||||
|
if sshKeysSet {
|
||||||
|
// process SSH Key settings and set API values accordingly
|
||||||
|
log.Debugf("resourceComputeCreate: calling makeSshKeysArgString to setup SSH keys for guest login(s)")
|
||||||
|
urlValues.Add("userdata", makeSshKeysArgString(sshKeysVal.([]interface{})))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
computeCreateAPI := KvmX86CreateAPI
|
||||||
|
driver := d.Get("driver").(string)
|
||||||
|
if driver == "KVM_PPC" {
|
||||||
|
computeCreateAPI = KvmPPCCreateAPI
|
||||||
|
log.Debugf("resourceComputeCreate: creating Compute of type KVM VM PowerPC")
|
||||||
|
} else { // note that we do not validate arch value for explicit "KVM_X86" here
|
||||||
|
log.Debugf("resourceComputeCreate: creating Compute of type KVM VM x86")
|
||||||
|
}
|
||||||
|
|
||||||
|
argVal, argSet = d.GetOk("cloud_init")
|
||||||
|
if argSet {
|
||||||
|
// userdata must not be empty string and must not be a reserved keyword "applied"
|
||||||
|
userdata := argVal.(string)
|
||||||
|
if userdata != "" && userdata != "applied" {
|
||||||
|
urlValues.Add("userdata", userdata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apiResp, err := controller.decortAPICall("POST", computeCreateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Compute create API returns ID of the new Compute instance on success
|
||||||
|
|
||||||
|
d.SetId(apiResp) // update ID of the resource to tell Terraform that the resource exists, albeit partially
|
||||||
|
compId, _ := strconv.Atoi(apiResp)
|
||||||
|
d.SetPartial("name")
|
||||||
|
d.SetPartial("description")
|
||||||
|
d.SetPartial("cpu")
|
||||||
|
d.SetPartial("ram")
|
||||||
|
d.SetPartial("image_id")
|
||||||
|
d.SetPartial("boot_disk_size")
|
||||||
|
/*
|
||||||
|
if sshKeysSet {
|
||||||
|
d.SetPartial("ssh_keys")
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
log.Debugf("resourceComputeCreate: new simple Compute ID %d, name %s created", compId, d.Get("name").(string))
|
||||||
|
|
||||||
|
// Configure data disks if any
|
||||||
|
extraDisksOk := true
|
||||||
|
argVal, argSet = d.GetOk("extra_disks")
|
||||||
|
if argSet && argVal.(*schema.Set).Len() > 0 {
|
||||||
|
// urlValues.Add("desc", argVal.(string))
|
||||||
|
log.Debugf("resourceComputeCreate: calling utilityComputeExtraDisksConfigure to attach %d extra disk(s)", argVal.(*schema.Set).Len())
|
||||||
|
err = controller.utilityComputeExtraDisksConfigure(d, false) // do_delta=false, as we are working on a new compute
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("resourceComputeCreate: error when attaching extra disk(s) to a new Compute ID %d: %v", compId, err)
|
||||||
|
extraDisksOk = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if extraDisksOk {
|
||||||
|
d.SetPartial("extra_disks")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure external networks if any
|
||||||
|
netsOk := true
|
||||||
|
argVal, argSet = d.GetOk("network")
|
||||||
|
if argSet && argVal.(*schema.Set).Len() > 0 {
|
||||||
|
log.Debugf("resourceComputeCreate: calling utilityComputeNetworksConfigure to attach %d network(s)", argVal.(*schema.Set).Len())
|
||||||
|
err = controller.utilityComputeNetworksConfigure(d, false) // do_delta=false, as we are working on a new compute
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("resourceComputeCreate: error when attaching networks to a new Compute ID %d: %s", compId, err)
|
||||||
|
netsOk = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if netsOk {
|
||||||
|
// there were no errors reported when configuring networks
|
||||||
|
d.SetPartial("network")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extraDisksOk && netsOk {
|
||||||
|
// if there were no errors in setting any of the subresources, we may leave Partial mode
|
||||||
|
d.Partial(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note bene: we created compute in a STOPPED state (this is required to properly attach 1st network interface),
|
||||||
|
// now we need to start it before we report the sequence complete
|
||||||
|
if d.Get("started").(bool) {
|
||||||
|
reqValues := &url.Values{}
|
||||||
|
reqValues.Add("computeId", fmt.Sprintf("%d", compId))
|
||||||
|
log.Debugf("resourceComputeCreate: starting Compute ID %d after completing its resource configuration", compId)
|
||||||
|
if _, err := controller.decortAPICall("POST", ComputeStartAPI, reqValues); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("resourceComputeCreate: new Compute ID %d, name %s creation sequence complete", compId, d.Get("name").(string))
|
||||||
|
|
||||||
|
// We may reuse dataSourceComputeRead here as we maintain similarity
|
||||||
|
// between Compute resource and Compute data source schemas
|
||||||
|
// Compute read function will also update resource ID on success, so that Terraform
|
||||||
|
// will know the resource exists
|
||||||
|
return dataSourceComputeRead(d, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceComputeRead: called for Compute name %s, RG ID %d",
|
||||||
|
d.Get("name").(string), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
compFacts, err := utilityComputeCheckPresence(d, m)
|
||||||
|
if compFacts == "" {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Compute with such name and RG ID was not found
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = flattenCompute(d, compFacts); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("resourceComputeRead: after flattenCompute: Compute ID %s, name %q, RG ID %d",
|
||||||
|
d.Id(), d.Get("name").(string), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceComputeUpdate: called for Compute ID %s / name %s, RGID %d",
|
||||||
|
d.Id(), d.Get("name").(string), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Resize CPU/RAM
|
||||||
|
2. Resize (grow) boot disk
|
||||||
|
3. Update extra disks
|
||||||
|
4. Update networks
|
||||||
|
5. Start/stop
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 1. Resize CPU/RAM
|
||||||
|
params := &url.Values{}
|
||||||
|
doUpdate := false
|
||||||
|
params.Add("computeId", d.Id())
|
||||||
|
|
||||||
|
d.Partial(true)
|
||||||
|
|
||||||
|
oldCpu, newCpu := d.GetChange("cpu")
|
||||||
|
if oldCpu.(int) != newCpu.(int) {
|
||||||
|
params.Add("cpu", fmt.Sprintf("%d", newCpu.(int)))
|
||||||
|
doUpdate = true
|
||||||
|
} else {
|
||||||
|
params.Add("cpu", "0") // no change to CPU allocation
|
||||||
|
}
|
||||||
|
|
||||||
|
oldRam, newRam := d.GetChange("ram")
|
||||||
|
if oldRam.(int) != newRam.(int) {
|
||||||
|
params.Add("ram", fmt.Sprintf("%d", newRam.(int)))
|
||||||
|
doUpdate = true
|
||||||
|
} else {
|
||||||
|
params.Add("ram", "0")
|
||||||
|
}
|
||||||
|
|
||||||
|
if doUpdate {
|
||||||
|
log.Debugf("resourceComputeUpdate: changing CPU %d -> %d and/or RAM %d -> %d",
|
||||||
|
oldCpu.(int), newCpu.(int),
|
||||||
|
oldRam.(int), newRam.(int))
|
||||||
|
params.Add("force", "true")
|
||||||
|
_, err := controller.decortAPICall("POST", ComputeResizeAPI, params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetPartial("cpu")
|
||||||
|
d.SetPartial("ram")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Resize (grow) Boot disk
|
||||||
|
oldSize, newSize := d.GetChange("boot_disk_size")
|
||||||
|
if oldSize.(int) < newSize.(int) {
|
||||||
|
bdsParams := &url.Values{}
|
||||||
|
bdsParams.Add("diskId", fmt.Sprintf("%d", d.Get("boot_disk_id").(int)))
|
||||||
|
bdsParams.Add("size", fmt.Sprintf("%d", newSize.(int)))
|
||||||
|
log.Debugf("resourceComputeUpdate: compute ID %s, boot disk ID %d resize %d -> %d",
|
||||||
|
d.Id(), d.Get("boot_disk_id").(int), oldSize.(int), newSize.(int))
|
||||||
|
_, err := controller.decortAPICall("POST", DisksResizeAPI, bdsParams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetPartial("boot_disk_size")
|
||||||
|
} else if oldSize.(int) > newSize.(int) {
|
||||||
|
log.Warnf("resourceComputeUpdate: compute ID %s - shrinking boot disk is not allowed", d.Id())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Calculate and apply changes to data disks
|
||||||
|
err := controller.utilityComputeExtraDisksConfigure(d, true) // pass do_delta = true to apply changes, if any
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
d.SetPartial("extra_disks")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Calculate and apply changes to network connections
|
||||||
|
err = controller.utilityComputeNetworksConfigure(d, true) // pass do_delta = true to apply changes, if any
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
d.SetPartial("network")
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("started") {
|
||||||
|
params := &url.Values{}
|
||||||
|
params.Add("computeId", d.Id())
|
||||||
|
if d.Get("started").(bool) {
|
||||||
|
if _, err := controller.decortAPICall("POST", ComputeStartAPI, params); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err := controller.decortAPICall("POST", ComputeStopAPI, params); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.SetPartial("started")
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Partial(false)
|
||||||
|
|
||||||
|
// we may reuse dataSourceComputeRead here as we maintain similarity
|
||||||
|
// between Compute resource and Compute data source schemas
|
||||||
|
return dataSourceComputeRead(d, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
// NOTE: this function destroys target Compute instance "permanently", so
|
||||||
|
// there is no way to restore it.
|
||||||
|
// If compute being destroyed has some extra disks attached, they are
|
||||||
|
// detached from the compute
|
||||||
|
log.Debugf("resourceComputeDelete: called for Compute name %s, RG ID %d",
|
||||||
|
d.Get("name").(string), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
compFacts, err := utilityComputeCheckPresence(d, m)
|
||||||
|
if compFacts == "" {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// the target Compute does not exist - in this case according to Terraform best practice
|
||||||
|
// we exit from Destroy method without error
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
|
||||||
|
model := ComputeGetResp{}
|
||||||
|
log.Debugf("resourceComputeDelete: ready to unmarshal string %s", compFacts)
|
||||||
|
err = json.Unmarshal([]byte(compFacts), &model)
|
||||||
|
if err == nil && len(model.Disks) > 0 {
|
||||||
|
// prepare to detach data disks from compute - do it only if compFacts unmarshalled
|
||||||
|
// properly and the resulting model contains non-empty Disks list
|
||||||
|
for _, diskFacts := range model.Disks {
|
||||||
|
if diskFacts.Type == "B" {
|
||||||
|
// boot disk is never detached on compute delete
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("resourceComputeDelete: ready to detach data disk ID %d from compute ID %s", diskFacts.ID, d.Id())
|
||||||
|
|
||||||
|
detachParams := &url.Values{}
|
||||||
|
detachParams.Add("computeId", d.Id())
|
||||||
|
detachParams.Add("diskId", fmt.Sprintf("%d", diskFacts.ID))
|
||||||
|
|
||||||
|
_, err = controller.decortAPICall("POST", ComputeDiskDetachAPI, detachParams)
|
||||||
|
if err != nil {
|
||||||
|
// We do not fail compute deletion on data disk detach errors
|
||||||
|
log.Errorf("resourceComputeDelete: error when detaching Disk ID %d: %s", diskFacts.ID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
params := &url.Values{}
|
||||||
|
params.Add("computeId", d.Id())
|
||||||
|
params.Add("permanently", "1")
|
||||||
|
// TODO: this is for the upcoming API update - params.Add("detachdisks", "1")
|
||||||
|
|
||||||
|
_, err = controller.decortAPICall("POST", ComputeDeleteAPI, params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
// Reminder: according to Terraform rules, this function should not modify its ResourceData argument
|
||||||
|
log.Debugf("resourceComputeExist: called for Compute name %s, RG ID %d",
|
||||||
|
d.Get("name").(string), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
compFacts, err := utilityComputeCheckPresence(d, m)
|
||||||
|
if compFacts == "" {
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceCompute() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceComputeCreate,
|
||||||
|
Read: resourceComputeRead,
|
||||||
|
Update: resourceComputeUpdate,
|
||||||
|
Delete: resourceComputeDelete,
|
||||||
|
Exists: resourceComputeExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout180s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout180s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Name of this compute. Compute names are case sensitive and must be unique in the resource group.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"rg_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.IntAtLeast(1),
|
||||||
|
Description: "ID of the resource group where this compute should be deployed.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"driver": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
StateFunc: stateFuncToUpper,
|
||||||
|
ValidateFunc: validation.StringInSlice([]string{"KVM_X86", "KVM_PPC"}, false), // observe case while validating
|
||||||
|
Description: "Hardware architecture of this compute instance.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"cpu": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.IntBetween(1, MaxCpusPerCompute),
|
||||||
|
Description: "Number of CPUs to allocate to this compute instance.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ram": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.IntAtLeast(MinRamPerCompute),
|
||||||
|
Description: "Amount of RAM in MB to allocate to this compute instance.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
ValidateFunc: validation.IntAtLeast(1),
|
||||||
|
Description: "ID of the OS image to base this compute instance on.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"boot_disk_size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "This compute instance boot disk size in GB. Make sure it is large enough to accomodate selected OS image.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "ID of SEP to create bootDisk on. Uses image's sepId if not set.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"pool": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "Pool to use if sepId is set, can be also empty if needed to be chosen by system.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"extra_disks": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
MaxItems: MaxExtraDisksPerCompute,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
Description: "Optional list of IDs of extra disks to attach to this compute. You may specify several extra disks.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"network": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
MaxItems: MaxNetworksPerCompute,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: networkSubresourceSchemaMake(),
|
||||||
|
},
|
||||||
|
Description: "Optional network connection(s) for this compute. You may specify several network blocks, one for each connection.",
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
"ssh_keys": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
MaxItems: MaxSshKeysPerCompute,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: sshSubresourceSchemaMake(),
|
||||||
|
},
|
||||||
|
Description: "SSH keys to authorize on this compute instance.",
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
|
"description": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Optional text description of this compute instance.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"cloud_init": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: "applied",
|
||||||
|
DiffSuppressFunc: cloudInitDiffSupperss,
|
||||||
|
Description: "Optional cloud_init parameters. Applied when creating new compute instance only, ignored in all other cases.",
|
||||||
|
},
|
||||||
|
|
||||||
|
// The rest are Compute properties, which are "computed" once it is created
|
||||||
|
"rg_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Name of the resource group where this compute instance is located.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "ID of the account this compute instance belongs to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Name of the account this compute instance belongs to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"boot_disk_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "This compute instance boot disk ID.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"os_users": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: osUsersSubresourceSchemaMake(),
|
||||||
|
},
|
||||||
|
Description: "Guest OS users provisioned on this compute instance.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"started": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: true,
|
||||||
|
Description: "Is compute started.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceCreateListImages(d *schema.ResourceData, m interface{}) error {
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceDeleteListImages(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceDeleteListImages: start deleting...")
|
||||||
|
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
imageIds := d.Get("image_ids").([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(imageIds)
|
||||||
|
for i, imageId := range imageIds {
|
||||||
|
s := strconv.Itoa(imageId.(int))
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ",\n"
|
||||||
|
} else {
|
||||||
|
s += "\n"
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
|
||||||
|
urlValues.Add("reason", d.Get("reason").(string))
|
||||||
|
urlValues.Add("permanently", strconv.FormatBool(d.Get("permanently").(bool)))
|
||||||
|
urlValues.Add("imageIds", temp)
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", imageDeleteImagesAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceReadListImages(d *schema.ResourceData, m interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceDeleteImagesSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"image_ids": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
MinItems: 1,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
Description: "images ids for deleting",
|
||||||
|
},
|
||||||
|
"reason": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "reason for deleting the images",
|
||||||
|
},
|
||||||
|
"permanently": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "whether to completely delete the images",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceDeleteImages() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceCreateListImages,
|
||||||
|
Read: resourceReadListImages,
|
||||||
|
Delete: resourceDeleteListImages,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: resourceDeleteImagesSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,332 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceDiskCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceDiskCreate: called for Disk name %q, Account ID %d", d.Get("name").(string), d.Get("account_id").(int))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
// accountId, gid, name, description, size, type, sep_id, pool
|
||||||
|
urlValues.Add("accountId", fmt.Sprintf("%d", d.Get("account_id").(int)))
|
||||||
|
urlValues.Add("gid", fmt.Sprintf("%d", DefaultGridID)) // we use default Grid ID, which was obtained along with DECORT Controller init
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
urlValues.Add("size", fmt.Sprintf("%d", d.Get("size").(int)))
|
||||||
|
urlValues.Add("type", "D") // NOTE: only disks of Data type are managed via plugin
|
||||||
|
|
||||||
|
if sepId, ok := d.GetOk("sep_id"); ok {
|
||||||
|
urlValues.Add("sep_id", strconv.Itoa(sepId.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if poolName, ok := d.GetOk("pool"); ok {
|
||||||
|
urlValues.Add("pool", poolName.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
argVal, argSet := d.GetOk("description")
|
||||||
|
if argSet {
|
||||||
|
urlValues.Add("description", argVal.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
apiResp, err := controller.decortAPICall("POST", DisksCreateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(apiResp) // update ID of the resource to tell Terraform that the disk resource exists
|
||||||
|
diskId, _ := strconv.Atoi(apiResp)
|
||||||
|
|
||||||
|
log.Debugf("resourceDiskCreate: new Disk ID / name %d / %s creation sequence complete", diskId, d.Get("name").(string))
|
||||||
|
|
||||||
|
// We may reuse dataSourceDiskRead here as we maintain similarity
|
||||||
|
// between Disk resource and Disk data source schemas
|
||||||
|
// Disk resource read function will also update resource ID on success, so that Terraform
|
||||||
|
// will know the resource exists (however, we already did it a few lines before)
|
||||||
|
return dataSourceDiskRead(d, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceDiskRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
diskFacts, err := utilityDiskCheckPresence(d, m)
|
||||||
|
if diskFacts == "" {
|
||||||
|
// if empty string is returned from utilityDiskCheckPresence then there is no
|
||||||
|
// such Disk and err tells so - just return it to the calling party
|
||||||
|
d.SetId("") // ensure ID is empty
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return flattenDisk(d, diskFacts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceDiskUpdate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
// Update will only change the following attributes of the disk:
|
||||||
|
// - Size; to keep data safe, shrinking disk is not allowed.
|
||||||
|
// - Name
|
||||||
|
//
|
||||||
|
// Attempt to change disk type will throw an error and mark disk
|
||||||
|
// resource as partially updated
|
||||||
|
log.Debugf("resourceDiskUpdate: called for Disk ID / name %s / %s, Account ID %d",
|
||||||
|
d.Id(), d.Get("name").(string), d.Get("account_id").(int))
|
||||||
|
|
||||||
|
d.Partial(true)
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
|
||||||
|
oldSize, newSize := d.GetChange("size")
|
||||||
|
if oldSize.(int) < newSize.(int) {
|
||||||
|
log.Debugf("resourceDiskUpdate: resizing disk ID %s - %d GB -> %d GB",
|
||||||
|
d.Id(), oldSize.(int), newSize.(int))
|
||||||
|
sizeParams := &url.Values{}
|
||||||
|
sizeParams.Add("diskId", d.Id())
|
||||||
|
sizeParams.Add("size", fmt.Sprintf("%d", newSize.(int)))
|
||||||
|
_, err := controller.decortAPICall("POST", DisksResizeAPI, sizeParams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetPartial("size")
|
||||||
|
} else if oldSize.(int) > newSize.(int) {
|
||||||
|
return fmt.Errorf("resourceDiskUpdate: Disk ID %s - reducing disk size is not allowed", d.Id())
|
||||||
|
}
|
||||||
|
|
||||||
|
oldName, newName := d.GetChange("name")
|
||||||
|
if oldName.(string) != newName.(string) {
|
||||||
|
log.Debugf("resourceDiskUpdate: renaming disk ID %d - %s -> %s",
|
||||||
|
d.Get("disk_id").(int), oldName.(string), newName.(string))
|
||||||
|
renameParams := &url.Values{}
|
||||||
|
renameParams.Add("diskId", d.Id())
|
||||||
|
renameParams.Add("name", newName.(string))
|
||||||
|
_, err := controller.decortAPICall("POST", DisksRenameAPI, renameParams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetPartial("name")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOTE: plugin will manage disks of type "Data" only, and type cannot be changed once disk is created
|
||||||
|
|
||||||
|
oldType, newType := d.GetChange("type")
|
||||||
|
if oldType.(string) != newType.(string) {
|
||||||
|
return fmt.Errorf("resourceDiskUpdate: Disk ID %s - changing type of existing disk not allowed", d.Id())
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
d.Partial(false)
|
||||||
|
|
||||||
|
// we may reuse dataSourceDiskRead here as we maintain similarity
|
||||||
|
// between Compute resource and Compute data source schemas
|
||||||
|
return dataSourceDiskRead(d, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceDiskDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
// NOTE: this function tries to detach and destroy target Disk "permanently", so
|
||||||
|
// there is no way to restore it.
|
||||||
|
// If, however, the disk is attached to a compute, the method will
|
||||||
|
// fail (by failing the underpinning DECORt API call, which is issued with detach=false)
|
||||||
|
log.Debugf("resourceDiskDelete: called for Disk ID / name %d / %s, Account ID %d",
|
||||||
|
d.Get("disk_id").(int), d.Get("name").(string), d.Get("account_id").(int))
|
||||||
|
|
||||||
|
diskFacts, err := utilityDiskCheckPresence(d, m)
|
||||||
|
if diskFacts == "" {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// the specified Disk does not exist - in this case according to Terraform best practice
|
||||||
|
// we exit from Destroy method without error
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
params := &url.Values{}
|
||||||
|
params.Add("diskId", d.Id())
|
||||||
|
// NOTE: we are not force-detaching disk from a compute (if attached) thus protecting
|
||||||
|
// data that may be on that disk from destruction.
|
||||||
|
// However, this may change in the future, as TF state management logic may want
|
||||||
|
// to delete disk resource BEFORE it is detached from compute instance, and, while
|
||||||
|
// perfectly OK from data preservation viewpoint, this is breaking expected TF workflow
|
||||||
|
// in the eyes of an experienced TF user
|
||||||
|
params.Add("detach", "0")
|
||||||
|
params.Add("permanently", "1")
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
_, err = controller.decortAPICall("POST", DisksDeleteAPI, params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceDiskExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
// Reminder: according to Terraform rules, this function should not modify its ResourceData argument
|
||||||
|
log.Debugf("resourceDiskExists: called for Disk ID / name %d / %s, Account ID %d",
|
||||||
|
d.Get("disk_id").(int), d.Get("name").(string), d.Get("account_id").(int))
|
||||||
|
|
||||||
|
diskFacts, err := utilityDiskCheckPresence(d, m)
|
||||||
|
if diskFacts == "" {
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceDiskSchemaMake() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Name of this disk. NOTE: disk names are NOT unique within an account. If disk ID is specified, disk name is ignored.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"disk_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "ID of the disk to get. If disk ID is specified, then disk name and account ID are ignored.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "ID of the account this disk belongs to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "Storage end-point provider serving this disk. Cannot be changed for existing disk.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"pool": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "Pool where this disk is located. Cannot be changed for existing disk.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.IntAtLeast(1),
|
||||||
|
Description: "Size of the disk in GB. Note, that existing disks can only be grown in size.",
|
||||||
|
},
|
||||||
|
|
||||||
|
/* We moved "type" attribute to computed attributes section, as plugin manages disks of only
|
||||||
|
one type - "D", e.g. data disks.
|
||||||
|
"type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: "D",
|
||||||
|
StateFunc: stateFuncToUpper,
|
||||||
|
ValidateFunc: validation.StringInSlice([]string{"B", "D"}, false),
|
||||||
|
Description: "Optional type of this disk. Defaults to D, i.e. data disk. Cannot be changed for existing disks.",
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
|
"description": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: "Disk resource managed by Terraform",
|
||||||
|
Description: "Optional user-defined text description of this disk.",
|
||||||
|
},
|
||||||
|
|
||||||
|
// The rest of the attributes are all computed
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Name of the account this disk belongs to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "ID of the image, which this disk was cloned from (if ever cloned).",
|
||||||
|
},
|
||||||
|
|
||||||
|
"type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Type of this disk.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"sep_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Type of the storage end-point provider serving this disk.",
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
"snapshots": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource {
|
||||||
|
Schema: snapshotSubresourceSchemaMake(),
|
||||||
|
},
|
||||||
|
Description: "List of user-created snapshots for this disk."
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceDisk() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceDiskCreate,
|
||||||
|
Read: resourceDiskRead,
|
||||||
|
Update: resourceDiskUpdate,
|
||||||
|
Delete: resourceDiskDelete,
|
||||||
|
Exists: resourceDiskExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout180s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout180s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: resourceDiskSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,722 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/customdiff"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceImageCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageCreate: called for image %s", d.Get("name").(string))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
urlValues.Add("url", d.Get("url").(string))
|
||||||
|
urlValues.Add("gid", strconv.Itoa(d.Get("gid").(int)))
|
||||||
|
urlValues.Add("boottype", d.Get("boot_type").(string))
|
||||||
|
urlValues.Add("imagetype", d.Get("image_type").(string))
|
||||||
|
|
||||||
|
tstr := d.Get("drivers").([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(tstr)
|
||||||
|
for i, str := range tstr {
|
||||||
|
s := "\"" + str.(string) + "\""
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ","
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
urlValues.Add("drivers", temp)
|
||||||
|
|
||||||
|
if hotresize, ok := d.GetOk("hot_resize"); ok {
|
||||||
|
urlValues.Add("hotresize", strconv.FormatBool(hotresize.(bool)))
|
||||||
|
}
|
||||||
|
if username, ok := d.GetOk("username"); ok {
|
||||||
|
urlValues.Add("username", username.(string))
|
||||||
|
}
|
||||||
|
if password, ok := d.GetOk("password"); ok {
|
||||||
|
urlValues.Add("password", password.(string))
|
||||||
|
}
|
||||||
|
if accountId, ok := d.GetOk("account_id"); ok {
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(accountId.(int)))
|
||||||
|
}
|
||||||
|
if usernameDL, ok := d.GetOk("username_dl"); ok {
|
||||||
|
urlValues.Add("usernameDL", usernameDL.(string))
|
||||||
|
}
|
||||||
|
if passwordDL, ok := d.GetOk("password_dl"); ok {
|
||||||
|
urlValues.Add("passwordDL", passwordDL.(string))
|
||||||
|
}
|
||||||
|
if sepId, ok := d.GetOk("sep_id"); ok {
|
||||||
|
urlValues.Add("sepId", strconv.Itoa(sepId.(int)))
|
||||||
|
}
|
||||||
|
if poolName, ok := d.GetOk("pool_name"); ok {
|
||||||
|
urlValues.Add("poolName", poolName.(string))
|
||||||
|
}
|
||||||
|
if architecture, ok := d.GetOk("architecture"); ok {
|
||||||
|
urlValues.Add("architecture", architecture.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
api := ""
|
||||||
|
if isSync := d.Get("sync").(bool); !isSync {
|
||||||
|
api = imageCreateAPI
|
||||||
|
} else {
|
||||||
|
api = imageSyncCreateAPI
|
||||||
|
}
|
||||||
|
imageId, err := controller.decortAPICall("POST", api, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(imageId)
|
||||||
|
d.Set("image_id", imageId)
|
||||||
|
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(strconv.Itoa(image.ImageId))
|
||||||
|
d.Set("bootable", image.Bootable)
|
||||||
|
//d.Set("image_id", image.ImageId)
|
||||||
|
|
||||||
|
err = resourceImageRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageRead: called for %s id: %s", d.Get("name").(string), d.Id())
|
||||||
|
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if image == nil {
|
||||||
|
d.SetId("")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("name", image.Name)
|
||||||
|
d.Set("drivers", image.Drivers)
|
||||||
|
d.Set("url", image.Url)
|
||||||
|
d.Set("gid", image.Gid)
|
||||||
|
d.Set("image_id", image.ImageId)
|
||||||
|
d.Set("boot_type", image.Boottype)
|
||||||
|
d.Set("image_type", image.Imagetype)
|
||||||
|
d.Set("bootable", image.Bootable)
|
||||||
|
d.Set("sep_id", image.SepId)
|
||||||
|
d.Set("unc_path", image.UNCPath)
|
||||||
|
d.Set("link_to", image.LinkTo)
|
||||||
|
d.Set("status", image.Status)
|
||||||
|
d.Set("tech_status", image.TechStatus)
|
||||||
|
d.Set("version", image.Version)
|
||||||
|
d.Set("size", image.Size)
|
||||||
|
d.Set("enabled", image.Enabled)
|
||||||
|
d.Set("computeci_id", image.ComputeciId)
|
||||||
|
d.Set("pool_name", image.PoolName)
|
||||||
|
d.Set("username", image.Username)
|
||||||
|
d.Set("username_dl", image.UsernameDL)
|
||||||
|
d.Set("password", image.Password)
|
||||||
|
d.Set("password_dl", image.PasswordDL)
|
||||||
|
d.Set("account_id", image.AccountId)
|
||||||
|
d.Set("guid", image.Guid)
|
||||||
|
d.Set("milestones", image.Milestones)
|
||||||
|
d.Set("provider_name", image.ProviderName)
|
||||||
|
d.Set("purge_attempts", image.PurgeAttempts)
|
||||||
|
d.Set("reference_id", image.ReferenceId)
|
||||||
|
d.Set("res_id", image.ResId)
|
||||||
|
d.Set("res_name", image.ResName)
|
||||||
|
d.Set("rescuecd", image.Rescuecd)
|
||||||
|
d.Set("architecture", image.Architecture)
|
||||||
|
d.Set("meta", flattenMeta(image.Meta))
|
||||||
|
d.Set("hot_resize", image.Hotresize)
|
||||||
|
d.Set("history", flattenHistory(image.History))
|
||||||
|
d.Set("last_modified", image.LastModified)
|
||||||
|
d.Set("desc", image.Desc)
|
||||||
|
d.Set("shared_with", image.SharedWith)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageDelete: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if image == nil {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
if reason, ok := d.GetOk("reason"); ok {
|
||||||
|
urlValues.Add("reason", reason.(string))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("reason", "")
|
||||||
|
}
|
||||||
|
if permanently, ok := d.GetOk("permanently"); ok {
|
||||||
|
urlValues.Add("permanently", strconv.FormatBool(permanently.(bool)))
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = controller.decortAPICall("POST", imageDeleteAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
log.Debugf("resourceImageExists: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if image == nil {
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageEditName(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageEditName: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
_, err := c.decortAPICall("POST", imageEditNameAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageEdit(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageEdit: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
|
||||||
|
urlValues.Add("username", d.Get("username").(string))
|
||||||
|
urlValues.Add("password", d.Get("password").(string))
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
urlValues.Add("bootable", strconv.FormatBool(d.Get("bootable").(bool)))
|
||||||
|
urlValues.Add("hotresize", strconv.FormatBool(d.Get("hot_resize").(bool)))
|
||||||
|
|
||||||
|
//_, err := c.decortAPICall("POST", imageEditAPI, urlValues)
|
||||||
|
_, err := c.decortAPICall("POST", imageEditAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
err = resourceImageRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = resourceImageRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageChangeEnabled(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
var api string
|
||||||
|
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
if d.Get("enabled").(bool) {
|
||||||
|
api = imageEnableAPI
|
||||||
|
} else {
|
||||||
|
api = imageDisableAPI
|
||||||
|
}
|
||||||
|
resp, err := c.decortAPICall("POST", api, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res, err := strconv.ParseBool(resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !res {
|
||||||
|
return errors.New("Cannot enable/disable")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageLink(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
log.Debugf("resourceVirtualImageLink: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
urlValues.Add("targetId", strconv.Itoa(d.Get("link_to").(int)))
|
||||||
|
_, err := c.decortAPICall("POST", imageLinkAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageShare(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageShare: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
accIds := d.Get("shared_with").([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(accIds)
|
||||||
|
for i, accId := range accIds {
|
||||||
|
s := strconv.Itoa(accId.(int))
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ",\n"
|
||||||
|
} else {
|
||||||
|
s += "\n"
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
urlValues.Add("accounts", temp)
|
||||||
|
_, err := c.decortAPICall("POST", imageShareAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageChangeComputeci(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
computeci := d.Get("computeci_id").(int)
|
||||||
|
|
||||||
|
api := ""
|
||||||
|
|
||||||
|
if computeci == 0 {
|
||||||
|
api = imageComputeciUnsetAPI
|
||||||
|
} else {
|
||||||
|
urlValues.Add("computeciId", strconv.Itoa(computeci))
|
||||||
|
api = imageComputeciSetAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", api, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageUpdateNodes(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageUpdateNodes: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("imageId", strconv.Itoa(d.Get("image_id").(int)))
|
||||||
|
enabledStacks := d.Get("enabled_stacks").([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(enabledStacks)
|
||||||
|
for i, stackId := range enabledStacks {
|
||||||
|
s := stackId.(string)
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ","
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
urlValues.Add("enabledStacks", temp)
|
||||||
|
_, err := c.decortAPICall("POST", imageUpdateNodesAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImageSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Name of the rescue disk",
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "URL where to download media from",
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "grid (platform) ID where this template should be create in",
|
||||||
|
},
|
||||||
|
"boot_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Boot type of image bios or uefi",
|
||||||
|
},
|
||||||
|
"image_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Image type linux, windows or other",
|
||||||
|
},
|
||||||
|
"drivers": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Required: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "List of types of compute suitable for image. Example: [ \"KVM_X86\" ]",
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "meta",
|
||||||
|
},
|
||||||
|
"hot_resize": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this machine supports hot resize",
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional username for the image",
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional password for the image",
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "AccountId to make the image exclusive",
|
||||||
|
},
|
||||||
|
"username_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "username for upload binary media",
|
||||||
|
},
|
||||||
|
"password_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "password for upload binary media",
|
||||||
|
},
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "storage endpoint provider ID",
|
||||||
|
},
|
||||||
|
"pool_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "pool for image create",
|
||||||
|
},
|
||||||
|
"architecture": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "binary architecture of this image, one of X86_64 of PPC64_LE",
|
||||||
|
},
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image id",
|
||||||
|
},
|
||||||
|
"permanently": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Whether to completely delete the image",
|
||||||
|
},
|
||||||
|
"bootable": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this image boot OS",
|
||||||
|
},
|
||||||
|
"unc_path": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "unc path",
|
||||||
|
},
|
||||||
|
"link_to": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "",
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "status",
|
||||||
|
},
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "tech atatus",
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "version",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image size",
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"computeci_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"provider_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"purge_attempts": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reference_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rescuecd": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reason": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"last_modified": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"shared_with": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sync": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "Create image from a media identified by URL (in synchronous mode)",
|
||||||
|
},
|
||||||
|
"enabled_stacks": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceImage() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceImageCreate,
|
||||||
|
Read: resourceImageRead,
|
||||||
|
Update: resourceImageEdit,
|
||||||
|
Delete: resourceImageDelete,
|
||||||
|
Exists: resourceImageExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
CustomizeDiff: customdiff.All(
|
||||||
|
customdiff.IfValueChange("enabled", func(old, new, meta interface{}) bool {
|
||||||
|
return old.(bool) != new.(bool)
|
||||||
|
}, resourceImageChangeEnabled),
|
||||||
|
customdiff.IfValueChange("name", func(old, new, meta interface{}) bool {
|
||||||
|
return old.(string) != new.(string) && old.(string) != ""
|
||||||
|
}, resourceImageEditName),
|
||||||
|
customdiff.IfValueChange("shared_with", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.([]interface{})
|
||||||
|
n := new.([]interface{})
|
||||||
|
|
||||||
|
if len(o) != len(n) {
|
||||||
|
return true
|
||||||
|
} else if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
for i, v := range n {
|
||||||
|
if v.(int) == o[i].(int) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count == 0
|
||||||
|
}, resourceImageShare),
|
||||||
|
customdiff.IfValueChange("computeci_id", func(old, new, meta interface{}) bool {
|
||||||
|
return old.(int) != new.(int)
|
||||||
|
}, resourceImageChangeComputeci),
|
||||||
|
customdiff.IfValueChange("enabled_stacks", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.([]interface{})
|
||||||
|
n := new.([]interface{})
|
||||||
|
|
||||||
|
if len(o) != len(n) {
|
||||||
|
return true
|
||||||
|
} else if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
for i, v := range n {
|
||||||
|
if v.(string) == o[i].(string) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count == 0
|
||||||
|
}, resourceImageUpdateNodes),
|
||||||
|
),
|
||||||
|
|
||||||
|
Schema: resourceImageSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenMeta(m []interface{}) []string {
|
||||||
|
output := []string{}
|
||||||
|
for _, item := range m {
|
||||||
|
switch d := item.(type) {
|
||||||
|
case string:
|
||||||
|
output = append(output, d)
|
||||||
|
case int:
|
||||||
|
output = append(output, strconv.Itoa(d))
|
||||||
|
case int64:
|
||||||
|
output = append(output, strconv.FormatInt(d, 10))
|
||||||
|
case float64:
|
||||||
|
output = append(output, strconv.FormatInt(int64(d), 10))
|
||||||
|
default:
|
||||||
|
output = append(output, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenHistory(history []History) []map[string]interface{} {
|
||||||
|
temp := make([]map[string]interface{}, 0)
|
||||||
|
for _, item := range history {
|
||||||
|
t := map[string]interface{}{
|
||||||
|
"id": item.Id,
|
||||||
|
"guid": item.Guid,
|
||||||
|
"timestamp": item.Timestamp,
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = append(temp, t)
|
||||||
|
}
|
||||||
|
return temp
|
||||||
|
}
|
||||||
@ -0,0 +1,393 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Petr Krutov, <petr.krutov@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceK8sCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceK8sCreate: called with name %s, rg %d", d.Get("name").(string), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
urlValues.Add("rgId", strconv.Itoa(d.Get("rg_id").(int)))
|
||||||
|
urlValues.Add("k8ciId", strconv.Itoa(d.Get("k8sci_id").(int)))
|
||||||
|
urlValues.Add("workerGroupName", d.Get("wg_name").(string))
|
||||||
|
|
||||||
|
var masterNode K8sNodeRecord
|
||||||
|
if masters, ok := d.GetOk("masters"); ok {
|
||||||
|
masterNode = parseNode(masters.([]interface{}))
|
||||||
|
} else {
|
||||||
|
masterNode = nodeMasterDefault()
|
||||||
|
}
|
||||||
|
urlValues.Add("masterNum", strconv.Itoa(masterNode.Num))
|
||||||
|
urlValues.Add("masterCpu", strconv.Itoa(masterNode.Cpu))
|
||||||
|
urlValues.Add("masterRam", strconv.Itoa(masterNode.Ram))
|
||||||
|
urlValues.Add("masterDisk", strconv.Itoa(masterNode.Disk))
|
||||||
|
|
||||||
|
var workerNode K8sNodeRecord
|
||||||
|
if workers, ok := d.GetOk("workers"); ok {
|
||||||
|
workerNode = parseNode(workers.([]interface{}))
|
||||||
|
} else {
|
||||||
|
workerNode = nodeWorkerDefault()
|
||||||
|
}
|
||||||
|
urlValues.Add("workerNum", strconv.Itoa(workerNode.Num))
|
||||||
|
urlValues.Add("workerCpu", strconv.Itoa(workerNode.Cpu))
|
||||||
|
urlValues.Add("workerRam", strconv.Itoa(workerNode.Ram))
|
||||||
|
urlValues.Add("workerDisk", strconv.Itoa(workerNode.Disk))
|
||||||
|
|
||||||
|
//if withLB, ok := d.GetOk("with_lb"); ok {
|
||||||
|
//urlValues.Add("withLB", strconv.FormatBool(withLB.(bool)))
|
||||||
|
//}
|
||||||
|
urlValues.Add("withLB", strconv.FormatBool(true))
|
||||||
|
|
||||||
|
if extNet, ok := d.GetOk("extnet_id"); ok {
|
||||||
|
urlValues.Add("extnetId", strconv.Itoa(extNet.(int)))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("extnetId", "0")
|
||||||
|
}
|
||||||
|
|
||||||
|
//if desc, ok := d.GetOk("desc"); ok {
|
||||||
|
//urlValues.Add("desc", desc.(string))
|
||||||
|
//}
|
||||||
|
|
||||||
|
resp, err := controller.decortAPICall("POST", K8sCreateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
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: instance creating - %s", task.Stage)
|
||||||
|
|
||||||
|
if task.Completed {
|
||||||
|
if task.Error != "" {
|
||||||
|
return fmt.Errorf("cannot create k8s instance: %v", task.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(strconv.Itoa(int(task.Result)))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
k8s, err := utilityK8sCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("default_wg_id", k8s.Groups.Workers[0].ID)
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
urlValues.Add("lbId", strconv.Itoa(k8s.LbID))
|
||||||
|
|
||||||
|
resp, err = controller.decortAPICall("POST", LbGetAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var lb LbRecord
|
||||||
|
if err := json.Unmarshal([]byte(resp), &lb); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.Set("extnet_id", lb.ExtNetID)
|
||||||
|
d.Set("lb_ip", lb.PrimaryNode.FrontendIP)
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
urlValues.Add("k8sId", d.Id())
|
||||||
|
kubeconfig, err := controller.decortAPICall("POST", K8sGetConfigAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("could not get kubeconfig: %v", err)
|
||||||
|
}
|
||||||
|
d.Set("kubeconfig", kubeconfig)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceK8sRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceK8sRead: called with id %s, rg %d", d.Id(), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
k8s, err := utilityK8sCheckPresence(d, m)
|
||||||
|
if k8s == nil {
|
||||||
|
d.SetId("")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("name", k8s.Name)
|
||||||
|
d.Set("rg_id", k8s.RgID)
|
||||||
|
d.Set("k8sci_id", k8s.CI)
|
||||||
|
d.Set("wg_name", k8s.Groups.Workers[0].Name)
|
||||||
|
d.Set("masters", nodeToResource(k8s.Groups.Masters))
|
||||||
|
d.Set("workers", nodeToResource(k8s.Groups.Workers[0]))
|
||||||
|
d.Set("default_wg_id", k8s.Groups.Workers[0].ID)
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("lbId", strconv.Itoa(k8s.LbID))
|
||||||
|
|
||||||
|
resp, err := controller.decortAPICall("POST", LbGetAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var lb LbRecord
|
||||||
|
if err := json.Unmarshal([]byte(resp), &lb); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.Set("extnet_id", lb.ExtNetID)
|
||||||
|
d.Set("lb_ip", lb.PrimaryNode.FrontendIP)
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
urlValues.Add("k8sId", d.Id())
|
||||||
|
kubeconfig, err := controller.decortAPICall("POST", K8sGetConfigAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("could not get kubeconfig: %v", err)
|
||||||
|
}
|
||||||
|
d.Set("kubeconfig", kubeconfig)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceK8sUpdate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceK8sUpdate: called with id %s, rg %d", d.Id(), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
|
||||||
|
if d.HasChange("name") {
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("k8sId", d.Id())
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
|
||||||
|
_, err := controller.decortAPICall("POST", K8sUpdateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("workers") {
|
||||||
|
k8s, err := utilityK8sCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
wg := k8s.Groups.Workers[0]
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("k8sId", d.Id())
|
||||||
|
urlValues.Add("workersGroupId", strconv.Itoa(wg.ID))
|
||||||
|
|
||||||
|
newWorkers := parseNode(d.Get("workers").([]interface{}))
|
||||||
|
|
||||||
|
if newWorkers.Num > wg.Num {
|
||||||
|
urlValues.Add("num", strconv.Itoa(newWorkers.Num-wg.Num))
|
||||||
|
if _, err := controller.decortAPICall("POST", K8sWorkerAddAPI, urlValues); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i := wg.Num - 1; i >= newWorkers.Num; i-- {
|
||||||
|
urlValues.Set("workerId", strconv.Itoa(wg.DetailedInfo[i].ID))
|
||||||
|
if _, err := controller.decortAPICall("POST", K8sWorkerDeleteAPI, urlValues); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceK8sDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceK8sDelete: called with id %s, rg %d", d.Id(), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
k8s, err := utilityK8sCheckPresence(d, m)
|
||||||
|
if k8s == nil {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("k8sId", d.Id())
|
||||||
|
urlValues.Add("permanently", "true")
|
||||||
|
|
||||||
|
_, err = controller.decortAPICall("POST", K8sDeleteAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceK8sExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
log.Debugf("resourceK8sExists: called with id %s, rg %d", d.Id(), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
k8s, err := utilityK8sCheckPresence(d, m)
|
||||||
|
if k8s == nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceK8sSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Name of the cluster.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"rg_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "Resource group ID that this instance belongs to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"k8sci_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "ID of the k8s catalog item to base this instance on.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"wg_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "Name for first worker group created with cluster.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"masters": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: nodeK8sSubresourceSchemaMake(),
|
||||||
|
},
|
||||||
|
Description: "Master node(s) configuration.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"workers": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: nodeK8sSubresourceSchemaMake(),
|
||||||
|
},
|
||||||
|
Description: "Worker node(s) configuration.",
|
||||||
|
},
|
||||||
|
|
||||||
|
//"with_lb": {
|
||||||
|
//Type: schema.TypeBool,
|
||||||
|
//Optional: true,
|
||||||
|
//ForceNew: true,
|
||||||
|
//Default: true,
|
||||||
|
//Description: "Create k8s with load balancer if true.",
|
||||||
|
//},
|
||||||
|
|
||||||
|
"extnet_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "ID of the external network to connect workers to. If omitted network will be chosen by the platfom.",
|
||||||
|
},
|
||||||
|
|
||||||
|
//"desc": {
|
||||||
|
//Type: schema.TypeString,
|
||||||
|
//Optional: true,
|
||||||
|
//Description: "Text description of this instance.",
|
||||||
|
//},
|
||||||
|
|
||||||
|
"lb_ip": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "IP address of default load balancer.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"default_wg_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "ID of default workers group for this instace.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"kubeconfig": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Kubeconfig for cluster access.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceK8s() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceK8sCreate,
|
||||||
|
Read: resourceK8sRead,
|
||||||
|
Update: resourceK8sUpdate,
|
||||||
|
Delete: resourceK8sDelete,
|
||||||
|
Exists: resourceK8sExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout20m,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout20m,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: resourceK8sSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Petr Krutov, <petr.krutov@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceK8sWgCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceK8sWgCreate: called with k8s id %d", d.Get("k8s_id").(int))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("k8sId", strconv.Itoa(d.Get("k8s_id").(int)))
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
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)))
|
||||||
|
urlValues.Add("workerDisk", strconv.Itoa(d.Get("disk").(int)))
|
||||||
|
|
||||||
|
resp, err := controller.decortAPICall("POST", K8sWgCreateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceK8sWgRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceK8sWgRead: called with k8s id %d", d.Get("k8s_id").(int))
|
||||||
|
|
||||||
|
wg, err := utilityK8sWgCheckPresence(d, m)
|
||||||
|
if wg == nil {
|
||||||
|
d.SetId("")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("name", wg.Name)
|
||||||
|
d.Set("num", wg.Num)
|
||||||
|
d.Set("cpu", wg.Cpu)
|
||||||
|
d.Set("ram", wg.Ram)
|
||||||
|
d.Set("disk", wg.Disk)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceK8sWgUpdate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceK8sWgUpdate: called with k8s id %d", d.Get("k8s_id").(int))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
|
||||||
|
wg, err := utilityK8sWgCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("k8sId", strconv.Itoa(d.Get("k8s_id").(int)))
|
||||||
|
urlValues.Add("workersGroupId", d.Id())
|
||||||
|
|
||||||
|
if newNum := d.Get("num").(int); newNum > wg.Num {
|
||||||
|
urlValues.Add("num", strconv.Itoa(newNum-wg.Num))
|
||||||
|
_, err := controller.decortAPICall("POST", K8sWorkerAddAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i := wg.Num - 1; i >= newNum; i-- {
|
||||||
|
urlValues.Set("workerId", strconv.Itoa(wg.DetailedInfo[i].ID))
|
||||||
|
_, err := controller.decortAPICall("POST", K8sWorkerDeleteAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceK8sWgDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceK8sWgDelete: called with k8s id %d", d.Get("k8s_id").(int))
|
||||||
|
|
||||||
|
wg, err := utilityK8sWgCheckPresence(d, m)
|
||||||
|
if wg == nil {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("k8sId", strconv.Itoa(d.Get("k8s_id").(int)))
|
||||||
|
urlValues.Add("workersGroupId", strconv.Itoa(wg.ID))
|
||||||
|
|
||||||
|
_, err = controller.decortAPICall("POST", K8sWgDeleteAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceK8sWgExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
log.Debugf("resourceK8sWgExists: called with k8s id %d", d.Get("k8s_id").(int))
|
||||||
|
|
||||||
|
wg, err := utilityK8sWgCheckPresence(d, m)
|
||||||
|
if wg == nil {
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceK8sWgSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"k8s_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "ID of k8s instance.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "Name of the worker group.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"num": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Default: 1,
|
||||||
|
Description: "Number of worker nodes to create.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"cpu": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Default: 1,
|
||||||
|
Description: "Worker node CPU count.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ram": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Default: 1024,
|
||||||
|
Description: "Worker node RAM in MB.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"disk": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Default: 0,
|
||||||
|
Description: "Worker node boot disk size. If unspecified or 0, size is defined by OS image size.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceK8sWg() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceK8sWgCreate,
|
||||||
|
Read: resourceK8sWgRead,
|
||||||
|
Update: resourceK8sWgUpdate,
|
||||||
|
Delete: resourceK8sWgDelete,
|
||||||
|
Exists: resourceK8sWgExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout20m,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout20m,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: resourceK8sWgSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourcePcideviceCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourcePcideviceCreate: called for pcidevice %s", d.Get("name").(string))
|
||||||
|
|
||||||
|
if deviceId, ok := d.GetOk("device_id"); ok {
|
||||||
|
if exists, err := resourcePcideviceExists(d, m); exists {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId(strconv.Itoa(deviceId.(int)))
|
||||||
|
err = resourcePcideviceRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("provided device id does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
urlValues.Add("hwPath", d.Get("hw_path").(string))
|
||||||
|
urlValues.Add("rgId", strconv.Itoa(d.Get("rg_id").(int)))
|
||||||
|
urlValues.Add("stackId", strconv.Itoa(d.Get("stack_id").(int)))
|
||||||
|
|
||||||
|
if description, ok := d.GetOk("description"); ok {
|
||||||
|
urlValues.Add("description", description.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
pcideviceId, err := controller.decortAPICall("POST", pcideviceCreateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(pcideviceId)
|
||||||
|
d.Set("device_id", pcideviceId)
|
||||||
|
|
||||||
|
err = resourcePcideviceRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePcideviceRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
pcidevice, err := utilityPcideviceCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(strconv.Itoa(pcidevice.ID))
|
||||||
|
d.Set("ckey", pcidevice.CKey)
|
||||||
|
d.Set("meta", flattenMeta(pcidevice.Meta))
|
||||||
|
d.Set("compute_id", pcidevice.Computeid)
|
||||||
|
d.Set("description", pcidevice.Description)
|
||||||
|
d.Set("guid", pcidevice.Guid)
|
||||||
|
d.Set("hw_path", pcidevice.HwPath)
|
||||||
|
d.Set("device_id", pcidevice.ID)
|
||||||
|
d.Set("rg_id", pcidevice.RgID)
|
||||||
|
d.Set("name", pcidevice.Name)
|
||||||
|
d.Set("stack_id", pcidevice.StackID)
|
||||||
|
d.Set("status", pcidevice.Status)
|
||||||
|
d.Set("system_name", pcidevice.SystemName)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePcideviceDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourcePcideviceDelete: called for %s, id: %s", d.Get("name").(string), d.Id())
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("deviceId", d.Id())
|
||||||
|
urlValues.Add("force", strconv.FormatBool(d.Get("force").(bool)))
|
||||||
|
|
||||||
|
_, err := controller.decortAPICall("POST", pcideviceDeleteAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePcideviceExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
pcidevice, err := utilityPcideviceCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if pcidevice == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePcideviceEdit(d *schema.ResourceData, m interface{}) error {
|
||||||
|
if d.HasChange("enable") {
|
||||||
|
state := d.Get("enable").(bool)
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
api := ""
|
||||||
|
|
||||||
|
urlValues.Add("deviceId", strconv.Itoa(d.Get("device_id").(int)))
|
||||||
|
|
||||||
|
if state {
|
||||||
|
api = pcideviceEnableAPI
|
||||||
|
} else {
|
||||||
|
api = pcideviceDisableAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", api, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := resourcePcideviceRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePcideviceSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"ckey": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"compute_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "description, just for information",
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"hw_path": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "PCI address of the device",
|
||||||
|
},
|
||||||
|
"device_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Name of Device",
|
||||||
|
},
|
||||||
|
"rg_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "Resource GROUP",
|
||||||
|
},
|
||||||
|
"stack_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "stackId",
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"system_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"force": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "Force delete",
|
||||||
|
},
|
||||||
|
"enable": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "Enable pci device",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePcidevice() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourcePcideviceCreate,
|
||||||
|
Read: resourcePcideviceRead,
|
||||||
|
Update: resourcePcideviceEdit,
|
||||||
|
Delete: resourcePcideviceDelete,
|
||||||
|
Exists: resourcePcideviceExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: resourcePcideviceSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Petr Krutov, <petr.krutov@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourcePfwCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourcePfwCreate: called for compute %d", d.Get("compute_id").(int))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("computeId", strconv.Itoa(d.Get("compute_id").(int)))
|
||||||
|
urlValues.Add("publicPortStart", strconv.Itoa(d.Get("public_port_start").(int)))
|
||||||
|
urlValues.Add("localBasePort", strconv.Itoa(d.Get("local_base_port").(int)))
|
||||||
|
urlValues.Add("proto", d.Get("proto").(string))
|
||||||
|
|
||||||
|
if portEnd, ok := d.GetOk("public_port_end"); ok {
|
||||||
|
urlValues.Add("publicPortEnd", strconv.Itoa(portEnd.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pfwId, err := controller.decortAPICall("POST", ComputePfwAddAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(fmt.Sprintf("%d-%s", d.Get("compute_id").(int), pfwId))
|
||||||
|
|
||||||
|
pfw, err := utilityPfwCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("local_ip", pfw.LocalIP)
|
||||||
|
if _, ok := d.GetOk("public_port_end"); !ok {
|
||||||
|
d.Set("public_port_end", pfw.PublicPortEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePfwRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourcePfwRead: called for compute %d, rule %s", d.Get("compute_id").(int), d.Id())
|
||||||
|
|
||||||
|
pfw, err := utilityPfwCheckPresence(d, m)
|
||||||
|
if pfw == nil {
|
||||||
|
d.SetId("")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("compute_id", pfw.ComputeID)
|
||||||
|
d.Set("public_port_start", pfw.PublicPortStart)
|
||||||
|
d.Set("public_port_end", pfw.PublicPortEnd)
|
||||||
|
d.Set("local_ip", pfw.LocalIP)
|
||||||
|
d.Set("local_base_port", pfw.LocalPort)
|
||||||
|
d.Set("proto", pfw.Protocol)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePfwDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourcePfwDelete: called for compute %d, rule %s", d.Get("compute_id").(int), d.Id())
|
||||||
|
|
||||||
|
pfw, err := utilityPfwCheckPresence(d, m)
|
||||||
|
if pfw == nil {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("computeId", strconv.Itoa(d.Get("compute_id").(int)))
|
||||||
|
urlValues.Add("ruleId", strconv.Itoa(pfw.ID))
|
||||||
|
|
||||||
|
_, err = controller.decortAPICall("POST", ComputePfwDelAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePfwExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
log.Debugf("resourcePfwExists: called for compute %d, rule %s", d.Get("compute_id").(int), d.Id())
|
||||||
|
|
||||||
|
pfw, err := utilityPfwCheckPresence(d, m)
|
||||||
|
if pfw == nil {
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePfwSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"compute_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "ID of compute instance.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"public_port_start": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
ValidateFunc: validation.IntBetween(1, 65535),
|
||||||
|
Description: "External start port number for the rule.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"public_port_end": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
ForceNew: true,
|
||||||
|
ValidateFunc: validation.IntBetween(1, 65535),
|
||||||
|
Description: "End port number (inclusive) for the ranged rule.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"local_ip": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "IP address of compute instance.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"local_base_port": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
ValidateFunc: validation.IntBetween(1, 65535),
|
||||||
|
Description: "Internal base port number.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"proto": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
ValidateFunc: validation.StringInSlice([]string{"tcp", "udp"}, false),
|
||||||
|
Description: "Network protocol, either 'tcp' or 'udp'.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourcePfw() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourcePfwCreate,
|
||||||
|
Read: resourcePfwRead,
|
||||||
|
Delete: resourcePfwDelete,
|
||||||
|
Exists: resourcePfwExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: resourcePfwSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,430 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
// 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
|
||||||
|
|
||||||
|
rg_name, arg_set := d.GetOk("name")
|
||||||
|
if !arg_set {
|
||||||
|
return fmt.Errorf("Cannot create new RG: missing name.")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Current version of provider works with default grid id (same is true for disk resources)
|
||||||
|
grid_id, arg_set := d.GetOk("grid_id")
|
||||||
|
if !arg_set {
|
||||||
|
return fmt.Errorf("Cannot create new RG %q in account ID %d: missing Grid ID.",
|
||||||
|
rg_name.(string), validated_account_id)
|
||||||
|
}
|
||||||
|
if grid_id.(int) < 1 {
|
||||||
|
grid_id = DefaultGridID
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 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",
|
||||||
|
rg_name.(string), d.Get("account_id").(int))
|
||||||
|
|
||||||
|
// quota settings are optional
|
||||||
|
set_quota := false
|
||||||
|
var quota_record QuotaRecord
|
||||||
|
arg_value, arg_set := d.GetOk("quota")
|
||||||
|
if arg_set {
|
||||||
|
log.Debugf("resourceResgroupCreate: setting Quota on RG requested")
|
||||||
|
quota_record = makeQuotaRecord(arg_value.([]interface{}))
|
||||||
|
set_quota = true
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
log.Debugf("resourceResgroupCreate: called by user %q for RG name %s, account ID %d",
|
||||||
|
controller.getDecortUsername(),
|
||||||
|
rg_name.(string), d.Get("account_id").(int))
|
||||||
|
|
||||||
|
url_values := &url.Values{}
|
||||||
|
url_values.Add("accountId", fmt.Sprintf("%d", d.Get("account_id").(int)))
|
||||||
|
url_values.Add("name", rg_name.(string))
|
||||||
|
url_values.Add("gid", fmt.Sprintf("%d", DefaultGridID)) // use default Grid ID, similar to disk resource mgmt convention
|
||||||
|
url_values.Add("owner", controller.getDecortUsername())
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
url_values.Add("maxMemoryCapacity", fmt.Sprintf("%f", quota_record.Ram)) // RAM quota is float; this may change in the future
|
||||||
|
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
|
||||||
|
def_net_type, arg_set := d.GetOk("def_net_type")
|
||||||
|
if arg_set {
|
||||||
|
url_values.Add("def_net", def_net_type.(string)) // NOTE: in API default network type is set by "def_net" parameter
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcidr, arg_set := d.GetOk("ipcidr")
|
||||||
|
if arg_set {
|
||||||
|
url_values.Add("ipcidr", ipcidr.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
ext_net_id, arg_set := d.GetOk("ext_net_id")
|
||||||
|
if arg_set {
|
||||||
|
url_values.Add("extNetId", fmt.Sprintf("%d", ext_net_id.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
ext_ip, arg_set := d.GetOk("ext_ip")
|
||||||
|
if arg_set {
|
||||||
|
url_values.Add("extIp", ext_ip.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
// rg.ID, _ = strconv.Atoi(api_resp)
|
||||||
|
if !set_quota {
|
||||||
|
resp, err := utilityResgroupCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rg := ResgroupGetResp{}
|
||||||
|
if err := json.Unmarshal([]byte(resp), &rg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("quota", parseQuota(rg.Quota))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
log.Debugf("resourceResgroupRead: called for RG name %s, account ID %d",
|
||||||
|
d.Get("name").(string), d.Get("account_id").(int))
|
||||||
|
|
||||||
|
rg_facts, err := utilityResgroupCheckPresence(d, m)
|
||||||
|
if rg_facts == "" {
|
||||||
|
// if empty string is returned from utilityResgroupCheckPresence then there is no
|
||||||
|
// such resource group and err tells so - just return it to the calling party
|
||||||
|
d.SetId("") // ensure ID is empty
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return flattenResgroup(d, rg_facts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceResgroupUpdate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceResgroupUpdate: called for RG name %s, account ID %d",
|
||||||
|
d.Get("name").(string), d.Get("account_id").(int))
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
|
||||||
|
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) {
|
||||||
|
do_general_update = true
|
||||||
|
url_values.Add("name", name_new.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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{}))
|
||||||
|
quota_value_old, _ := d.GetChange("quota") // returns old as 1st, new as 2nd return value
|
||||||
|
quotarecord_old := makeQuotaRecord(quota_value_old.([]interface{}))
|
||||||
|
|
||||||
|
if quotarecord_new.Cpu != quotarecord_old.Cpu {
|
||||||
|
do_general_update = true
|
||||||
|
log.Debugf("resourceResgroupUpdate: Cpu diff %d <- %d", quotarecord_new.Cpu, quotarecord_old.Cpu)
|
||||||
|
url_values.Add("maxCPUCapacity", fmt.Sprintf("%d", quotarecord_new.Cpu))
|
||||||
|
}
|
||||||
|
|
||||||
|
if quotarecord_new.Disk != quotarecord_old.Disk {
|
||||||
|
do_general_update = true
|
||||||
|
log.Debugf("resourceResgroupUpdate: Disk diff %d <- %d", quotarecord_new.Disk, quotarecord_old.Disk)
|
||||||
|
url_values.Add("maxVDiskCapacity", fmt.Sprintf("%d", quotarecord_new.Disk))
|
||||||
|
}
|
||||||
|
|
||||||
|
if quotarecord_new.Ram != quotarecord_old.Ram { // NB: quota on RAM is stored as float32, in units of MB
|
||||||
|
do_general_update = true
|
||||||
|
log.Debugf("resourceResgroupUpdate: Ram diff %f <- %f", quotarecord_new.Ram, quotarecord_old.Ram)
|
||||||
|
url_values.Add("maxMemoryCapacity", fmt.Sprintf("%f", quotarecord_new.Ram))
|
||||||
|
}
|
||||||
|
|
||||||
|
if quotarecord_new.ExtTraffic != quotarecord_old.ExtTraffic {
|
||||||
|
do_general_update = true
|
||||||
|
log.Debugf("resourceResgroupUpdate: ExtTraffic diff %d <- %d", quotarecord_new.ExtTraffic, quotarecord_old.ExtTraffic)
|
||||||
|
url_values.Add("maxNetworkPeerTransfer", fmt.Sprintf("%d", quotarecord_new.ExtTraffic))
|
||||||
|
}
|
||||||
|
|
||||||
|
if quotarecord_new.ExtIPs != quotarecord_old.ExtIPs {
|
||||||
|
do_general_update = true
|
||||||
|
log.Debugf("resourceResgroupUpdate: ExtIPs diff %d <- %d", quotarecord_new.ExtIPs, quotarecord_old.ExtIPs)
|
||||||
|
url_values.Add("maxNumPublicIP", fmt.Sprintf("%d", quotarecord_new.ExtIPs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
desc_new, desc_set := d.GetOk("description")
|
||||||
|
if desc_set {
|
||||||
|
log.Debugf("resourceResgroupUpdate: description specified - looking for deltas from the old settings.")
|
||||||
|
desc_old, _ := d.GetChange("description")
|
||||||
|
if desc_old.(string) != desc_new.(string) {
|
||||||
|
do_general_update = true
|
||||||
|
url_values.Add("desc", desc_new.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if do_general_update {
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
log.Debugf("resourceResgroupDelete: called for RG name %s, account ID %d",
|
||||||
|
d.Get("name").(string), d.Get("account_id").(int))
|
||||||
|
|
||||||
|
rg_facts, err := utilityResgroupCheckPresence(d, m)
|
||||||
|
if rg_facts == "" {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// the target RG does not exist - in this case according to Terraform best practice
|
||||||
|
// we exit from Destroy method without error
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
url_values := &url.Values{}
|
||||||
|
url_values.Add("rgId", d.Id())
|
||||||
|
url_values.Add("force", "1")
|
||||||
|
url_values.Add("permanently", "1")
|
||||||
|
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 {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceResgroupCreate,
|
||||||
|
Read: resourceResgroupRead,
|
||||||
|
Update: resourceResgroupUpdate,
|
||||||
|
Delete: resourceResgroupDelete,
|
||||||
|
Exists: resourceResgroupExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout180s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout180s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Name of this resource group. Names are case sensitive and unique within the context of a account.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.IntAtLeast(1),
|
||||||
|
Description: "Unique ID of the account, which this resource group belongs to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"def_net_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: "PRIVATE",
|
||||||
|
ValidateFunc: validation.StringInSlice([]string{"PRIVATE", "PUBLIC", "NONE"}, false),
|
||||||
|
Description: "Type of the network, which this resource group will use as default for its computes - PRIVATE or PUBLIC or NONE.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"def_net_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "ID of the default network for this resource group (if any).",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ipcidr": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Address of the netowrk inside the private network segment (aka ViNS) if def_net_type=PRIVATE",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ext_net_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Default: 0,
|
||||||
|
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",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ext_ip": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "IP address on the external netowrk to request when def_net_type=PRIVATE and ext_net_id is not 0",
|
||||||
|
},
|
||||||
|
|
||||||
|
/* commented out, as in this version of provider we use default Grid ID
|
||||||
|
"grid_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
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
|
||||||
|
Description: "Unique ID of the grid, where this resource group is deployed.",
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
|
"quota": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: quotaRgSubresourceSchemaMake(),
|
||||||
|
},
|
||||||
|
Description: "Quota settings for this resource group.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"description": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Description: "User-defined text description of this resource group.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Name of the account, which this resource group belongs to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Current status of this resource group.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"vins": {
|
||||||
|
Type: schema.TypeList, // this is a list of ints
|
||||||
|
Computed: true,
|
||||||
|
MaxItems: LimitMaxVinsPerResgroup,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
Description: "List of VINs deployed in this resource group.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"computes": {
|
||||||
|
Type: schema.TypeList, // this is a list of ints
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
Description: "List of computes deployed in this resource group.",
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,548 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/customdiff"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceSepCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceSepCreate: called for sep %s", d.Get("name").(string))
|
||||||
|
|
||||||
|
if sepId, ok := d.GetOk("sep_id"); ok {
|
||||||
|
if exists, err := resourceSepExists(d, m); exists {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId(strconv.Itoa(sepId.(int)))
|
||||||
|
err = resourceSepRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("provided sep id does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
urlValues.Add("gid", strconv.Itoa(d.Get("gid").(int)))
|
||||||
|
urlValues.Add("sep_type", d.Get("type").(string))
|
||||||
|
|
||||||
|
if desc, ok := d.GetOk("desc"); ok {
|
||||||
|
urlValues.Add("description", desc.(string))
|
||||||
|
}
|
||||||
|
if configString, ok := d.GetOk("config"); ok {
|
||||||
|
urlValues.Add("config", configString.(string))
|
||||||
|
}
|
||||||
|
if enable, ok := d.GetOk("enable"); ok {
|
||||||
|
urlValues.Add("enable", strconv.FormatBool(enable.(bool)))
|
||||||
|
}
|
||||||
|
|
||||||
|
tstr := d.Get("consumed_by").([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(tstr)
|
||||||
|
for i, str := range tstr {
|
||||||
|
s := "\"" + str.(string) + "\""
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ","
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
urlValues.Add("consumer_nids", temp)
|
||||||
|
|
||||||
|
tstr = d.Get("provided_by").([]interface{})
|
||||||
|
temp = ""
|
||||||
|
l = len(tstr)
|
||||||
|
for i, str := range tstr {
|
||||||
|
s := "\"" + str.(string) + "\""
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ","
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
urlValues.Add("provider_nids", temp)
|
||||||
|
|
||||||
|
sepId, err := controller.decortAPICall("POST", sepCreateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(sepId)
|
||||||
|
d.Set("sep_id", sepId)
|
||||||
|
|
||||||
|
err = resourceSepRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(id.String())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSepRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceSepRead: called for %s id: %d", d.Get("name").(string), d.Get("sep_id").(int))
|
||||||
|
|
||||||
|
sep, err := utilitySepCheckPresence(d, m)
|
||||||
|
if sep == nil {
|
||||||
|
d.SetId("")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("ckey", sep.Ckey)
|
||||||
|
d.Set("meta", flattenMeta(sep.Meta))
|
||||||
|
d.Set("consumed_by", sep.ConsumedBy)
|
||||||
|
d.Set("desc", sep.Desc)
|
||||||
|
d.Set("gid", sep.Gid)
|
||||||
|
d.Set("guid", sep.Guid)
|
||||||
|
d.Set("sep_id", sep.Id)
|
||||||
|
d.Set("milestones", sep.Milestones)
|
||||||
|
d.Set("name", sep.Name)
|
||||||
|
d.Set("obj_status", sep.ObjStatus)
|
||||||
|
d.Set("provided_by", sep.ProvidedBy)
|
||||||
|
d.Set("tech_status", sep.TechStatus)
|
||||||
|
d.Set("type", sep.Type)
|
||||||
|
data, _ := json.Marshal(sep.Config)
|
||||||
|
d.Set("config", string(data))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSepDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceSepDelete: called for %s, id: %d", d.Get("name").(string), d.Get("sep_id").(int))
|
||||||
|
|
||||||
|
sepDes, err := utilitySepCheckPresence(d, m)
|
||||||
|
if sepDes == nil {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("sep_id", strconv.Itoa(d.Get("sep_id").(int)))
|
||||||
|
|
||||||
|
_, err = controller.decortAPICall("POST", sepDeleteAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSepExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
log.Debugf("resourceSepExists: called for %s, id: %d", d.Get("name").(string), d.Get("sep_id").(int))
|
||||||
|
|
||||||
|
sepDes, err := utilitySepCheckPresence(d, m)
|
||||||
|
if sepDes == nil {
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSepEdit(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceSepEdit: called for %s, id: %d", d.Get("name").(string), d.Get("sep_id").(int))
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
if d.HasChange("decommission") {
|
||||||
|
decommission := d.Get("decommission").(bool)
|
||||||
|
if decommission {
|
||||||
|
urlValues.Add("sep_id", strconv.Itoa(d.Get("sep_id").(int)))
|
||||||
|
urlValues.Add("clear_physically", strconv.FormatBool(d.Get("clear_physically").(bool)))
|
||||||
|
_, err := c.decortAPICall("POST", sepDecommissionAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
if d.HasChange("upd_capacity_limit") {
|
||||||
|
updCapacityLimit := d.Get("upd_capacity_limit").(bool)
|
||||||
|
if updCapacityLimit {
|
||||||
|
urlValues.Add("sep_id", strconv.Itoa(d.Get("sep_id").(int)))
|
||||||
|
_, err := c.decortAPICall("POST", sepUpdateCapacityLimitAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
if d.HasChange("config") {
|
||||||
|
urlValues.Add("sep_id", strconv.Itoa(d.Get("sep_id").(int)))
|
||||||
|
urlValues.Add("config", d.Get("config").(string))
|
||||||
|
_, err := c.decortAPICall("POST", sepConfigValidateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = c.decortAPICall("POST", sepConfigInsertAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
if d.HasChange("field_edit") {
|
||||||
|
fieldConfig := d.Get("field_edit").([]interface{})
|
||||||
|
field := fieldConfig[0].(map[string]interface{})
|
||||||
|
urlValues.Add("sep_id", strconv.Itoa(d.Get("sep_id").(int)))
|
||||||
|
urlValues.Add("field_name", field["field_name"].(string))
|
||||||
|
urlValues.Add("field_value", field["field_value"].(string))
|
||||||
|
urlValues.Add("field_type", field["field_type"].(string))
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", sepConfigFieldEditAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
if err := resourceSepRead(d, m); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSepChangeEnabled(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
var api string
|
||||||
|
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("sep_id", strconv.Itoa(d.Get("sep_id").(int)))
|
||||||
|
if d.Get("enable").(bool) {
|
||||||
|
api = sepEnableAPI
|
||||||
|
} else {
|
||||||
|
api = sepDisableAPI
|
||||||
|
}
|
||||||
|
resp, err := c.decortAPICall("POST", api, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res, err := strconv.ParseBool(resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !res {
|
||||||
|
return errors.New("Cannot enable/disable")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSepUpdateNodes(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
log.Debugf("resourceSepUpdateNodes: called for %s, id: %d", d.Get("name").(string), d.Get("sep_id").(int))
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
t1, t2 := d.GetChange("consumed_by")
|
||||||
|
|
||||||
|
urlValues.Add("sep_id", strconv.Itoa(d.Get("sep_id").(int)))
|
||||||
|
|
||||||
|
consumedIds := make([]interface{}, 0)
|
||||||
|
temp := ""
|
||||||
|
api := ""
|
||||||
|
|
||||||
|
if d1, d2 := t1.([]interface{}), t2.([]interface{}); len(d1) > len(d2) {
|
||||||
|
for _, n := range d2 {
|
||||||
|
if !findElInt(d1, n) {
|
||||||
|
consumedIds = append(consumedIds, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
api = sepDelConsumerNodesAPI
|
||||||
|
} else {
|
||||||
|
consumedIds = d.Get("consumed_by").([]interface{})
|
||||||
|
api = sepAddConsumerNodesAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
l := len(consumedIds)
|
||||||
|
for i, consumedId := range consumedIds {
|
||||||
|
s := strconv.Itoa(consumedId.(int))
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ","
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
urlValues.Add("consumer_nids", temp)
|
||||||
|
_, err := c.decortAPICall("POST", api, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findElInt(sl []interface{}, el interface{}) bool {
|
||||||
|
for _, e := range sl {
|
||||||
|
if e.(int) == el.(int) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSepUpdateProviders(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
log.Debugf("resourceSepUpdateProviders: called for %s, id: %d", d.Get("name").(string), d.Get("sep_id").(int))
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("sep_id", strconv.Itoa(d.Get("sep_id").(int)))
|
||||||
|
providerIds := d.Get("provided_by").([]interface{})
|
||||||
|
temp := ""
|
||||||
|
l := len(providerIds)
|
||||||
|
for i, providerId := range providerIds {
|
||||||
|
s := strconv.Itoa(providerId.(int))
|
||||||
|
if i != (l - 1) {
|
||||||
|
s += ","
|
||||||
|
}
|
||||||
|
temp = temp + s
|
||||||
|
}
|
||||||
|
temp = "[" + temp + "]"
|
||||||
|
urlValues.Add("provider_nids", temp)
|
||||||
|
_, err := c.decortAPICall("POST", sepAddProviderNodesAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSepSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "sep type des id",
|
||||||
|
},
|
||||||
|
"upd_capacity_limit": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "Update SEP capacity limit",
|
||||||
|
},
|
||||||
|
"decommission": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "unlink everything that exists from SEP",
|
||||||
|
},
|
||||||
|
"clear_physically": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: true,
|
||||||
|
Description: "clear disks and images physically",
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "sep config string",
|
||||||
|
},
|
||||||
|
"ckey": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"consumed_by": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
Description: "list of consumer nodes IDs",
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Optional: true,
|
||||||
|
Description: "sep description",
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "grid (platform) ID",
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "SEP name",
|
||||||
|
},
|
||||||
|
"obj_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"provided_by": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
Description: "list of provider nodes IDs",
|
||||||
|
},
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "type of storage",
|
||||||
|
},
|
||||||
|
"enable": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "enable SEP after creation",
|
||||||
|
},
|
||||||
|
"field_edit": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
MaxItems: 1,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"field_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"field_value": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"field_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSep() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceSepCreate,
|
||||||
|
Read: resourceSepRead,
|
||||||
|
Update: resourceSepEdit,
|
||||||
|
Delete: resourceSepDelete,
|
||||||
|
Exists: resourceSepExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: resourceSepSchemaMake(),
|
||||||
|
|
||||||
|
CustomizeDiff: customdiff.All(
|
||||||
|
customdiff.IfValueChange("enable", func(old, new, meta interface{}) bool {
|
||||||
|
return old.(bool) != new.(bool)
|
||||||
|
}, resourceSepChangeEnabled),
|
||||||
|
customdiff.IfValueChange("consumed_by", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.([]interface{})
|
||||||
|
n := new.([]interface{})
|
||||||
|
|
||||||
|
if len(o) != len(n) {
|
||||||
|
return true
|
||||||
|
} else if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
for i, v := range n {
|
||||||
|
if v.(int) == o[i].(int) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count == 0
|
||||||
|
}, resourceSepUpdateNodes),
|
||||||
|
customdiff.IfValueChange("provided_by", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.([]interface{})
|
||||||
|
n := new.([]interface{})
|
||||||
|
|
||||||
|
if len(o) != len(n) {
|
||||||
|
return true
|
||||||
|
} else if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
for i, v := range n {
|
||||||
|
if v.(int) == o[i].(int) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count == 0
|
||||||
|
}, resourceSepUpdateProviders),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceSepConfigCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceSepConfigCreate: called for sep id %d", d.Get("sep_id").(int))
|
||||||
|
|
||||||
|
if _, ok := d.GetOk("sep_id"); ok {
|
||||||
|
if exists, err := resourceSepConfigExists(d, m); exists {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New()
|
||||||
|
d.SetId(id.String())
|
||||||
|
err = resourceSepConfigRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("provided sep id config does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceSepConfigRead(d, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSepConfigRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceSepConfigRead: called for sep id: %d", d.Get("sep_id").(int))
|
||||||
|
|
||||||
|
sepConfig, err := utilitySepConfigCheckPresence(d, m)
|
||||||
|
if sepConfig == nil {
|
||||||
|
d.SetId("")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data, _ := json.Marshal(sepConfig)
|
||||||
|
d.Set("config", string(data))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSepConfigDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSepConfigExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
log.Debugf("resourceSepConfigExists: called for sep id: %d", d.Get("sep_id").(int))
|
||||||
|
|
||||||
|
sepDesConfig, err := utilitySepConfigCheckPresence(d, m)
|
||||||
|
if sepDesConfig == nil {
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSepConfigEdit(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceSepConfigEdit: called for sep id: %d", d.Get("sep_id").(int))
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
if d.HasChange("config") {
|
||||||
|
urlValues.Add("sep_id", strconv.Itoa(d.Get("sep_id").(int)))
|
||||||
|
urlValues.Add("config", d.Get("config").(string))
|
||||||
|
_, err := c.decortAPICall("POST", sepConfigValidateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = c.decortAPICall("POST", sepConfigInsertAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues = &url.Values{}
|
||||||
|
if d.HasChange("field_edit") {
|
||||||
|
fieldConfig := d.Get("field_edit").([]interface{})
|
||||||
|
field := fieldConfig[0].(map[string]interface{})
|
||||||
|
urlValues.Add("sep_id", strconv.Itoa(d.Get("sep_id").(int)))
|
||||||
|
urlValues.Add("field_name", field["field_name"].(string))
|
||||||
|
urlValues.Add("field_value", field["field_value"].(string))
|
||||||
|
urlValues.Add("field_type", field["field_type"].(string))
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", sepConfigFieldEditAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := resourceSepConfigRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSepConfigSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"field_edit": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
MaxItems: 1,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"field_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"field_value": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"field_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSepConfig() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceSepConfigCreate,
|
||||||
|
Read: resourceSepConfigRead,
|
||||||
|
Update: resourceSepConfigEdit,
|
||||||
|
Delete: resourceSepConfigDelete,
|
||||||
|
Exists: resourceSepConfigExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: resourceSepConfigSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/customdiff"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceSnapshotCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceSnapshotCreate: called for snapshot %s", d.Get("label").(string))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("label", d.Get("label").(string))
|
||||||
|
urlValues.Add("computeId", strconv.Itoa(d.Get("compute_id").(int)))
|
||||||
|
|
||||||
|
snapshotId, err := controller.decortAPICall("POST", snapshotCreateAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshotId = strings.ReplaceAll(snapshotId, "\"", "")
|
||||||
|
|
||||||
|
d.SetId(snapshotId)
|
||||||
|
d.Set("guid", snapshotId)
|
||||||
|
|
||||||
|
err = resourceSnapshotRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSnapshotRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
snapshot, err := utilitySnapshotCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("timestamp", snapshot.Timestamp)
|
||||||
|
d.Set("guid", snapshot.Guid)
|
||||||
|
d.Set("disks", snapshot.Disks)
|
||||||
|
d.Set("label", snapshot.Label)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSnapshotDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceSnapshotDelete: called for %s, id: %s", d.Get("label").(string), d.Id())
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("computeId", strconv.Itoa(d.Get("compute_id").(int)))
|
||||||
|
urlValues.Add("label", d.Get("label").(string))
|
||||||
|
|
||||||
|
_, err := controller.decortAPICall("POST", snapshotDeleteAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSnapshotExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
snapshot, err := utilitySnapshotCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if snapshot == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSnapshotEdit(d *schema.ResourceData, m interface{}) error {
|
||||||
|
err := resourceSnapshotRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSnapshotRollback(d *schema.ResourceDiff, m interface{}) error {
|
||||||
|
c := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("computeId", strconv.Itoa(d.Get("compute_id").(int)))
|
||||||
|
urlValues.Add("label", d.Get("label").(string))
|
||||||
|
|
||||||
|
_, err := c.decortAPICall("POST", snapshotRollbackAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSnapshotSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"compute_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "ID of the compute instance to create snapshot for.",
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Description: "text label for snapshot. Must be unique among this compute snapshots.",
|
||||||
|
},
|
||||||
|
"rollback": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "is rollback the snapshot",
|
||||||
|
},
|
||||||
|
"disks": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "guid of the snapshot",
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "timestamp",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceSnapshot() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceSnapshotCreate,
|
||||||
|
Read: resourceSnapshotRead,
|
||||||
|
Update: resourceSnapshotEdit,
|
||||||
|
Delete: resourceSnapshotDelete,
|
||||||
|
Exists: resourceSnapshotExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
CustomizeDiff: customdiff.All(
|
||||||
|
customdiff.IfValueChange("rollback", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.(bool)
|
||||||
|
if o != new.(bool) && !o {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, resourceSnapshotRollback),
|
||||||
|
),
|
||||||
|
|
||||||
|
Schema: resourceSnapshotSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,321 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
||||||
|
// "github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ipcidrDiffSupperss(key, oldVal, newVal string, d *schema.ResourceData) bool {
|
||||||
|
if oldVal == "" && newVal != "" {
|
||||||
|
// if old value for "ipcidr" resource is empty string, it means that we are creating new ViNS
|
||||||
|
// and there is a chance that the user will want specific IP address range for this ViNS -
|
||||||
|
// check if "ipcidr" is explicitly set in TF file to a non-empty string.
|
||||||
|
log.Debugf("ipcidrDiffSupperss: key=%s, oldVal=%q, newVal=%q -> suppress=FALSE", key, oldVal, newVal)
|
||||||
|
return false // there is a difference between stored and new value
|
||||||
|
}
|
||||||
|
log.Debugf("ipcidrDiffSupperss: key=%s, oldVal=%q, newVal=%q -> suppress=TRUE", key, oldVal, newVal)
|
||||||
|
return true // suppress difference
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVinsCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceVinsCreate: called for ViNS name %s, Account ID %d, RG ID %d",
|
||||||
|
d.Get("name").(string), d.Get("account_id").(int), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
apiToCall := VinsCreateInAccountAPI
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
|
||||||
|
argVal, argSet := d.GetOk("rg_id")
|
||||||
|
if argSet && argVal.(int) > 0 {
|
||||||
|
apiToCall = VinsCreateInRgAPI
|
||||||
|
urlValues.Add("rgId", fmt.Sprintf("%d", argVal.(int)))
|
||||||
|
} else {
|
||||||
|
// RG ID either not set at all or set to 0 - user may want ViNS at account level
|
||||||
|
argVal, argSet = d.GetOk("account_id")
|
||||||
|
if !argSet || argVal.(int) <= 0 {
|
||||||
|
// No valid Account ID (and no RG ID either) - cannot create ViNS
|
||||||
|
return fmt.Errorf("resourceVinsCreate: ViNS name %s - no valid account and/or resource group ID specified", d.Id())
|
||||||
|
}
|
||||||
|
urlValues.Add("accountId", fmt.Sprintf("%d", argVal.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
argVal, argSet = d.GetOk("ext_net_id") // NB: even if ext_net_id value is explicitly set to 0, argSet = false anyway
|
||||||
|
if argSet {
|
||||||
|
if argVal.(int) > 0 {
|
||||||
|
// connect to specific external network
|
||||||
|
urlValues.Add("extNetId", fmt.Sprintf("%d", argVal.(int)))
|
||||||
|
/*
|
||||||
|
Commented out, as we've made "ext_net_ip" parameter non-configurable via Terraform!
|
||||||
|
|
||||||
|
// in case of specific ext net connection user may also want a particular IP address
|
||||||
|
argVal, argSet = d.GetOk("ext_net_ip")
|
||||||
|
if argSet && argVal.(string) != "" {
|
||||||
|
urlValues.Add("extIp", argVal.(string))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
// ext_net_id is set to a negative value - connect to default external network
|
||||||
|
// no particular IP address selection in this case
|
||||||
|
urlValues.Add("extNetId", "0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argVal, argSet = d.GetOk("ipcidr")
|
||||||
|
if argSet && argVal.(string) != "" {
|
||||||
|
log.Debugf("resourceVinsCreate: ipcidr is set to %s", argVal.(string))
|
||||||
|
urlValues.Add("ipcidr", argVal.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
argVal, argSet = d.GetOk("description")
|
||||||
|
if argSet {
|
||||||
|
urlValues.Add("desc", argVal.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
apiResp, err := controller.decortAPICall("POST", apiToCall, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(apiResp) // update ID of the resource to tell Terraform that the ViNS resource exists
|
||||||
|
vinsId, _ := strconv.Atoi(apiResp)
|
||||||
|
|
||||||
|
log.Debugf("resourceVinsCreate: new ViNS ID / name %d / %s creation sequence complete", vinsId, d.Get("name").(string))
|
||||||
|
|
||||||
|
// We may reuse dataSourceVinsRead here as we maintain similarity
|
||||||
|
// between ViNS resource and ViNS data source schemas
|
||||||
|
// ViNS resource read function will also update resource ID on success, so that Terraform
|
||||||
|
// will know the resource exists (however, we already did it a few lines before)
|
||||||
|
return dataSourceVinsRead(d, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVinsRead(d *schema.ResourceData, m interface{}) error {
|
||||||
|
vinsFacts, err := utilityVinsCheckPresence(d, m)
|
||||||
|
if vinsFacts == "" {
|
||||||
|
// if empty string is returned from utilityVinsCheckPresence then there is no
|
||||||
|
// such ViNS and err tells so - just return it to the calling party
|
||||||
|
d.SetId("") // ensure ID is empty
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return flattenVins(d, vinsFacts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVinsUpdate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
|
||||||
|
log.Debugf("resourceVinsUpdate: called for ViNS ID / name %s / %s, Account ID %d, RG ID %d",
|
||||||
|
d.Id(), d.Get("name").(string), d.Get("account_id").(int), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
|
||||||
|
d.Partial(true)
|
||||||
|
|
||||||
|
// 1. Handle external network connection change
|
||||||
|
oldExtNetId, newExtNedId := d.GetChange("ext_net_id")
|
||||||
|
if oldExtNetId.(int) != newExtNedId.(int) {
|
||||||
|
log.Debugf("resourceVinsUpdate: changing ViNS ID %s - ext_net_id %d -> %d", d.Id(), oldExtNetId.(int), newExtNedId.(int))
|
||||||
|
|
||||||
|
extnetParams := &url.Values{}
|
||||||
|
extnetParams.Add("vinsId", d.Id())
|
||||||
|
|
||||||
|
if oldExtNetId.(int) > 0 {
|
||||||
|
// there was preexisting external net connection - disconnect ViNS
|
||||||
|
_, err := controller.decortAPICall("POST", VinsExtNetDisconnectAPI, extnetParams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if newExtNedId.(int) > 0 {
|
||||||
|
// new external network connection requested - connect ViNS
|
||||||
|
extnetParams.Add("netId", fmt.Sprintf("%d", newExtNedId.(int)))
|
||||||
|
_, err := controller.decortAPICall("POST", VinsExtNetConnectAPI, extnetParams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetPartial("ext_net_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Partial(false)
|
||||||
|
|
||||||
|
// we may reuse dataSourceVinsRead here as we maintain similarity
|
||||||
|
// between Compute resource and Compute data source schemas
|
||||||
|
return dataSourceVinsRead(d, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVinsDelete(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceVinsDelete: called for ViNS ID / name %s / %s, Account ID %d, RG ID %d",
|
||||||
|
d.Id(), d.Get("name").(string), d.Get("account_id").(int), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
vinsFacts, err := utilityVinsCheckPresence(d, m)
|
||||||
|
if vinsFacts == "" {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// the specified ViNS does not exist - in this case according to Terraform best practice
|
||||||
|
// we exit from Destroy method without error
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
params := &url.Values{}
|
||||||
|
params.Add("vinsId", d.Id())
|
||||||
|
params.Add("force", "1") // disconnect all computes before deleting ViNS
|
||||||
|
params.Add("permanently", "1") // delete ViNS immediately bypassing recycle bin
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
_, err = controller.decortAPICall("POST", VinsDeleteAPI, params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVinsExists(d *schema.ResourceData, m interface{}) (bool, error) {
|
||||||
|
// Reminder: according to Terraform rules, this function should not modify its ResourceData argument
|
||||||
|
log.Debugf("resourceVinsExists: called for ViNS name %s, Account ID %d, RG ID %d",
|
||||||
|
d.Get("name").(string), d.Get("account_id").(int), d.Get("rg_id").(int))
|
||||||
|
|
||||||
|
vinsFacts, err := utilityVinsCheckPresence(d, m)
|
||||||
|
if vinsFacts == "" {
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVinsSchemaMake() map[string]*schema.Schema {
|
||||||
|
rets := map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.StringIsNotEmpty,
|
||||||
|
Description: "Name of the ViNS. Names are case sensitive and unique within the context of an account or resource group.",
|
||||||
|
},
|
||||||
|
|
||||||
|
/* we do not need ViNS ID as an argument because if we already know this ID, it is not practical to call resource provider.
|
||||||
|
Resource Import will work anyway, as it obtains the ID of ViNS to be imported through another mechanism.
|
||||||
|
"vins_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Description: "Unique ID of the ViNS. If ViNS ID is specified, then ViNS name, rg_id and account_id are ignored.",
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
|
"rg_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Default: 0,
|
||||||
|
Description: "ID of the resource group, where this ViNS belongs to. Non-zero for ViNS created at resource group level, 0 otherwise.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
ValidateFunc: validation.IntAtLeast(1),
|
||||||
|
Description: "ID of the account, which this ViNS belongs to. For ViNS created at account level, resource group ID is 0.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ext_net_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.IntAtLeast(0),
|
||||||
|
Description: "ID of the external network this ViNS is connected to. Pass 0 if no external connection required.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ipcidr": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
DiffSuppressFunc: ipcidrDiffSupperss,
|
||||||
|
Description: "Network address to use by this ViNS. This parameter is only valid when creating new ViNS.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"description": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: "",
|
||||||
|
Description: "Optional user-defined text description of this ViNS.",
|
||||||
|
},
|
||||||
|
|
||||||
|
// the rest of attributes are computed
|
||||||
|
"account_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Name of the account, which this ViNS belongs to.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"ext_ip_addr": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "IP address of the external connection (valid for ViNS connected to external network, ignored otherwise).",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return rets
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVins() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceVinsCreate,
|
||||||
|
Read: resourceVinsRead,
|
||||||
|
Update: resourceVinsUpdate,
|
||||||
|
Delete: resourceVinsDelete,
|
||||||
|
Exists: resourceVinsExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout180s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout180s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: resourceVinsSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,384 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/customdiff"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceVirtualImageCreate(d *schema.ResourceData, m interface{}) error {
|
||||||
|
log.Debugf("resourceImageCreate: called for image %s", d.Get("name").(string))
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("name", d.Get("name").(string))
|
||||||
|
urlValues.Add("targetId", strconv.Itoa(d.Get("target_id").(int)))
|
||||||
|
|
||||||
|
imageId, err := controller.decortAPICall("POST", imageCreateVirtualAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(imageId)
|
||||||
|
d.Set("image_id", imageId)
|
||||||
|
|
||||||
|
image, err := utilityImageCheckPresence(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(strconv.Itoa(image.ImageId))
|
||||||
|
d.Set("bootable", image.Bootable)
|
||||||
|
//d.Set("image_id", image.ImageId)
|
||||||
|
|
||||||
|
err = resourceImageRead(d, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVirtualImageSchemaMake() map[string]*schema.Schema {
|
||||||
|
return map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "name of the virtual image to create",
|
||||||
|
},
|
||||||
|
"target_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
Description: "ID of real image to link this virtual image to upon creation",
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "URL where to download media from",
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "grid (platform) ID where this template should be create in",
|
||||||
|
},
|
||||||
|
"boot_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Boot type of image bios or uefi",
|
||||||
|
},
|
||||||
|
"image_type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Image type linux, windows or other",
|
||||||
|
},
|
||||||
|
"drivers": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "List of types of compute suitable for image. Example: [ \"KVM_X86\" ]",
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
Description: "meta",
|
||||||
|
},
|
||||||
|
"hot_resize": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this machine supports hot resize",
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional username for the image",
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional password for the image",
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "AccountId to make the image exclusive",
|
||||||
|
},
|
||||||
|
"username_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "username for upload binary media",
|
||||||
|
},
|
||||||
|
"password_dl": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "password for upload binary media",
|
||||||
|
},
|
||||||
|
"sep_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "storage endpoint provider ID",
|
||||||
|
},
|
||||||
|
"pool_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "pool for image create",
|
||||||
|
},
|
||||||
|
"architecture": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "binary architecture of this image, one of X86_64 of PPC64_LE",
|
||||||
|
},
|
||||||
|
"image_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image id",
|
||||||
|
},
|
||||||
|
"permanently": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Whether to completely delete the image",
|
||||||
|
},
|
||||||
|
"bootable": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Does this image boot OS",
|
||||||
|
},
|
||||||
|
"unc_path": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "unc path",
|
||||||
|
},
|
||||||
|
"link_to": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "",
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "status",
|
||||||
|
},
|
||||||
|
"tech_status": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "tech atatus",
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "version",
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "image size",
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"computeci_id": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"guid": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"provider_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"purge_attempts": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reference_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"res_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"rescuecd": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"reason": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"last_modified": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"desc": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"enabled_stacks": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"shared_with": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVirtualImage() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
|
Create: resourceVirtualImageCreate,
|
||||||
|
Read: resourceImageRead,
|
||||||
|
Update: resourceImageEdit,
|
||||||
|
Delete: resourceImageDelete,
|
||||||
|
Exists: resourceImageExists,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeouts: &schema.ResourceTimeout{
|
||||||
|
Create: &Timeout60s,
|
||||||
|
Read: &Timeout30s,
|
||||||
|
Update: &Timeout60s,
|
||||||
|
Delete: &Timeout60s,
|
||||||
|
Default: &Timeout60s,
|
||||||
|
},
|
||||||
|
|
||||||
|
CustomizeDiff: customdiff.All(
|
||||||
|
customdiff.IfValueChange("enabled", func(old, new, meta interface{}) bool {
|
||||||
|
return old.(bool) != new.(bool)
|
||||||
|
}, resourceImageChangeEnabled),
|
||||||
|
customdiff.IfValueChange("link_to", func(old, new, meta interface{}) bool {
|
||||||
|
return old.(int) != new.(int)
|
||||||
|
}, resourceImageLink),
|
||||||
|
customdiff.IfValueChange("name", func(old, new, meta interface{}) bool {
|
||||||
|
return old.(string) != new.(string) && old.(string) != ""
|
||||||
|
}, resourceImageEditName),
|
||||||
|
customdiff.IfValueChange("shared_with", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.([]interface{})
|
||||||
|
n := new.([]interface{})
|
||||||
|
|
||||||
|
if len(o) != len(n) {
|
||||||
|
return true
|
||||||
|
} else if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
for i, v := range n {
|
||||||
|
if v.(int) == o[i].(int) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count == 0
|
||||||
|
}, resourceImageShare),
|
||||||
|
customdiff.IfValueChange("computeci_id", func(old, new, meta interface{}) bool {
|
||||||
|
return old.(int) != new.(int)
|
||||||
|
}, resourceImageChangeComputeci),
|
||||||
|
customdiff.IfValueChange("enabled_stacks", func(old, new, meta interface{}) bool {
|
||||||
|
o := old.([]interface{})
|
||||||
|
n := new.([]interface{})
|
||||||
|
|
||||||
|
if len(o) != len(n) {
|
||||||
|
return true
|
||||||
|
} else if len(o) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
for i, v := range n {
|
||||||
|
if v.(string) == o[i].(string) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count == 0
|
||||||
|
}, resourceImageUpdateNodes),
|
||||||
|
),
|
||||||
|
|
||||||
|
Schema: resourceVirtualImageSchemaMake(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityAccountCheckPresence(d *schema.ResourceData, m interface{}) (*AccountWithResources, error) {
|
||||||
|
account := &AccountWithResources{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
if (strconv.Itoa(d.Get("account_id").(int))) != "0" {
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("accountId", d.Id())
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountCheckPresence: load account")
|
||||||
|
accountRaw, err := controller.decortAPICall("POST", accountGetAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(accountRaw), &account)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return account, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityAccountAuditsListCheckPresence(d *schema.ResourceData, m interface{}) (AccountAuditsList, error) {
|
||||||
|
accountAuditsList := AccountAuditsList{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountAuditsListCheckPresence: load account list")
|
||||||
|
accountAuditsListRaw, err := controller.decortAPICall("POST", accountAuditsAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(accountAuditsListRaw), &accountAuditsList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountAuditsList, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityAccountComputesListCheckPresence(d *schema.ResourceData, m interface{}) (AccountComputesList, error) {
|
||||||
|
accountComputesList := AccountComputesList{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountComputesListCheckPresence: load account list")
|
||||||
|
accountComputesListRaw, err := controller.decortAPICall("POST", accountListComputesAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(accountComputesListRaw), &accountComputesList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountComputesList, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityAccountConsumedUnitsCheckPresence(d *schema.ResourceData, m interface{}) (*ResourceLimits, error) {
|
||||||
|
accountConsumedUnits := &ResourceLimits{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountConsumedUnitsCheckPresence: load account list")
|
||||||
|
accountConsumedUnitsRaw, err := controller.decortAPICall("POST", accountGetConsumedUnitsAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(accountConsumedUnitsRaw), accountConsumedUnits)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountConsumedUnits, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityAccountConsumedUnitsByTypeCheckPresence(d *schema.ResourceData, m interface{}) (float64, error) {
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
urlValues.Add("cutype", strings.ToUpper(d.Get("cu_type").(string)))
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountConsumedUnitsByTypeCheckPresence")
|
||||||
|
resultRaw, err := controller.decortAPICall("POST", accountGetConsumedUnitsByTypeAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
result, err := strconv.ParseFloat(resultRaw, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityAccountDeletedListCheckPresence(d *schema.ResourceData, m interface{}) (AccountCloudApiList, error) {
|
||||||
|
accountDeletedList := AccountCloudApiList{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
if page, ok := d.GetOk("page"); ok {
|
||||||
|
urlValues.Add("page", strconv.Itoa(page.(int)))
|
||||||
|
}
|
||||||
|
if size, ok := d.GetOk("size"); ok {
|
||||||
|
urlValues.Add("size", strconv.Itoa(size.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountDeletedListCheckPresence: load")
|
||||||
|
accountDeletedListRaw, err := controller.decortAPICall("POST", accountListDeletedAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(accountDeletedListRaw), &accountDeletedList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountDeletedList, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityAccountDisksListCheckPresence(d *schema.ResourceData, m interface{}) (AccountDisksList, error) {
|
||||||
|
accountDisksList := AccountDisksList{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountDisksListCheckPresence: load account list")
|
||||||
|
accountDisksListRaw, err := controller.decortAPICall("POST", accountListDisksAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(accountDisksListRaw), &accountDisksList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountDisksList, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityAccountFlipGroupsListCheckPresence(d *schema.ResourceData, m interface{}) (AccountFlipGroupsList, error) {
|
||||||
|
accountFlipGroupsList := AccountFlipGroupsList{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountFlipGroupsListCheckPresence")
|
||||||
|
accountFlipGroupsListRaw, err := controller.decortAPICall("POST", accountListFlipGroupsAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(accountFlipGroupsListRaw), &accountFlipGroupsList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountFlipGroupsList, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityAccountListCheckPresence(d *schema.ResourceData, m interface{}) (AccountCloudApiList, error) {
|
||||||
|
accountList := AccountCloudApiList{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
if page, ok := d.GetOk("page"); ok {
|
||||||
|
urlValues.Add("page", strconv.Itoa(page.(int)))
|
||||||
|
}
|
||||||
|
if size, ok := d.GetOk("size"); ok {
|
||||||
|
urlValues.Add("size", strconv.Itoa(size.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountListCheckPresence: load account list")
|
||||||
|
accountListRaw, err := controller.decortAPICall("POST", accountListAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(accountListRaw), &accountList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*uncomment for cloudbroker
|
||||||
|
func utilityAccountListCheckPresence(d *schema.ResourceData, m interface{}) (AccountList, error) {
|
||||||
|
accountList := AccountList{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
if page, ok := d.GetOk("page"); ok {
|
||||||
|
urlValues.Add("page", strconv.Itoa(page.(int)))
|
||||||
|
}
|
||||||
|
if size, ok := d.GetOk("size"); ok {
|
||||||
|
urlValues.Add("size", strconv.Itoa(size.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountListCheckPresence: load account list")
|
||||||
|
accountListRaw, err := controller.decortAPICall("POST", accountListAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(accountListRaw), &accountList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountList, nil
|
||||||
|
}
|
||||||
|
*/
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityAccountReservedUnitsCheckPresence(d *schema.ResourceData, m interface{}) (*ResourceLimits, error) {
|
||||||
|
accountReservedUnits := &ResourceLimits{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountReservedUnitsCheckPresence: load units")
|
||||||
|
accountReservedUnitsRaw, err := controller.decortAPICall("POST", accountGetReservedUnitsAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(accountReservedUnitsRaw), accountReservedUnits)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountReservedUnits, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityAccountRGListCheckPresence(d *schema.ResourceData, m interface{}) (AccountRGList, error) {
|
||||||
|
accountRGList := AccountRGList{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountRGListCheckPresence: load account list")
|
||||||
|
accountRGListRaw, err := controller.decortAPICall("POST", accountListRGAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(accountRGListRaw), &accountRGList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountRGList, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityAccountTemplatesListCheckPresence(d *schema.ResourceData, m interface{}) (AccountTemplatesList, error) {
|
||||||
|
accountTemplatesList := AccountTemplatesList{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountTemplatesListCheckPresence: load")
|
||||||
|
accountTemplatesListRaw, err := controller.decortAPICall("POST", accountListTemplatesAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(accountTemplatesListRaw), &accountTemplatesList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountTemplatesList, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityAccountVinsListCheckPresence(d *schema.ResourceData, m interface{}) (AccountVinsList, error) {
|
||||||
|
accountVinsList := AccountVinsList{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(d.Get("account_id").(int)))
|
||||||
|
|
||||||
|
log.Debugf("utilityAccountVinsListCheckPresence: load account list")
|
||||||
|
accountVinsListRaw, err := controller.decortAPICall("POST", accountListVinsAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(accountVinsListRaw), &accountVinsList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountVinsList, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityBasicServiceDeletedListCheckPresence(d *schema.ResourceData, m interface{}) (BasicServiceList, error) {
|
||||||
|
basicServiceDeletedList := BasicServiceList{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
if accountId, ok := d.GetOk("account_id"); ok {
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(accountId.(int)))
|
||||||
|
}
|
||||||
|
if rgId, ok := d.GetOk("rg_id"); ok {
|
||||||
|
urlValues.Add("rgId", strconv.Itoa(rgId.(int)))
|
||||||
|
}
|
||||||
|
if page, ok := d.GetOk("page"); ok {
|
||||||
|
urlValues.Add("page", strconv.Itoa(page.(int)))
|
||||||
|
}
|
||||||
|
if size, ok := d.GetOk("size"); ok {
|
||||||
|
urlValues.Add("size", strconv.Itoa(size.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityBasicServiceDeletedListCheckPresence")
|
||||||
|
basicServiceDeletedListRaw, err := controller.decortAPICall("POST", bserviceListDeletedAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(basicServiceDeletedListRaw), &basicServiceDeletedList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return basicServiceDeletedList, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityBasicServiceCheckPresence(d *schema.ResourceData, m interface{}) (*BasicServiceExtend, error) {
|
||||||
|
bservice := &BasicServiceExtend{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
if (strconv.Itoa(d.Get("service_id").(int))) != "0" {
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("serviceId", d.Id())
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityBasicServiceCheckPresence")
|
||||||
|
bserviceRaw, err := controller.decortAPICall("POST", bserviceGetAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(bserviceRaw), &bservice)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bservice, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityBasicServiceGroupCheckPresence(d *schema.ResourceData, m interface{}) (*BasicServiceGroup, error) {
|
||||||
|
bserviceGroup := &BasicServiceGroup{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(d.Get("service_id").(int)))
|
||||||
|
if (strconv.Itoa(d.Get("compgroup_id").(int))) != "0" {
|
||||||
|
urlValues.Add("compgroupId", strconv.Itoa(d.Get("compgroup_id").(int)))
|
||||||
|
} else {
|
||||||
|
urlValues.Add("compgroupId", d.Id())
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityBasicServiceGroupCheckPresence")
|
||||||
|
bserviceGroupRaw, err := controller.decortAPICall("POST", bserviceGroupGetAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(bserviceGroupRaw), &bserviceGroup)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bserviceGroup, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityBasicServiceListCheckPresence(d *schema.ResourceData, m interface{}) (BasicServiceList, error) {
|
||||||
|
basicServiceList := BasicServiceList{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
if accountId, ok := d.GetOk("account_id"); ok {
|
||||||
|
urlValues.Add("accountId", strconv.Itoa(accountId.(int)))
|
||||||
|
}
|
||||||
|
if rgId, ok := d.GetOk("rg_id"); ok {
|
||||||
|
urlValues.Add("rgId", strconv.Itoa(rgId.(int)))
|
||||||
|
}
|
||||||
|
if page, ok := d.GetOk("page"); ok {
|
||||||
|
urlValues.Add("page", strconv.Itoa(page.(int)))
|
||||||
|
}
|
||||||
|
if size, ok := d.GetOk("size"); ok {
|
||||||
|
urlValues.Add("size", strconv.Itoa(size.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityBasicServiceListCheckPresence")
|
||||||
|
basicServiceListRaw, err := controller.decortAPICall("POST", bserviceListAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(basicServiceListRaw), &basicServiceList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return basicServiceList, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2022 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Stanislav Solovev, <spsolovev@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityBasicServiceSnapshotListCheckPresence(d *schema.ResourceData, m interface{}) (BasicServiceSnapshots, error) {
|
||||||
|
basicServiceSnapshotList := BasicServiceSnapshots{}
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
if serviceId, ok := d.GetOk("service_id"); ok {
|
||||||
|
urlValues.Add("serviceId", strconv.Itoa(serviceId.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityBasicServiceSnapshotListCheckPresence")
|
||||||
|
basicServiceSnapshotListRaw, err := controller.decortAPICall("POST", bserviceSnapshotListAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(basicServiceSnapshotListRaw), &basicServiceSnapshotList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return basicServiceSnapshotList, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
// "github.com/hashicorp/terraform-plugin-sdk/helper/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (ctrl *ControllerCfg) utilityComputeExtraDisksConfigure(d *schema.ResourceData, do_delta bool) error {
|
||||||
|
// d is filled with data according to computeResource schema, so extra disks config is retrieved via "extra_disks" key
|
||||||
|
// If do_delta is true, this function will identify changes between new and existing specs for extra disks and try to
|
||||||
|
// update compute configuration accordingly
|
||||||
|
// Otherwise it will apply whatever is found in the new set of "extra_disks" right away.
|
||||||
|
// Primary use of do_delta=false is when calling this function from compute Create handler.
|
||||||
|
|
||||||
|
// Note that this function will not abort on API errors, but will continue to configure (attach / detach) other individual
|
||||||
|
// disks via atomic API calls. However, it will not retry failed manipulation on the same disk.
|
||||||
|
log.Debugf("utilityComputeExtraDisksConfigure: called for Compute ID %s with do_delta = %t", d.Id(), do_delta)
|
||||||
|
|
||||||
|
// NB: as of rc-1.25 "extra_disks" are TypeSet with the elem of TypeInt
|
||||||
|
old_set, new_set := d.GetChange("extra_disks")
|
||||||
|
|
||||||
|
apiErrCount := 0
|
||||||
|
var lastSavedError error
|
||||||
|
|
||||||
|
if !do_delta {
|
||||||
|
if new_set.(*schema.Set).Len() < 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, disk := range new_set.(*schema.Set).List() {
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("computeId", d.Id())
|
||||||
|
urlValues.Add("diskId", fmt.Sprintf("%d", disk.(int)))
|
||||||
|
_, err := ctrl.decortAPICall("POST", ComputeDiskAttachAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
// failed to attach extra disk - partial resource update
|
||||||
|
apiErrCount++
|
||||||
|
lastSavedError = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiErrCount > 0 {
|
||||||
|
log.Errorf("utilityComputeExtraDisksConfigure: there were %d error(s) when attaching disks to Compute ID %s. Last error was: %s",
|
||||||
|
apiErrCount, d.Id(), lastSavedError)
|
||||||
|
return lastSavedError
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
detach_set := old_set.(*schema.Set).Difference(new_set.(*schema.Set))
|
||||||
|
log.Debugf("utilityComputeExtraDisksConfigure: detach set has %d items for Compute ID %s", detach_set.Len(), d.Id())
|
||||||
|
for _, diskId := range detach_set.List() {
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("computeId", d.Id())
|
||||||
|
urlValues.Add("diskId", fmt.Sprintf("%d", diskId.(int)))
|
||||||
|
_, err := ctrl.decortAPICall("POST", ComputeDiskDetachAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
// failed to detach disk - there will be partial resource update
|
||||||
|
log.Errorf("utilityComputeExtraDisksConfigure: failed to detach disk ID %d from Compute ID %s: %s", diskId.(int), d.Id(), err)
|
||||||
|
apiErrCount++
|
||||||
|
lastSavedError = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attach_set := new_set.(*schema.Set).Difference(old_set.(*schema.Set))
|
||||||
|
log.Debugf("utilityComputeExtraDisksConfigure: attach set has %d items for Compute ID %s", attach_set.Len(), d.Id())
|
||||||
|
for _, diskId := range attach_set.List() {
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
urlValues.Add("computeId", d.Id())
|
||||||
|
urlValues.Add("diskId", fmt.Sprintf("%d", diskId.(int)))
|
||||||
|
_, err := ctrl.decortAPICall("POST", ComputeDiskAttachAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
// failed to attach disk - there will be partial resource update
|
||||||
|
log.Errorf("utilityComputeExtraDisksConfigure: failed to attach disk ID %d to Compute ID %s: %s", diskId.(int), d.Id(), err)
|
||||||
|
apiErrCount++
|
||||||
|
lastSavedError = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiErrCount > 0 {
|
||||||
|
log.Errorf("utilityComputeExtraDisksConfigure: there were %d error(s) when managing disks of Compute ID %s. Last error was: %s",
|
||||||
|
apiErrCount, d.Id(), lastSavedError)
|
||||||
|
return lastSavedError
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctrl *ControllerCfg) utilityComputeNetworksConfigure(d *schema.ResourceData, do_delta bool) error {
|
||||||
|
// "d" is filled with data according to computeResource schema, so extra networks config is retrieved via "network" key
|
||||||
|
// If do_delta is true, this function will identify changes between new and existing specs for network and try to
|
||||||
|
// update compute configuration accordingly
|
||||||
|
// Otherwise it will apply whatever is found in the new set of "network" right away.
|
||||||
|
// Primary use of do_delta=false is when calling this function from compute Create handler.
|
||||||
|
|
||||||
|
old_set, new_set := d.GetChange("network")
|
||||||
|
|
||||||
|
apiErrCount := 0
|
||||||
|
var lastSavedError error
|
||||||
|
|
||||||
|
if !do_delta {
|
||||||
|
if new_set.(*schema.Set).Len() < 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, runner := range new_set.(*schema.Set).List() {
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
net_data := runner.(map[string]interface{})
|
||||||
|
urlValues.Add("computeId", d.Id())
|
||||||
|
urlValues.Add("netType", net_data["net_type"].(string))
|
||||||
|
urlValues.Add("netId", fmt.Sprintf("%d", net_data["net_id"].(int)))
|
||||||
|
ipaddr, ipSet := net_data["ip_address"] // "ip_address" key is optional
|
||||||
|
if ipSet {
|
||||||
|
urlValues.Add("ipAddr", ipaddr.(string))
|
||||||
|
}
|
||||||
|
_, err := ctrl.decortAPICall("POST", ComputeNetAttachAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
// failed to attach network - partial resource update
|
||||||
|
apiErrCount++
|
||||||
|
lastSavedError = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiErrCount > 0 {
|
||||||
|
log.Errorf("utilityComputeNetworksConfigure: there were %d error(s) when managing networks of Compute ID %s. Last error was: %s",
|
||||||
|
apiErrCount, d.Id(), lastSavedError)
|
||||||
|
return lastSavedError
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
detach_set := old_set.(*schema.Set).Difference(new_set.(*schema.Set))
|
||||||
|
log.Debugf("utilityComputeNetworksConfigure: detach set has %d items for Compute ID %s", detach_set.Len(), d.Id())
|
||||||
|
for _, runner := range detach_set.List() {
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
net_data := runner.(map[string]interface{})
|
||||||
|
urlValues.Add("computeId", d.Id())
|
||||||
|
urlValues.Add("ipAddr", net_data["ip_address"].(string))
|
||||||
|
urlValues.Add("mac", net_data["mac"].(string))
|
||||||
|
_, err := ctrl.decortAPICall("POST", ComputeNetDetachAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
// failed to detach this network - there will be partial resource update
|
||||||
|
log.Errorf("utilityComputeNetworksConfigure: failed to detach net ID %d of type %s from Compute ID %s: %s",
|
||||||
|
net_data["net_id"].(int), net_data["net_type"].(string), d.Id(), err)
|
||||||
|
apiErrCount++
|
||||||
|
lastSavedError = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attach_set := new_set.(*schema.Set).Difference(old_set.(*schema.Set))
|
||||||
|
log.Debugf("utilityComputeNetworksConfigure: attach set has %d items for Compute ID %s", attach_set.Len(), d.Id())
|
||||||
|
for _, runner := range attach_set.List() {
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
net_data := runner.(map[string]interface{})
|
||||||
|
urlValues.Add("computeId", d.Id())
|
||||||
|
urlValues.Add("netId", fmt.Sprintf("%d", net_data["net_id"].(int)))
|
||||||
|
urlValues.Add("netType", net_data["net_type"].(string))
|
||||||
|
if net_data["ip_address"].(string) != "" {
|
||||||
|
urlValues.Add("ipAddr", net_data["ip_address"].(string))
|
||||||
|
}
|
||||||
|
_, err := ctrl.decortAPICall("POST", ComputeNetAttachAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
// failed to attach this network - there will be partial resource update
|
||||||
|
log.Errorf("utilityComputeNetworksConfigure: failed to attach net ID %d of type %s to Compute ID %s: %s",
|
||||||
|
net_data["net_id"].(int), net_data["net_type"].(string), d.Id(), err)
|
||||||
|
apiErrCount++
|
||||||
|
lastSavedError = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiErrCount > 0 {
|
||||||
|
log.Errorf("utilityComputeNetworksConfigure: there were %d error(s) when managing networks of Compute ID %s. Last error was: %s",
|
||||||
|
apiErrCount, d.Id(), lastSavedError)
|
||||||
|
return lastSavedError
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func utilityComputeCheckPresence(d *schema.ResourceData, m interface{}) (string, error) {
|
||||||
|
// This function tries to locate Compute by one of the following approaches:
|
||||||
|
// - if compute_id is specified - locate by compute ID
|
||||||
|
// - if compute_name is specified - locate by a combination of compute name and resource
|
||||||
|
// group ID
|
||||||
|
//
|
||||||
|
// If succeeded, it returns non-empty string that contains JSON formatted facts about the
|
||||||
|
// Compute as returned by compute/get API call.
|
||||||
|
// Otherwise it returns empty string and meaningful error.
|
||||||
|
//
|
||||||
|
// This function does not modify its ResourceData argument, so it is safe to use it as core
|
||||||
|
// method for resource's Exists method.
|
||||||
|
//
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
// make it possible to use "read" & "check presence" functions with compute ID set so
|
||||||
|
// that Import of Compute resource is possible
|
||||||
|
idSet := false
|
||||||
|
theId, err := strconv.Atoi(d.Id())
|
||||||
|
if err != nil || theId <= 0 {
|
||||||
|
computeId, argSet := d.GetOk("compute_id") // NB: compute_id is NOT present in computeResource schema!
|
||||||
|
if argSet {
|
||||||
|
theId = computeId.(int)
|
||||||
|
idSet = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
idSet = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if idSet {
|
||||||
|
// compute ID is specified, try to get compute instance straight by this ID
|
||||||
|
log.Debugf("utilityComputeCheckPresence: locating compute by its ID %d", theId)
|
||||||
|
urlValues.Add("computeId", fmt.Sprintf("%d", theId))
|
||||||
|
computeFacts, err := controller.decortAPICall("POST", ComputeGetAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return computeFacts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID was not set in the schema upon entering this function - work through Compute name
|
||||||
|
// and RG ID
|
||||||
|
computeName, argSet := d.GetOk("name")
|
||||||
|
if !argSet {
|
||||||
|
return "", fmt.Errorf("Cannot locate compute instance if name is empty and no compute ID specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
rgId, argSet := d.GetOk("rg_id")
|
||||||
|
if !argSet {
|
||||||
|
return "", fmt.Errorf("Cannot locate compute by name %s if no resource group ID is set", computeName.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues.Add("rgId", fmt.Sprintf("%d", rgId))
|
||||||
|
apiResp, err := controller.decortAPICall("POST", RgListComputesAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityComputeCheckPresence: ready to unmarshal string %s", apiResp)
|
||||||
|
|
||||||
|
computeList := RgListComputesResp{}
|
||||||
|
err = json.Unmarshal([]byte(apiResp), &computeList)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// log.Printf("%#v", computeList)
|
||||||
|
log.Debugf("utilityComputeCheckPresence: traversing decoded JSON of length %d", len(computeList))
|
||||||
|
for index, item := range computeList {
|
||||||
|
// need to match Compute by name, skip Computes with the same name in DESTROYED satus
|
||||||
|
if item.Name == computeName.(string) && item.Status != "DESTROYED" {
|
||||||
|
log.Debugf("utilityComputeCheckPresence: index %d, matched name %s", index, item.Name)
|
||||||
|
// we found the Compute we need - now get detailed information via compute/get API
|
||||||
|
cgetValues := &url.Values{}
|
||||||
|
cgetValues.Add("computeId", fmt.Sprintf("%d", item.ID))
|
||||||
|
apiResp, err = controller.decortAPICall("POST", ComputeGetAPI, cgetValues)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return apiResp, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil // there should be no error if Compute does not exist
|
||||||
|
}
|
||||||
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
|
||||||
|
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
|
||||||
|
Technology platfom.
|
||||||
|
|
||||||
|
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package decort
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func utilityDiskCheckPresence(d *schema.ResourceData, m interface{}) (string, error) {
|
||||||
|
// This function tries to locate Disk by one of the following algorithms depending on
|
||||||
|
// the parameters passed:
|
||||||
|
// - if disk ID is specified -> by disk ID
|
||||||
|
// - if disk name is specifeid -> by disk name and either account ID or account name
|
||||||
|
//
|
||||||
|
// NOTE: disk names are not unique, so the first occurence of this name in the account will
|
||||||
|
// be returned. There is no such ambiguity when locating disk by its ID.
|
||||||
|
//
|
||||||
|
// If succeeded, it returns non empty string that contains JSON formatted facts about the disk
|
||||||
|
// as returned by disks/get API call.
|
||||||
|
// Otherwise it returns empty string and meaningful error.
|
||||||
|
//
|
||||||
|
// This function does not modify its ResourceData argument, so it is safe to use it as core
|
||||||
|
// method for resource's Exists method.
|
||||||
|
//
|
||||||
|
|
||||||
|
controller := m.(*ControllerCfg)
|
||||||
|
urlValues := &url.Values{}
|
||||||
|
|
||||||
|
// make it possible to use "read" & "check presence" functions with disk ID set so
|
||||||
|
// that Import of preexisting Disk resource is possible
|
||||||
|
idSet := false
|
||||||
|
theId, err := strconv.Atoi(d.Id())
|
||||||
|
if err != nil || theId <= 0 {
|
||||||
|
diskId, argSet := d.GetOk("disk_id")
|
||||||
|
if argSet {
|
||||||
|
theId = diskId.(int)
|
||||||
|
idSet = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
idSet = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if idSet {
|
||||||
|
// disk ID is specified, try to get disk instance straight by this ID
|
||||||
|
log.Debugf("utilityDiskCheckPresence: locating disk by its ID %d", theId)
|
||||||
|
urlValues.Add("diskId", fmt.Sprintf("%d", theId))
|
||||||
|
diskFacts, err := controller.decortAPICall("POST", DisksGetAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return diskFacts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID or disk_di was not set in the schema upon entering this function - rely on Disk name
|
||||||
|
// and Account ID to find the disk
|
||||||
|
diskName, argSet := d.GetOk("name")
|
||||||
|
if !argSet {
|
||||||
|
// no disk ID and no disk name - we cannot locate disk in this case
|
||||||
|
return "", fmt.Errorf("Cannot locate disk if name is empty and no disk ID specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid account ID is required to locate disks
|
||||||
|
// obtain Account ID by account name - it should not be zero on success
|
||||||
|
|
||||||
|
urlValues.Add("accountId", fmt.Sprintf("%d", d.Get("account_id").(int)))
|
||||||
|
diskFacts, err := controller.decortAPICall("POST", DisksListAPI, urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("utilityDiskCheckPresence: ready to unmarshal string %s", diskFacts)
|
||||||
|
|
||||||
|
disksList := DisksListResp{}
|
||||||
|
err = json.Unmarshal([]byte(diskFacts), &disksList)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// log.Printf("%#v", vm_list)
|
||||||
|
log.Debugf("utilityDiskCheckPresence: traversing decoded JSON of length %d", len(disksList))
|
||||||
|
for index, item := range disksList {
|
||||||
|
// need to match disk by name, return the first match
|
||||||
|
if item.Name == diskName.(string) && item.Status != "DESTROYED" {
|
||||||
|
log.Debugf("utilityDiskCheckPresence: index %d, matched disk name %q", index, item.Name)
|
||||||
|
// we found the disk we need - not get detailed information via API call to disks/get
|
||||||
|
/*
|
||||||
|
// TODO: this may not be optimal as it initiates one extra call to the DECORT controller
|
||||||
|
// in spite of the fact that we already have all required information about the disk in
|
||||||
|
// item variable
|
||||||
|
//
|
||||||
|
get_urlValues := &url.Values{}
|
||||||
|
get_urlValues.Add("diskId", fmt.Sprintf("%d", item.ID))
|
||||||
|
diskFacts, err = controller.decortAPICall("POST", DisksGetAPI, get_urlValues)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return diskFacts, nil
|
||||||
|
*/
|
||||||
|
reencodedItem, err := json.Marshal(item)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(reencodedItem[:]), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil // there should be no error if disk does not exist
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue