Compare commits

..

13 Commits

Author SHA1 Message Date
kjubybot
95cd7cb820 fixed pfw deletion 2022-02-07 12:19:21 +03:00
kjubybot
06c0578fa6 Merge branch 'rc-1.25' into 1.26 2022-02-07 12:14:31 +03:00
kjubybot
1bf17c23c8 updated id computation for pfw 2022-02-07 12:14:16 +03:00
kjubybot
668d57cd3b updated docs for pfw and kvmvm 2022-02-07 11:50:42 +03:00
kjubybot
fef6040cc6 k8s, k8s_wg resources 2022-02-03 15:20:12 +03:00
kjubybot
d0165918c3 Merge branch 'rc-1.25' into 1.26 2022-02-02 16:30:14 +03:00
kjubybot
dfeb9a9165 compute os_users parsing fix; driver field fix in compute datasource 2022-02-02 16:14:32 +03:00
kjubybot
e0dcd053c5 kubernetes resource (currently broken) 2022-02-02 15:58:20 +03:00
kjubybot
ab070b73cb docs and timeouts for pfw 2022-01-31 11:32:25 +03:00
kjubybot
80a4b70db8 added port forwarding resource 2022-01-27 17:51:44 +03:00
kjubybot
28db919ffa Fixed JSON parsing 2022-01-14 18:04:31 +03:00
kjubybot
3164793f69 added goreleaser, terraform docs 2021-12-29 15:40:57 +03:00
kjubybot
5db588e5dc driver fix; start/stop compute 2021-12-29 14:43:33 +03:00
46 changed files with 2314 additions and 958 deletions

56
.goreleaser.yml Normal file
View File

@@ -0,0 +1,56 @@
# Visit https://goreleaser.com for documentation on how to customize this
# behavior.
before:
hooks:
# this is just an example and not a requirement for provider building/publishing
- go mod tidy
builds:
- env:
# goreleaser does not work with CGO, it could also complicate
# usage by users in CI/CD systems like Terraform Cloud where
# they are unable to install libraries.
- CGO_ENABLED=0
mod_timestamp: '{{ .CommitTimestamp }}'
flags:
- -trimpath
goos:
- freebsd
- windows
- linux
- darwin
goarch:
- amd64
- '386'
ignore:
- goos: darwin
goarch: '386'
binary: '{{ .ProjectName }}_v{{ .Version }}'
archives:
- format: zip
name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}'
checksum:
extra_files:
- glob: 'terraform-registry-manifest.json'
name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json'
name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS'
algorithm: sha256
signs:
- artifacts: checksum
args:
# if you are using this in a GitHub action or some other automated pipeline, you
# need to pass the batch flag to indicate its not interactive.
- "--batch"
- "--local-user"
- "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key
- "--output"
- "${signature}"
- "--detach-sign"
- "${artifact}"
release:
extra_files:
- glob: 'terraform-registry-manifest.json'
name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json'
# If you want to manually examine the release before its live, uncomment this line:
# draft: true
changelog:
skip: true

View File

@@ -1,7 +1,7 @@
# terraform-provider-decort
Terraform provider for Digital Energy Cloud Orchestration Technology (DECORT) platform
NOTE: provider rc-1.40 is designed for DECORT API 3.7.x. For older API versions please use:
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)

View File

@@ -25,7 +25,6 @@ Visit https://github.com/rudecs/terraform-provider-decort for full source code p
package decort
import (
"bytes"
"crypto/tls"
"fmt"
@@ -34,6 +33,7 @@ import (
"net/url"
"strconv"
"strings"
// "time"
log "github.com/sirupsen/logrus"
@@ -42,7 +42,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
// "github.com/hashicorp/terraform-plugin-sdk/terraform"
)
// enumerated constants that define authentication modes
@@ -132,12 +131,12 @@ func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) {
}
ret_config.auth_mode_code = MODE_LEGACY
default:
return nil, fmt.Errorf("Unknown authenticator mode %s provided.", ret_config.auth_mode_txt)
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},}
transCfg := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
ret_config.cc_client = &http.Client{
Transport: transCfg,
Timeout: Timeout180s,
@@ -195,7 +194,7 @@ func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) {
return ret_config, nil
}
func (config *ControllerCfg) getDecortUsername() (string) {
func (config *ControllerCfg) getDecortUsername() string {
return config.decort_username
}
@@ -205,7 +204,7 @@ func (config *ControllerCfg) getOAuth2JWT() (string, error) {
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 %s.", config.auth_mode_txt)
return "", fmt.Errorf("getOAuth2JWT method called for incompatible authorization mode %q.", config.auth_mode_txt)
}
params := url.Values{}
@@ -216,7 +215,7 @@ func (config *ControllerCfg) getOAuth2JWT() (string, error) {
params.Add("validity", "3600")
params_str := params.Encode()
req, err := http.NewRequest("POST", config.oauth2_url + "/v1/oauth/access_token", strings.NewReader(params_str))
req, err := http.NewRequest("POST", config.oauth2_url+"/v1/oauth/access_token", strings.NewReader(params_str))
if err != nil {
return "", err
}
@@ -231,7 +230,7 @@ func (config *ControllerCfg) getOAuth2JWT() (string, error) {
// 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 %s for APP_ID %s, request Body %s",
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()
@@ -265,7 +264,7 @@ func (config *ControllerCfg) validateJWT(jwt string) (bool, error) {
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)
req, err := http.NewRequest("POST", config.controller_url+"/restmachine/cloudapi/accounts/list", nil)
if err != nil {
return false, err
}
@@ -279,7 +278,7 @@ func (config *ControllerCfg) validateJWT(jwt string) (bool, error) {
return false, err
}
if resp.StatusCode != http.StatusOK {
return false, fmt.Errorf("validateJWT: unexpected status code %d when validating JWT against %s.",
return false, fmt.Errorf("validateJWT: unexpected status code %d when validating JWT against %q.",
resp.StatusCode, req.URL)
}
defer resp.Body.Close()
@@ -298,7 +297,7 @@ func (config *ControllerCfg) validateLegacyUser() (bool, error) {
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 %s.", config.auth_mode_txt)
return false, fmt.Errorf("validateLegacyUser method called for incompatible authorization mode %q.", config.auth_mode_txt)
}
params := url.Values{}
@@ -306,7 +305,7 @@ func (config *ControllerCfg) validateLegacyUser() (bool, error) {
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))
req, err := http.NewRequest("POST", config.controller_url+"/restmachine/cloudapi/users/authenticate", strings.NewReader(params_str))
if err != nil {
return false, err
}
@@ -319,7 +318,7 @@ func (config *ControllerCfg) validateLegacyUser() (bool, error) {
return false, err
}
if resp.StatusCode != http.StatusOK {
return false, fmt.Errorf("validateLegacyUser: unexpected status code %d when validating legacy user %s against %s.",
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()
@@ -335,15 +334,13 @@ func (config *ControllerCfg) validateLegacyUser() (bool, error) {
return true, nil
}
func (config *ControllerCfg) decortAPICall(method string, api_name string, url_values *url.Values) (json_resp string, err error, hrc int) {
func (config *ControllerCfg) decortAPICall(method string, api_name string, url_values *url.Values) (json_resp string, err error) {
// 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.
hrc = 0 // HTTP Response Code
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."), 0
return "", fmt.Errorf("decortAPICall method called with unconfigured DECORT cloud controller HTTP client.")
}
// Example: to create api_params, one would generally do the following:
@@ -361,7 +358,7 @@ func (config *ControllerCfg) decortAPICall(method string, api_name string, url_v
//
if config.auth_mode_code == MODE_UNDEF {
return "", fmt.Errorf("decortAPICall method called for unknown authorization mode."), 0
return "", fmt.Errorf("decortAPICall method called for unknown authorization mode.")
}
if config.auth_mode_code == MODE_LEGACY {
@@ -369,12 +366,13 @@ func (config *ControllerCfg) decortAPICall(method string, api_name string, url_v
}
params_str := url_values.Encode()
req, err := http.NewRequest(method, config.controller_url + api_name, strings.NewReader(params_str))
req, err := http.NewRequest(method, config.controller_url+api_name, strings.NewReader(params_str))
if err != nil {
return "", err, 0
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))
@@ -382,29 +380,26 @@ func (config *ControllerCfg) decortAPICall(method string, api_name string, url_v
resp, err := config.cc_client.Do(req)
if err != nil {
return "", err, 0
return "", err
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
tmp_body, err := ioutil.ReadAll(resp.Body)
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err, resp.StatusCode
return "", err
}
json_resp := Jo2JSON(string(tmp_body))
log.Debugf("decortAPICall: %s %s\n %s", method, api_name, json_resp)
return json_resp, nil, resp.StatusCode
log.Debugf("decortAPICall: %s %s\n %s", method, api_name, body)
if resp.StatusCode == http.StatusOK {
return string(body), nil
} else {
return "", fmt.Errorf("decortAPICall: unexpected status code %d when calling API %s with request Body %s",
resp.StatusCode, req.URL, params_str), resp.StatusCode
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)
}
/*
if resp.StatusCode == StatusServiceUnavailable {
return nil, fmt.Errorf("decortAPICall method called for incompatible authorization mode %s.", config.auth_mode_txt), resp.StatusCode
return nil, fmt.Errorf("decortAPICall method called for incompatible authorization mode %q.", config.auth_mode_txt)
}
*/
return "", err, resp.StatusCode
}

View File

@@ -27,6 +27,7 @@ package decort
import (
"encoding/json"
"fmt"
// "net/url"
log "github.com/sirupsen/logrus"
@@ -43,7 +44,7 @@ func parseComputeDisksToExtraDisks(disks []DiskRecord) []interface{} {
length := len(disks)
log.Debugf("parseComputeDisksToExtraDisks: called for %d disks", length)
if length == 0 || ( length == 1 && disks[0].Type == "B" ) {
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
@@ -175,6 +176,32 @@ func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord) []interface{} {
return result
}
/*
func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord) []map[string]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 := make([]map[string]interface{}, length, length)
for i, 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[i] = elem
}
return result
}
*/
// NOTE: this function is retained for historical purposes and actually not used as of rc-1.10
func parseComputeInterfaces(ifaces []InterfaceRecord) []map[string]interface{} {
// return value was designed to d.Set("interfaces",) item of dataSourceCompute schema
@@ -236,7 +263,7 @@ func flattenCompute(d *schema.ResourceData, compFacts string) error {
d.Set("rg_name", model.RgName)
d.Set("account_id", model.AccountID)
d.Set("account_name", model.AccountName)
d.Set("arch", model.Arch)
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
@@ -248,6 +275,12 @@ func flattenCompute(d *schema.ResourceData, compFacts string) error {
// d.Set("status", model.Status)
// d.Set("tech_status", model.TechStatus)
if model.TechStatus == "STARTED" {
d.Set("started", true)
} else {
d.Set("started", false)
}
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 {
@@ -334,7 +367,7 @@ func dataSourceCompute() *schema.Resource {
Description: "Name of the account this compute instance belongs to.",
},
"arch": {
"driver": {
Type: schema.TypeString,
Computed: true,
Description: "Hardware architecture of this compute instance.",
@@ -380,7 +413,7 @@ func dataSourceCompute() *schema.Resource {
Type: schema.TypeSet,
Computed: true,
MaxItems: MaxExtraDisksPerCompute,
Elem: &schema.Schema {
Elem: &schema.Schema{
Type: schema.TypeInt,
},
Description: "IDs of the extra disk(s) attached to this compute.",
@@ -439,6 +472,13 @@ func dataSourceCompute() *schema.Resource {
Description: "Placeholder for cloud_init parameters.",
},
"started": {
Type: schema.TypeBool,
Optional: true,
Default: true,
Description: "Is compute started.",
},
/*
"status": {
Type: schema.TypeString,

View File

@@ -45,7 +45,7 @@ func dataSourceImageRead(d *schema.ResourceData, m interface{}) error {
if accSet {
url_values.Add("accountId", fmt.Sprintf("%d", accId.(int)))
}
body_string, err, _ := controller.decortAPICall("POST", ImagesListAPI, url_values)
body_string, err := controller.decortAPICall("POST", ImagesListAPI, url_values)
if err != nil {
return err
}

View File

@@ -1,144 +0,0 @@
/*
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 (
"encoding/json"
"fmt"
// "hash/fnv"
log "github.com/sirupsen/logrus"
// "net/url"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
)
func flattenPfw(d *schema.ResourceData, pfwFacts string) error {
// NOTE: this function modifies ResourceData argument - as such it should never be called
// from resourcePfwExists(...) method
pfwRecord := ComputePfwListResp{}
err := json.Unmarshal([]byte(pfwFacts), &pfwRecord)
if err != nil {
return err
}
log.Debugf("flattenPfw: decoded %d PFW rules for compute ID %s on ViNS ID %d",
len(pfwRecord.Rules), pfwRecord.Header.VinsID, pfwRecord.Header.VinsID)
/*
Here it gets a little bit interesting.
Unlike compute or disk, port forwaring rules are NOT represented by any cloud
platform resource, which might have had a unique ID. They are just a subset of
rules in the list maintained by the corresponding ViNS instance. However,
Terraform needs a unique ID for each resource it manages so that it could be
stored in the state file and retrieved for use.
Therefore we need to make up an ID and supply it to Terraform in a standard
way (i.e. by calling d.SetId(...)).
Fortunately, a combination of Compute ID and ViNS ID with GW VNF, where this
compute is plugged in, makes a unique string, so we use it as an ID for
the PFW ruleset.
The following few lines are legacy from the first attempt to make an ID
as a hash of concatenated Compute ID & ViNS ID, but it did not work as
expected for a number of reasons, which explanation is not a primary
intent of the comment in the source code.
combo := fmt.Sprintf("%d:%d", compId.(int), pfwRecord.ViNS.VinsID)
hasher := fnv.New32a()
hasher.Write([]byte(combo))
d.SetId(fmt.Sprintf("%d", hasher.Sum32()))
*/
// set ID of this PFW rule set as "compute_id:vins_id"
d.SetId(fmt.Sprintf("%d:%d", pfwRecord.Header.ComputeID, pfwRecord.Header.VinsID))
log.Debugf("flattenPfw: PFW rule set ID %s", d.Id())
d.Set("compute_id", pfwRecord.Header.ComputeID)
d.Set("vins_id", pfwRecord.Header.VinsID)
pfwRulesList := []interface{}{}
for _, runner := range pfwRecord.Rules {
rule := map[string]interface{}{
"pub_port_start": runner.PublicPortStart,
"pub_port_end": runner.PublicPortEnd,
"local_port": runner.LocalPort,
"proto": runner.Protocol,
"rule_id": runner.ID,
}
pfwRulesList = append(pfwRulesList, rule)
}
if err = d.Set("rule", pfwRulesList); err != nil {
return err
}
return nil
}
func dataSourcePfwRead(d *schema.ResourceData, m interface{}) error {
pfwFacts, err := utilityPfwCheckPresence(d, m)
if pfwFacts == "" {
// if empty string is returned from dataSourcePfwRead then we got no
// PFW rules. It could also be because there was some error, which
// is indicated by non-nil err value
d.SetId("") // ensure ID is empty in this case anyway
return err
}
return flattenPfw(d, pfwFacts)
}
func dataSourcePfw() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,
Read: dataSourcePfwRead,
Timeouts: &schema.ResourceTimeout{
Read: &Timeout30s,
Default: &Timeout60s,
},
Schema: map[string]*schema.Schema{
"compute_id": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntAtLeast(1),
Description: "ID of the compute instance to configure port forwarding rules for.",
},
"vins_id": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntAtLeast(1),
Description: "ID of the ViNS to configure port forwarding rules on. Compute must be already plugged into this ViNS and ViNS must have external network connection.",
},
// TODO: consider making "rule" attribute Required with MinItems = 1
"rule": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: rulesSubresourceSchemaMake(),
},
Description: "Port forwarding rule. You may specify several rules, one in each such block.",
},
},
}
}

View File

@@ -25,6 +25,8 @@ Visit https://github.com/rudecs/terraform-provider-decort for full source code p
package decort
import (
"bytes"
"strconv"
"time"
)
@@ -203,6 +205,7 @@ type KvmVmCreateParam struct { // this is unified structure for both x86 and PPC
// structures related to cloudapi/compute/start API
const ComputeStartAPI = "/restmachine/cloudapi/compute/start"
const ComputeStopAPI = "/restmachine/cloudapi/compute/stop"
// structures related to cloudapi/compute/delete API
const ComputeDeleteAPI = "/restmachine/cloudapi/compute/delete"
@@ -355,6 +358,7 @@ type ComputeGetResp struct {
Cpu int `json:"cpus"`
Desc string `json:"desc"`
Disks []DiskRecord `json:"disks"`
Driver string `json:"driver"`
GridID int `json:"gid"`
ID uint `json:"id"`
ImageID int `json:"imageId"`
@@ -446,20 +450,7 @@ type AccountsListResp []AccountRecord
//
// structures related to /cloudapi/portforwarding/list API
//
// Note the specifics of compute/pfwList response in API 3.7.x (this may be changed in the future):
// 1) if there are no PFW rules and compute is not connected to any PFW-able ViNS
// the response will be empty string
// 2) if there are no PFW rules but compute is connected to a PFW-able ViNS
// the response will contain a list with a single element - prefix (see PfwPrefixRecord)
// 3) if there are port forwarding rules, the response will contain a list which starts
// with prefix (see PfwPrefixRecord) and then followed by one or more rule records
// (see PfwRuleRecord)
type PfwPrefixRecord struct {
VinsID int `json:"vinsId"`
VinsName string `json:"vinsName"`
ComputeID int `json:"computeId"`
}
type PfwRuleRecord struct {
type PfwRecord struct {
ID int `json:"id"`
LocalIP string `json:"localIp"`
LocalPort int `json:"localPort"`
@@ -469,13 +460,10 @@ type PfwRuleRecord struct {
ComputeID int `json:"vmId"`
}
type ComputePfwListResp struct {
Header PfwPrefixRecord `json:"header"`
Rules []PfwRuleRecord `json:"rules"`
}
const ComputePfwListAPI = "/restmachine/cloudapi/compute/pfwList"
type ComputePfwListResp []PfwRecord
const ComputePfwAddAPI = "/restmachine/cloudapi/compute/pfwAdd"
const ComputePfwDelAPI = "/restmachine/cloudapi/compute/pfwDel"
@@ -489,6 +477,7 @@ type ComputeNetMgmtRecord struct { // used to "cache" network specs when prepari
IPAddress string
MAC string
}
const ComputeNetAttachAPI = "/restmachine/cloudapi/compute/netAttach"
const ComputeNetDetachAPI = "/restmachine/cloudapi/compute/netDetach"
@@ -528,7 +517,6 @@ const DisksRenameAPI = "/restmachine/cloudapi/disks/rename"
//
const DisksDeleteAPI = "/restmachine/cloudapi/disks/delete"
//
// ViNS structures
//
@@ -547,6 +535,7 @@ type VinsSearchRecord struct {
}
const VinsSearchAPI = "/restmachine/cloudapi/vins/search"
type VinsSearchResp []VinsSearchRecord
type VnfRecord struct {
@@ -586,6 +575,76 @@ const VinsExtNetDisconnectAPI = "/restmachine/cloudapi/vins/extNetDisconnect"
const VinsDeleteAPI = "/restmachine/cloudapi/vins/delete"
//
// K8s structures
//
//K8sNodeRecord represents a worker/master group
type K8sNodeRecord struct {
ID int `json:"id"`
Disk int `json:"disk"`
Cpu int `json:"cpu"`
Num int `json:"num"`
Ram int `json:"ram"`
}
//K8sRecord represents k8s instance
type K8sRecord struct {
AccountID int `json:"accountId"`
AccountName string `json:"accountName"`
CI int `json:"ciId"`
ID int `json:"id"`
Groups struct {
Masters K8sNodeRecord `json:"masters"`
Workers []K8sNodeRecord `json:"workers"`
} `json:"k8sGroups"`
Name string `json:"name"`
RgID int `json:"rgId"`
RgName string `json:"rgName"`
}
const K8sCreateAPI = "/restmachine/cloudapi/k8s/create"
const K8sGetAPI = "/restmachine/cloudapi/k8s/get"
const K8sUpdateAPI = "/restmachine/cloudapi/k8s/update"
const K8sDeleteAPI = "/restmachine/cloudapi/k8s/delete"
const K8sWgCreateAPI = "/restmachine/cloudapi/k8s/workersGroupAdd"
const K8sWgDeleteAPI = "/restmachine/cloudapi/k8s/workersGroupDelete"
//Blasphemous workaround for parsing Result value
type TaskResult int
func (r *TaskResult) UnmarshalJSON(b []byte) error {
b = bytes.Trim(b, `"`)
if len(b) == 0 {
*r = 0
return nil
}
n, err := strconv.Atoi(string(b))
if err != nil {
return err
}
*r = TaskResult(n)
return nil
}
//AsyncTask represents a long task completion status
type AsyncTask struct {
AuditID string `json:"auditId"`
Completed bool `json:"completed"`
Error string `json:"error"`
Log []string `json:"log"`
Result TaskResult `json:"result"`
Stage string `json:"stage"`
Status string `json:"status"`
UpdateTime uint64 `json:"updateTime"`
UpdatedTime uint64 `json:"updatedTime"`
}
const AsyncTaskGetAPI = "/restmachine/cloudapi/tasks/get"
//
// Grid ID structures
//

100
decort/node_subresource.go Normal file
View File

@@ -0,0 +1,100 @@
/*
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["id"] = node.ID
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,
ForceNew: 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.",
},
}
}

View File

@@ -27,9 +27,9 @@ import (
func parseOsUsers(logins []OsUserRecord) []interface{} {
var result = make([]interface{}, len(logins))
for index, value := range logins {
elem := make(map[string]interface{})
for index, value := range logins {
elem["guid"] = value.Guid
elem["login"] = value.Login
elem["password"] = value.Password

View File

@@ -104,6 +104,8 @@ func Provider() *schema.Provider {
"decort_disk": resourceDisk(),
"decort_vins": resourceVins(),
"decort_pfw": resourcePfw(),
"decort_k8s": resourceK8s(),
"decort_k8s_wg": resourceK8sWg(),
},
DataSourcesMap: map[string]*schema.Resource{
@@ -113,7 +115,7 @@ func Provider() *schema.Provider {
"decort_image": dataSourceImage(),
"decort_disk": dataSourceDisk(),
"decort_vins": dataSourceVins(),
"decort_pfw": dataSourcePfw(),
// "decort_pfw": dataSourcePfw(),
},
ConfigureFunc: providerConfigure,

View File

@@ -85,8 +85,8 @@ func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
*/
computeCreateAPI := KvmX86CreateAPI
arch := d.Get("arch").(string)
if arch == "KVM_PPC" {
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
@@ -102,7 +102,7 @@ func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
}
}
apiResp, err, _ := controller.decortAPICall("POST", computeCreateAPI, urlValues)
apiResp, err := controller.decortAPICall("POST", computeCreateAPI, urlValues)
if err != nil {
return err
}
@@ -163,13 +163,15 @@ func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
// 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)
apiResp, err, _ = controller.decortAPICall("POST", ComputeStartAPI, reqValues)
apiResp, err = controller.decortAPICall("POST", ComputeStartAPI, reqValues)
if err != nil {
return err
}
}
log.Debugf("resourceComputeCreate: new Compute ID %d, name %s creation sequence complete", compId, d.Get("name").(string))
@@ -186,7 +188,6 @@ func resourceComputeRead(d *schema.ResourceData, m interface{}) error {
compFacts, err := utilityComputeCheckPresence(d, m)
if compFacts == "" {
d.SetId("")
if err != nil {
return err
}
@@ -215,6 +216,7 @@ func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
2. Resize (grow) boot disk
3. Update extra disks
4. Update networks
5. Start/stop
*/
// 1. Resize CPU/RAM
@@ -244,7 +246,7 @@ func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
log.Debugf("resourceComputeUpdate: changing CPU %d -> %d and/or RAM %d -> %d",
oldCpu.(int), newCpu.(int),
oldRam.(int), newRam.(int))
_, err, _ := controller.decortAPICall("POST", ComputeResizeAPI, params)
_, err := controller.decortAPICall("POST", ComputeResizeAPI, params)
if err != nil {
return err
}
@@ -260,7 +262,7 @@ func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
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, params)
_, err := controller.decortAPICall("POST", DisksResizeAPI, params)
if err != nil {
return err
}
@@ -285,6 +287,21 @@ func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
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
@@ -327,7 +344,7 @@ func resourceComputeDelete(d *schema.ResourceData, m interface{}) error {
detachParams.Add("computeId", d.Id())
detachParams.Add("diskId", fmt.Sprintf("%d", diskFacts.ID))
_, err, _ = controller.decortAPICall("POST", ComputeDiskDetachAPI, detachParams)
_, 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)
@@ -340,7 +357,7 @@ func resourceComputeDelete(d *schema.ResourceData, m interface{}) error {
params.Add("permanently", "1")
// TODO: this is for the upcoming API update - params.Add("detachdisks", "1")
_, err, _ = controller.decortAPICall("POST", ComputeDeleteAPI, params)
_, err = controller.decortAPICall("POST", ComputeDeleteAPI, params)
if err != nil {
return err
}
@@ -399,7 +416,7 @@ func resourceCompute() *schema.Resource {
Description: "ID of the resource group where this compute should be deployed.",
},
"arch": {
"driver": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
@@ -474,7 +491,6 @@ func resourceCompute() *schema.Resource {
Description: "Optional text description of this compute instance.",
},
"cloud_init": {
Type: schema.TypeString,
Optional: true,
@@ -517,6 +533,13 @@ func resourceCompute() *schema.Resource {
Description: "Guest OS users provisioned on this compute instance.",
},
"started": {
Type: schema.TypeBool,
Optional: true,
Default: true,
Description: "Is compute started.",
},
/*
"disks": {
Type: schema.TypeList,

View File

@@ -55,7 +55,7 @@ func resourceDiskCreate(d *schema.ResourceData, m interface{}) error {
urlValues.Add("description", argVal.(string))
}
apiResp, err, _ := controller.decortAPICall("POST", DisksCreateAPI, urlValues)
apiResp, err := controller.decortAPICall("POST", DisksCreateAPI, urlValues)
if err != nil {
return err
}
@@ -105,7 +105,7 @@ func resourceDiskUpdate(d *schema.ResourceData, m interface{}) error {
sizeParams := &url.Values{}
sizeParams.Add("diskId", d.Id())
sizeParams.Add("size", fmt.Sprintf("%d", newSize.(int)))
_, err, _ := controller.decortAPICall("POST", DisksResizeAPI, sizeParams)
_, err := controller.decortAPICall("POST", DisksResizeAPI, sizeParams)
if err != nil {
return err
}
@@ -121,7 +121,7 @@ func resourceDiskUpdate(d *schema.ResourceData, m interface{}) error {
renameParams := &url.Values{}
renameParams.Add("diskId", d.Id())
renameParams.Add("name", newName.(string))
_, err, _ := controller.decortAPICall("POST", DisksRenameAPI, renameParams)
_, err := controller.decortAPICall("POST", DisksRenameAPI, renameParams)
if err != nil {
return err
}
@@ -171,7 +171,7 @@ func resourceDiskDelete(d *schema.ResourceData, m interface{}) error {
params.Add("permanently", "1")
controller := m.(*ControllerCfg)
_, err, _ = controller.decortAPICall("POST", DisksDeleteAPI, params)
_, err = controller.decortAPICall("POST", DisksDeleteAPI, params)
if err != nil {
return err
}

289
decort/resource_k8s.go Normal file
View File

@@ -0,0 +1,289 @@
/*
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)))
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))
//TODO find a way to avoid hardcoding these values
//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)))
//}
urlValues.Add("extnetId", strconv.Itoa(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)
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("masters", nodeToResource(k8s.Groups.Masters))
d.Set("workers", nodeToResource(k8s.Groups.Workers[0]))
d.Set("default_wg_id", k8s.Groups.Workers[0].ID)
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)
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
}
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.",
},
"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,
ForceNew: 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,
//ForceNew: true,
//Default: 0,
//Description: "ID of the external network to connect workers to.",
//},
//"desc": {
//Type: schema.TypeString,
//Optional: true,
//Description: "Text description of this instance.",
//},
"default_wg_id": {
Type: schema.TypeInt,
Computed: true,
Description: "ID of default workers group for this instace.",
},
}
}
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,
},
//TODO timeouts
Schema: resourceK8sSchemaMake(),
}
}

207
decort/resource_k8s_wg.go Normal file
View File

@@ -0,0 +1,207 @@
/*
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/google/uuid"
"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", uuid.New().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)
//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("num", wg.Num)
d.Set("cpu", wg.Cpu)
d.Set("ram", wg.Ram)
d.Set("disk", wg.Disk)
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.",
},
//Unused but required by creation API. Sending generated UUID each time
//"name": {
//Type: schema.TypeString,
//Required: true,
//ForceNew: true,
//Description: "Name of the worker group.",
//},
"num": {
Type: schema.TypeInt,
Optional: true,
ForceNew: 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,
Delete: resourceK8sWgDelete,
Exists: resourceK8sWgExists,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
//TODO timeouts
Schema: resourceK8sWgSchemaMake(),
}
}

View File

@@ -1,6 +1,6 @@
/*
Copyright (c) 2019-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
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.
@@ -15,158 +15,171 @@ 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"
"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 {
compId := d.Get("compute_id")
rules_set, ok := d.GetOk("rule")
if !ok || rules_set.(*schema.Set).Len() == 0 {
log.Debugf("resourcePfwCreate: empty new PFW rules set requested for compute ID %d - nothing to create", compId.(int))
return nil
}
log.Debugf("resourcePfwCreate: ready to setup %d PFW rules for compute ID %d",
rules_set.(*schema.Set).Len(), compId.(int))
log.Debugf("resourcePfwCreate: called for compute %d", d.Get("compute_id").(int))
controller := m.(*ControllerCfg)
apiErrCount := 0
var lastSavedError error
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))
for _, runner := range rules_set.(*schema.Set).List() {
rule := runner.(map[string]interface{})
params := &url.Values{}
params.Add("computeId", fmt.Sprintf("%d", compId.(int)))
params.Add("publicPortStart", fmt.Sprintf("%d", rule["pub_port_start"].(int)))
params.Add("publicPortEnd", fmt.Sprintf("%d", rule["pub_port_end"].(int)))
params.Add("localBasePort", fmt.Sprintf("%d", rule["local_port"].(int)))
params.Add("proto", rule["proto"].(string))
log.Debugf("resourcePfwCreate: ready to add rule %d:%d -> %d %s for Compute ID %d",
rule["pub_port_start"].(int),rule["pub_port_end"].(int),
rule["local_port"].(int), rule["proto"].(string),
compId.(int))
_, err, _ := controller.decortAPICall("POST", ComputePfwAddAPI, params)
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 {
log.Errorf("resourcePfwCreate: error adding rule %d:%d -> %d %s for Compute ID %d: %s",
rule["pub_port_start"].(int),rule["pub_port_end"].(int),
rule["local_port"].(int), rule["proto"].(string),
compId.(int),
err)
apiErrCount++
lastSavedError = err
}
}
if apiErrCount > 0 {
log.Errorf("resourcePfwCreate: there were %d error(s) adding PFW rules to Compute ID %s. Last error was: %s",
apiErrCount, compId.(int), lastSavedError)
return lastSavedError
}
return resourcePfwRead(d, m)
}
func resourcePfwRead(d *schema.ResourceData, m interface{}) error {
pfwFacts, err := utilityPfwCheckPresence(d, m)
if pfwFacts == "" {
// if empty string is returned from dataSourcePfwRead then we got no
// PFW rules. It could also be because there was some error, which
// is indicated by non-nil err value
d.SetId("") // ensure ID is empty in this case anyway
return err
}
return flattenPfw(d, pfwFacts)
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 resourcePfwUpdate(d *schema.ResourceData, m interface{}) error {
// TODO: update not implemented yet
compId := d.Get("compute_id")
return fmt.Errorf("resourcePfwUpdate: method is not implemented yet (Compute ID %d)", compId.(int))
func resourcePfwRead(d *schema.ResourceData, m interface{}) error {
log.Debugf("resourcePfwRead: called for compute %d, rule %s", d.Get("compute_id").(int), d.Id())
// return resourcePfwRead(d, m)
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 {
compId := d.Get("compute_id")
log.Debugf("resourcePfwDelete: called for compute %d, rule %s", d.Get("compute_id").(int), d.Id())
rules_set, ok := d.GetOk("rule")
if !ok || rules_set.(*schema.Set).Len() == 0 {
log.Debugf("resourcePfwDelete: no PFW rules defined for compute ID %d - nothing to delete", compId.(int))
pfw, err := utilityPfwCheckPresence(d, m)
if pfw == nil {
if err != nil {
return err
}
return nil
}
log.Debugf("resourcePfwDelete: ready to delete %d PFW rules from compute ID %d",
rules_set.(*schema.Set).Len(), compId.(int))
controller := m.(*ControllerCfg)
apiErrCount := 0
var lastSavedError error
urlValues := &url.Values{}
urlValues.Add("computeId", strconv.Itoa(d.Get("compute_id").(int)))
urlValues.Add("ruleId", strconv.Itoa(pfw.ID))
for _, runner := range rules_set.(*schema.Set).List() {
rule := runner.(map[string]interface{})
params := &url.Values{}
params.Add("computeId", fmt.Sprintf("%d", compId.(int)))
params.Add("ruleId", fmt.Sprintf("%d", rule["rule_id"].(int)))
log.Debugf("resourcePfwCreate: ready to delete rule ID%s (%d:%d -> %d %s) from Compute ID %d",
rule["rule_id"].(int),
rule["pub_port_start"].(int),rule["pub_port_end"].(int),
rule["local_port"].(int), rule["proto"].(string),
compId.(int))
_, err, _ := controller.decortAPICall("POST", ComputePfwDelAPI, params)
_, err = controller.decortAPICall("POST", ComputePfwDelAPI, urlValues)
if err != nil {
log.Errorf("resourcePfwDelete: error deleting rule ID %d (%d:%d -> %d %s) from Compute ID %d: %s",
rule["rule_id"].(int),
rule["pub_port_start"].(int),rule["pub_port_end"].(int),
rule["local_port"].(int), rule["proto"].(string),
compId.(int),
err)
apiErrCount++
lastSavedError = err
}
}
if apiErrCount > 0 {
log.Errorf("resourcePfwDelete: there were %d error(s) when deleting PFW rules from Compute ID %s. Last error was: %s",
apiErrCount, compId.(int), lastSavedError)
return lastSavedError
return err
}
return nil
}
func resourcePfwExists(d *schema.ResourceData, m interface{}) (bool, error) {
// Reminder: according to Terraform rules, this function should not modify its ResourceData argument
log.Debugf("resourcePfwExists: called for Compute ID %d", d.Get("compute_id").(int))
log.Debugf("resourcePfwExists: called for compute %d, rule %s", d.Get("compute_id").(int), d.Id())
pfwFacts, err := utilityPfwCheckPresence(d, m)
if pfwFacts == "" {
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,
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,
Update: resourcePfwUpdate,
Delete: resourcePfwDelete,
Exists: resourcePfwExists,
@@ -175,38 +188,13 @@ func resourcePfw() *schema.Resource {
},
Timeouts: &schema.ResourceTimeout{
Create: &Timeout180s,
Create: &Timeout60s,
Read: &Timeout30s,
Update: &Timeout180s,
Update: &Timeout60s,
Delete: &Timeout60s,
Default: &Timeout60s,
},
Schema: map[string]*schema.Schema{
"compute_id": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntAtLeast(1),
Description: "ID of the compute instance to configure port forwarding rules for.",
},
"vins_id": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntAtLeast(1),
Description: "ID of the ViNS to configure port forwarding rules on. Compute must be already plugged into this ViNS and ViNS must have external network connection.",
},
// TODO: consider making "rule" attribute Required with MinItems = 1 to prevent
// empty PFW list definition
"rule": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: rulesSubresourceSchemaMake(),
},
Description: "Port forwarding rule. You may specify several rules, one in each such block.",
},
},
Schema: resourcePfwSchemaMake(),
}
}

View File

@@ -115,7 +115,7 @@ func resourceResgroupCreate(d *schema.ResourceData, m interface{}) error {
url_values.Add("extIp", ext_ip.(string))
}
api_resp, err, _ := controller.decortAPICall("POST", ResgroupCreateAPI, url_values)
api_resp, err := controller.decortAPICall("POST", ResgroupCreateAPI, url_values)
if err != nil {
return err
}
@@ -233,7 +233,7 @@ func resourceResgroupUpdate(d *schema.ResourceData, m interface{}) error {
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)
_, err := controller.decortAPICall("POST", ResgroupUpdateAPI, url_values)
if err != nil {
return err
}
@@ -264,7 +264,7 @@ func resourceResgroupDelete(d *schema.ResourceData, m interface{}) error {
url_values.Add("reason", "Destroyed by DECORT Terraform provider")
controller := m.(*ControllerCfg)
_, err, _ = controller.decortAPICall("POST", ResgroupDeleteAPI, url_values)
_, err = controller.decortAPICall("POST", ResgroupDeleteAPI, url_values)
if err != nil {
return err
}

View File

@@ -106,7 +106,7 @@ func resourceVinsCreate(d *schema.ResourceData, m interface{}) error {
urlValues.Add("desc", argVal.(string))
}
apiResp, err, _ := controller.decortAPICall("POST", apiToCall, urlValues)
apiResp, err := controller.decortAPICall("POST", apiToCall, urlValues)
if err != nil {
return err
}
@@ -154,7 +154,7 @@ func resourceVinsUpdate(d *schema.ResourceData, m interface{}) error {
if oldExtNetId.(int) > 0 {
// there was preexisting external net connection - disconnect ViNS
_, err, _ := controller.decortAPICall("POST", VinsExtNetDisconnectAPI, extnetParams)
_, err := controller.decortAPICall("POST", VinsExtNetDisconnectAPI, extnetParams)
if err != nil {
return err
}
@@ -163,7 +163,7 @@ func resourceVinsUpdate(d *schema.ResourceData, m interface{}) error {
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)
_, err := controller.decortAPICall("POST", VinsExtNetConnectAPI, extnetParams)
if err != nil {
return err
}
@@ -196,7 +196,7 @@ func resourceVinsDelete(d *schema.ResourceData, m interface{}) error {
params.Add("permanently", "1") // delete ViNS immediately bypassing recycle bin
controller := m.(*ControllerCfg)
_, err, _ = controller.decortAPICall("POST", VinsDeleteAPI, params)
_, err = controller.decortAPICall("POST", VinsDeleteAPI, params)
if err != nil {
return err
}

View File

@@ -1,77 +0,0 @@
/*
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 (
// "encoding/json"
// "fmt"
// "bytes"
// log "github.com/sirupsen/logrus"
// "net/url"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
)
// This is rules subresource of PFW resource used
// when creating/managing port forwarding rules for a compute connected
// to the corresponding network
func rulesSubresourceSchemaMake() map[string]*schema.Schema {
rets := map[string]*schema.Schema{
"pub_port_start": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntBetween(1, 65535),
Description: "Port number on the external interface. For a ranged rule it set the starting port number.",
},
"pub_port_end": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntBetween(1, 65535),
Description: "End port number on the external interface for a ranged rule. Set it equal to start port for a single port rule.",
},
"local_port": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntBetween(1, 65535),
Description: "Port number on the local interface.",
},
"proto": {
Type: schema.TypeString,
Required: true,
StateFunc: stateFuncToLower,
ValidateFunc: validation.StringInSlice([]string{"tcp", "udp"}, false),
Description: "Protocol for this rule. Could be either tcp or udp.",
},
// the rest are computed
"rule_id": {
Type: schema.TypeInt,
Computed: true,
Description: "Rule ID as assigned by the cloud platform.",
},
}
return rets
}

View File

@@ -44,7 +44,7 @@ func utilityAccountCheckPresence(d *schema.ResourceData, m interface{}) (string,
// get Account right away by its ID
log.Debugf("utilityAccountCheckPresence: locating Account by its ID %d", accId.(int))
urlValues.Add("accountId", fmt.Sprintf("%d", accId.(int)))
apiResp, err, _ := controller.decortAPICall("POST", AccountsGetAPI, urlValues)
apiResp, err := controller.decortAPICall("POST", AccountsGetAPI, urlValues)
if err != nil {
return "", err
}
@@ -57,7 +57,7 @@ func utilityAccountCheckPresence(d *schema.ResourceData, m interface{}) (string,
return "", fmt.Errorf("Cannot check account presence if name is empty and no account ID specified")
}
apiResp, err, _ := controller.decortAPICall("POST", AccountsListAPI, urlValues)
apiResp, err := controller.decortAPICall("POST", AccountsListAPI, urlValues)
if err != nil {
return "", err
}
@@ -131,7 +131,7 @@ func utilityGetAccountIdBySchema(d *schema.ResourceData, m interface{}) (int, er
controller := m.(*ControllerCfg)
urlValues := &url.Values{}
apiResp, err, _ := controller.decortAPICall("POST", AccountsListAPI, urlValues)
apiResp, err := controller.decortAPICall("POST", AccountsListAPI, urlValues)
if err != nil {
return 0, err
}

View File

@@ -62,7 +62,7 @@ func (ctrl *ControllerCfg) utilityComputeExtraDisksConfigure(d *schema.ResourceD
urlValues := &url.Values{}
urlValues.Add("computeId", d.Id())
urlValues.Add("diskId", fmt.Sprintf("%d", disk.(int)))
_, err, _ := ctrl.decortAPICall("POST", ComputeDiskAttachAPI, urlValues)
_, err := ctrl.decortAPICall("POST", ComputeDiskAttachAPI, urlValues)
if err != nil {
// failed to attach extra disk - partial resource update
apiErrCount++
@@ -85,7 +85,7 @@ func (ctrl *ControllerCfg) utilityComputeExtraDisksConfigure(d *schema.ResourceD
urlValues := &url.Values{}
urlValues.Add("computeId", d.Id())
urlValues.Add("diskId", fmt.Sprintf("%d", diskId.(int)))
_, err, _ := ctrl.decortAPICall("POST", ComputeDiskDetachAPI, urlValues)
_, 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)
@@ -100,7 +100,7 @@ func (ctrl *ControllerCfg) utilityComputeExtraDisksConfigure(d *schema.ResourceD
urlValues := &url.Values{}
urlValues.Add("computeId", d.Id())
urlValues.Add("diskId", fmt.Sprintf("%d", diskId.(int)))
_, err, _ := ctrl.decortAPICall("POST", ComputeDiskAttachAPI, urlValues)
_, 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)
@@ -145,7 +145,7 @@ func (ctrl *ControllerCfg) utilityComputeNetworksConfigure(d *schema.ResourceDat
if ipSet {
urlValues.Add("ipAddr", ipaddr.(string))
}
_, err, _ := ctrl.decortAPICall("POST", ComputeNetAttachAPI, urlValues)
_, err := ctrl.decortAPICall("POST", ComputeNetAttachAPI, urlValues)
if err != nil {
// failed to attach network - partial resource update
apiErrCount++
@@ -169,7 +169,7 @@ func (ctrl *ControllerCfg) utilityComputeNetworksConfigure(d *schema.ResourceDat
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)
_, 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",
@@ -190,7 +190,7 @@ func (ctrl *ControllerCfg) utilityComputeNetworksConfigure(d *schema.ResourceDat
if net_data["ip_address"].(string) != "" {
urlValues.Add("ipAddr", net_data["ip_address"].(string))
}
_, err, _ := ctrl.decortAPICall("POST", ComputeNetAttachAPI, urlValues)
_, 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",
@@ -244,7 +244,7 @@ func utilityComputeCheckPresence(d *schema.ResourceData, m interface{}) (string,
// 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)
computeFacts, err := controller.decortAPICall("POST", ComputeGetAPI, urlValues)
if err != nil {
return "", err
}
@@ -264,7 +264,7 @@ func utilityComputeCheckPresence(d *schema.ResourceData, m interface{}) (string,
}
urlValues.Add("rgId", fmt.Sprintf("%d", rgId))
apiResp, err, _ := controller.decortAPICall("POST", RgListComputesAPI, urlValues)
apiResp, err := controller.decortAPICall("POST", RgListComputesAPI, urlValues)
if err != nil {
return "", err
}
@@ -286,7 +286,7 @@ func utilityComputeCheckPresence(d *schema.ResourceData, m interface{}) (string,
// 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)
apiResp, err = controller.decortAPICall("POST", ComputeGetAPI, cgetValues)
if err != nil {
return "", err
}

View File

@@ -75,7 +75,7 @@ func utilityDiskCheckPresence(d *schema.ResourceData, m interface{}) (string, er
// 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)
diskFacts, err := controller.decortAPICall("POST", DisksGetAPI, urlValues)
if err != nil {
return "", err
}
@@ -98,7 +98,7 @@ func utilityDiskCheckPresence(d *schema.ResourceData, m interface{}) (string, er
}
urlValues.Add("accountId", fmt.Sprintf("%d", validatedAccountId))
diskFacts, err, _ := controller.decortAPICall("POST", DisksListAPI, urlValues)
diskFacts, err := controller.decortAPICall("POST", DisksListAPI, urlValues)
if err != nil {
return "", err
}

54
decort/utility_k8s.go Normal file
View File

@@ -0,0 +1,54 @@
/*
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"
"net/url"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)
func utilityK8sCheckPresence(d *schema.ResourceData, m interface{}) (*K8sRecord, error) {
controller := m.(*ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("k8sId", d.Id())
resp, err := controller.decortAPICall("POST", K8sGetAPI, urlValues)
if err != nil {
return nil, err
}
if resp == "" {
return nil, nil
}
var k8s K8sRecord
if err := json.Unmarshal([]byte(resp), &k8s); err != nil {
return nil, err
}
return &k8s, nil
}

66
decort/utility_k8s_wg.go Normal file
View File

@@ -0,0 +1,66 @@
/*
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"
"net/url"
"strconv"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)
func utilityK8sWgCheckPresence(d *schema.ResourceData, m interface{}) (*K8sNodeRecord, error) {
controller := m.(*ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("k8sId", strconv.Itoa(d.Get("k8s_id").(int)))
resp, err := controller.decortAPICall("POST", K8sGetAPI, urlValues)
if err != nil {
return nil, err
}
if resp == "" {
return nil, nil
}
var k8s K8sRecord
if err := json.Unmarshal([]byte(resp), &k8s); err != nil {
return nil, err
}
id, err := strconv.Atoi(d.Id())
if err != nil {
return nil, err
}
for _, wg := range k8s.Groups.Workers {
if wg.ID == id {
return &wg, nil
}
}
return nil, nil
}

View File

@@ -41,7 +41,7 @@ func (controller *ControllerCfg) utilityLocationGetDefaultGridID() (int, error)
urlValues := &url.Values{}
log.Debug("utilityLocationGetDefaultGridID: retrieving locations list")
apiResp, err, _ := controller.decortAPICall("POST", LocationsListAPI, urlValues)
apiResp, err := controller.decortAPICall("POST", LocationsListAPI, urlValues)
if err != nil {
return 0, err
}

View File

@@ -1,6 +1,6 @@
/*
Copyright (c) 2020-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
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.
@@ -26,183 +26,43 @@ package decort
import (
"encoding/json"
"fmt"
"net/url"
"strconv"
"strings"
log "github.com/sirupsen/logrus"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)
func utilityPfwCheckPresence(d *schema.ResourceData, m interface{}) (string, error) {
//
// This function does not modify its ResourceData argument, so it is safe to use it as core
// method for the Terraform resource Exists method.
//
// The string returned by this method mimics response of an imaginary API that will
// report PFW rules (if any) as following:
// {
// "header": {
// "computeId": <int>,
// "vinsId": <int>,
// },
// "rules": [
// {
// "id": <int>,
// "localPort": <int>,
// "protocol": <int>,
// "publicPortStart": <int>,
// "publicPortEnd": <int>,
// "vmId": <int>,
// },
// {
// ...
// },
// ],
// }
// This response unmarshalls into ComputePfwListResp structure.
// NOTE: If there are no rules for this compute, an empty string is returned along with err=nil
//
func utilityPfwCheckPresence(d *schema.ResourceData, m interface{}) (*PfwRecord, error) {
controller := m.(*ControllerCfg)
urlValues := &url.Values{}
var compId, vinsId int
// PFW resource ID is a combination of compute_id and vins_id separated by ":"
// See a note in "flattenPfw" method explaining the rationale behind this approach.
if d.Id() != "" {
log.Debugf("utilityPfwCheckPresence: setting context from PFW ID %s", d.Id())
idParts := strings.SplitN(d.Id(), ":", 2)
compId, _ = strconv.Atoi(idParts[0])
vinsId, _ = strconv.Atoi(idParts[1])
log.Debugf("utilityPfwCheckPresence: extracted Compute ID %d, ViNS %d", compId, vinsId)
if compId <= 0 || vinsId <= 0 {
return "", fmt.Errorf("Ivalid context from d.Id %s", d.Id())
}
} else {
scId, cSet := d.GetOk("compute_id")
svId, vSet := d.GetOk("vins_id")
if cSet || vSet {
log.Debugf("utilityPfwCheckPresence: setting Compute ID from schema")
compId = scId.(int)
vinsId = svId.(int)
log.Debugf("utilityPfwCheckPresence: extracted Compute ID %d, ViNS %d", compId, vinsId)
} else {
return "", fmt.Errorf("Cannot get context to check PFW rules neither from PFW ID nor from schema")
}
}
log.Debugf("utilityPfwCheckPresence: preparing to get PFW rules for Compute ID %d on ViNS ID %d", compId, vinsId)
urlValues.Add("computeId", fmt.Sprintf("%d", compId))
apiResp, err, respCode := controller.decortAPICall("POST", ComputePfwListAPI, urlValues)
if respCode == 500 {
// this is workaround for API 3.7.0 "feature" - will be removed in one of the future versions
log.Errorf("utilityPfwCheckPresence: Compute ID %d has no PFW and no connection to PFW-ready ViNS", compId)
return "", nil
}
urlValues.Add("computeId", strconv.Itoa(d.Get("compute_id").(int)))
resp, err := controller.decortAPICall("POST", ComputePfwListAPI, urlValues)
if err != nil {
return "", err
return nil, err
}
pfwListResp := ComputePfwListResp{}
// Note the specifics of compute/pfwList response in API 3.7.x (this may be changed in the future):
// 1) if there are no PFW rules and compute is not connected to any PFW-able ViNS
// the response will be empty string (or HTTP error code 500)
// 2) if there are no PFW rules but compute is connected to a PFW-able ViNS
// the response will contain a list with a single element - prefix (see PfwPrefixRecord)
// 3) if there are port forwarding rules, the response will contain a list which starts
// with prefix (see PfwPrefixRecord) and then followed by one or more rule records
// (see PfwRuleRecord)
//
// EXTRA NOTE: in API 3.7.0 and the likes pfwList returns HTTP response code 500 for a compute
// that is not connected to any PFW-able ViNS - need to implement temporary workaround
if apiResp == "" {
// No port forward rules defined for this compute
return "", nil
if resp == "" {
return nil, nil
}
log.Debugf("utilityPfwCheckPresence: ready to split API response string %s", apiResp)
twoParts := strings.SplitN(apiResp, "},", 2)
if len(twoParts) < 1 || len(twoParts) > 2 {
// Case: invalid format of API response
log.Errorf("utilityPfwCheckPresence: non-empty pfwList response for compute ID %d failed to split properly", compId)
return "", fmt.Errorf("Non-empty pfwList response failed to split properly")
}
if len(twoParts) == 1 {
// Case: compute is connected to a PWF-ready ViNS but has no PFW rules defined
log.Debugf("utilityPfwCheckPresence: compute ID %d is connected to PFW-ready ViNS but has no PFW rules", compId)
return "", nil
}
// Case: compute is connected to a PFW ready ViNS and has some PFW rule
prefixResp := strings.TrimSuffix(strings.TrimPrefix(twoParts[0], "["), ",") + "}"
log.Debugf("utilityPfwCheckPresence: ready to unmarshal prefix part %s", prefixResp)
err = json.Unmarshal([]byte(prefixResp), &pfwListResp.Header)
idS := strings.Split(d.Id(), "-")[1]
id, err := strconv.Atoi(idS)
if err != nil {
log.Errorf("utilityPfwCheckPresence: failed to unmarshal prefix part of API response: %s", err)
return "", err
return nil, err
}
rulesResp := "[" + twoParts[1]
log.Debugf("utilityPfwCheckPresence: ready to unmarshal rules part %s", rulesResp)
err = json.Unmarshal([]byte(rulesResp), &pfwListResp.Rules)
if err != nil {
log.Errorf("utilityPfwCheckPresence: failed to unmarshal rules part of API response: %s", err)
return "", err
var pfws []PfwRecord
if err := json.Unmarshal([]byte(resp), &pfws); err != nil {
return nil, err
}
log.Debugf("utilityPfwCheckPresence: successfully read %d port forward rules for Compute ID %d",
len(pfwListResp.Rules), compId)
if len(pfwListResp.Rules) == 0 {
// this compute technically can have rules, but no rules are currently defined
return "", nil
for _, pfw := range pfws {
if pfw.ID == id {
return &pfw, nil
}
}
// Now we can double check that the PFWs we've got do belong to the compute & ViNS specified in the
// PFW definition. Do so by reading compute details and comparing NatableVinsID value with the
// specified ViNS ID
//
// We may reuse urlValues here, as it already contains computeId field (see initialization above)
apiResp, err, _ = controller.decortAPICall("POST", ComputeGetAPI, urlValues)
if err != nil || apiResp == "" {
log.Errorf("utilityPfwCheckPresence: failed to get Compute ID %d details", compId)
return "", err
}
compFacts := ComputeGetResp{}
err = json.Unmarshal([]byte(rulesResp), &apiResp)
if err != nil {
log.Errorf("utilityPfwCheckPresence: failed to unmarshal compute details for ID %d: %s", compId, err)
return "", err
}
if compFacts.NatableVinsID <= 0 {
log.Errorf("utilityPfwCheckPresence: compute ID %d is not connected to a NAT-able ViNS", compId)
return "", fmt.Errorf("Compute ID %d is not connected to a NAT-able ViNS", compId)
}
if compFacts.NatableVinsID != vinsId {
log.Errorf("utilityPfwCheckPresence: ViNS ID mismatch for PFW rules on compute ID %d: actual %d, required %d",
compId, compFacts.NatableVinsID, vinsId)
return "", fmt.Errorf("ViNS ID mismatch for PFW rules on compute ID %d: actual %d, required %d",
compId, compFacts.NatableVinsID, vinsId)
}
// reconstruct API response string to return
pfwListResp.Header.ComputeID = compId
pfwListResp.Header.VinsID = compFacts.NatableVinsID
reencodedItem, err := json.Marshal(pfwListResp)
if err != nil {
return "", err
}
return string(reencodedItem[:]), nil
return nil, nil
}

View File

@@ -39,7 +39,7 @@ import (
func (ctrl *ControllerCfg) utilityResgroupConfigGet(rgid int) (*ResgroupGetResp, error) {
urlValues := &url.Values{}
urlValues.Add("rgId", fmt.Sprintf("%d", rgid))
rgFacts, err, _ := ctrl.decortAPICall("POST", ResgroupGetAPI, urlValues)
rgFacts, err := ctrl.decortAPICall("POST", ResgroupGetAPI, urlValues)
if err != nil {
return nil, err
}
@@ -109,7 +109,7 @@ func utilityResgroupCheckPresence(d *schema.ResourceData, m interface{}) (string
// go straight for the RG by its ID
log.Debugf("utilityResgroupCheckPresence: locating RG by its ID %d", theId)
urlValues.Add("rgId", fmt.Sprintf("%d", theId))
rgFacts, err, _ := controller.decortAPICall("POST", ResgroupGetAPI, urlValues)
rgFacts, err := controller.decortAPICall("POST", ResgroupGetAPI, urlValues)
if err != nil {
return "", err
}
@@ -130,7 +130,7 @@ func utilityResgroupCheckPresence(d *schema.ResourceData, m interface{}) (string
}
urlValues.Add("includedeleted", "false")
apiResp, err, _ := controller.decortAPICall("POST", ResgroupListAPI, urlValues)
apiResp, err := controller.decortAPICall("POST", ResgroupListAPI, urlValues)
if err != nil {
return "", err
}
@@ -154,7 +154,7 @@ func utilityResgroupCheckPresence(d *schema.ResourceData, m interface{}) (string
// Namely, we need resource quota settings
reqValues := &url.Values{}
reqValues.Add("rgId", fmt.Sprintf("%d", item.ID))
apiResp, err, _ := controller.decortAPICall("POST", ResgroupGetAPI, reqValues)
apiResp, err := controller.decortAPICall("POST", ResgroupGetAPI, reqValues)
if err != nil {
return "", err
}

View File

@@ -38,7 +38,7 @@ import (
func (ctrl *ControllerCfg) utilityVinsConfigGet(vinsid int) (*VinsRecord, error) {
urlValues := &url.Values{}
urlValues.Add("vinsId", fmt.Sprintf("%d", vinsid))
vinsFacts, err, _ := ctrl.decortAPICall("POST", VinsGetAPI, urlValues)
vinsFacts, err := ctrl.decortAPICall("POST", VinsGetAPI, urlValues)
if err != nil {
return nil, err
}
@@ -94,7 +94,7 @@ func utilityVinsCheckPresence(d *schema.ResourceData, m interface{}) (string, er
// ViNS ID is specified, try to get compute instance straight by this ID
log.Debugf("utilityVinsCheckPresence: locating ViNS by its ID %d", theId)
urlValues.Add("vinsId", fmt.Sprintf("%d", theId))
vinsFacts, err, _ := controller.decortAPICall("POST", VinsGetAPI, urlValues)
vinsFacts, err := controller.decortAPICall("POST", VinsGetAPI, urlValues)
if err != nil {
return "", err
}
@@ -125,7 +125,7 @@ func utilityVinsCheckPresence(d *schema.ResourceData, m interface{}) (string, er
urlValues.Add("accountId", fmt.Sprintf("%d", accountId.(int)))
}
apiResp, err, _ := controller.decortAPICall("POST", VinsSearchAPI, urlValues)
apiResp, err := controller.decortAPICall("POST", VinsSearchAPI, urlValues)
if err != nil {
return "", err
}
@@ -154,7 +154,7 @@ func utilityVinsCheckPresence(d *schema.ResourceData, m interface{}) (string, er
// manage ViNS, so we have to get detailed info by calling API vins/get
rqValues := &url.Values{}
rqValues.Add("vinsId", fmt.Sprintf("%d",item.ID))
vinsGetResp, err, _ := controller.decortAPICall("POST", VinsGetAPI, rqValues)
vinsGetResp, err := controller.decortAPICall("POST", VinsGetAPI, rqValues)
if err != nil {
return "", err
}

View File

@@ -0,0 +1,37 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_account Data Source - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_account (Data Source)
<!-- schema generated by tfplugindocs -->
## Schema
### Optional
- **account_id** (Number) Unique ID of the account. If account ID is specified, then account name is ignored.
- **id** (String) The ID of this resource.
- **name** (String) Name of the account. Names are case sensitive and unique.
- **timeouts** (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- **status** (String) Current status of the account.
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Optional:
- **default** (String)
- **read** (String)

45
docs/data-sources/disk.md Normal file
View File

@@ -0,0 +1,45 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_disk Data Source - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_disk (Data Source)
<!-- schema generated by tfplugindocs -->
## Schema
### Optional
- **account_id** (Number) ID of the account this disk belongs to. If disk ID is specified, then account ID is ignored.
- **disk_id** (Number) ID of the disk to get. If disk ID is specified, then disk name and account ID are ignored.
- **id** (String) The ID of this resource.
- **name** (String) Name of this disk. NOTE: disk names are NOT unique within an account. If disk ID is specified, disk name is ignored.
- **timeouts** (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- **account_name** (String) Name of the account this disk belongs to. If account ID is specified, account name is ignored.
- **description** (String) User-defined text description of this disk.
- **image_id** (Number) ID of the image, which this disk was cloned from (valid for disk clones only).
- **pool** (String) Pool where this disk is located.
- **sep_id** (Number) Storage end-point provider serving this disk.
- **sep_type** (String) Type of the storage end-point provider serving this disk.
- **size** (Number) Size of the disk in GB.
- **type** (String) Type of this disk. E.g. D for data disks, B for boot.
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Optional:
- **default** (String)
- **read** (String)

View File

@@ -0,0 +1,44 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_image Data Source - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_image (Data Source)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- **name** (String) Name of the image to locate. This parameter is case sensitive.
### Optional
- **account_id** (Number) Optional ID of the account to limit image search to.
- **id** (String) The ID of this resource.
- **timeouts** (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- **arch** (String) Binary architecture of this image.
- **pool** (String) Pool where this image is located.
- **sep_id** (Number) Storage end-point provider serving this image.
- **size** (Number) Size of the image in GB.
- **status** (String) Current model status of this image.
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Optional:
- **default** (String)
- **read** (String)

View File

@@ -0,0 +1,81 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_kvmvm Data Source - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_kvmvm (Data Source)
<!-- schema generated by tfplugindocs -->
## Schema
### Optional
- **compute_id** (Number) ID of the compute instance. If ID is specified, name and resource group ID are ignored.
- **id** (String) The ID of this resource.
- **name** (String) Name of this compute instance. NOTE: this parameter is case sensitive.
- **network** (Block Set, Max: 8) Network connection(s) for this compute. (see [below for nested schema](#nestedblock--network))
- **rg_id** (Number) ID of the resource group where this compute instance is located.
- **started** (Boolean) Is compute started.
- **timeouts** (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- **account_id** (Number) ID of the account this compute instance belongs to.
- **account_name** (String) Name of the account this compute instance belongs to.
- **boot_disk_id** (Number) This compute instance boot disk ID.
- **boot_disk_size** (Number) This compute instance boot disk size in GB.
- **cloud_init** (String) Placeholder for cloud_init parameters.
- **cpu** (Number) Number of CPUs allocated for this compute instance.
- **description** (String) User-defined text description of this compute instance.
- **driver** (String) Hardware architecture of this compute instance.
- **extra_disks** (Set of Number) IDs of the extra disk(s) attached to this compute.
- **image_id** (Number) ID of the OS image this compute instance is based on.
- **image_name** (String) Name of the OS image this compute instance is based on.
- **os_users** (List of Object) Guest OS users provisioned on this compute instance. (see [below for nested schema](#nestedatt--os_users))
- **ram** (Number) Amount of RAM in MB allocated for this compute instance.
- **rg_name** (String) Name of the resource group where this compute instance is located.
<a id="nestedblock--network"></a>
### Nested Schema for `network`
Required:
- **net_id** (Number) ID of the network for this connection.
- **net_type** (String) Type of the network for this connection, either EXTNET or VINS.
Optional:
- **ip_address** (String) Optional IP address to assign to this connection. This IP should belong to the selected network and free for use.
Read-Only:
- **mac** (String) MAC address associated with this connection. MAC address is assigned automatically.
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Optional:
- **default** (String)
- **read** (String)
<a id="nestedatt--os_users"></a>
### Nested Schema for `os_users`
Read-Only:
- **guid** (String)
- **login** (String)
- **password** (String)
- **public_key** (String)

View File

@@ -0,0 +1,58 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_resgroup Data Source - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_resgroup (Data Source)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- **account_id** (Number) Unique ID of the account, which this resource group belongs to.
### Optional
- **id** (String) The ID of this resource.
- **name** (String) Name of the resource group. Names are case sensitive and unique within the context of an account.
- **rg_id** (Number) Unique ID of the resource group. If this ID is specified, then resource group name is ignored.
- **timeouts** (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- **account_name** (String) Name of the account, which this resource group belongs to.
- **def_net_id** (Number) ID of the default network for this resource group (if any).
- **def_net_type** (String) Type of the default network for this resource group.
- **description** (String) User-defined text description of this resource group.
- **quota** (List of Object) Quota settings for this resource group. (see [below for nested schema](#nestedatt--quota))
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Optional:
- **default** (String)
- **read** (String)
<a id="nestedatt--quota"></a>
### Nested Schema for `quota`
Read-Only:
- **cpu** (Number)
- **disk** (Number)
- **ext_ips** (Number)
- **ext_traffic** (Number)
- **gpu_units** (Number)
- **ram** (Number)

45
docs/data-sources/vins.md Normal file
View File

@@ -0,0 +1,45 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_vins Data Source - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_vins (Data Source)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- **name** (String) Name of the ViNS. Names are case sensitive and unique within the context of an account or resource group.
### Optional
- **account_id** (Number) Unique ID of the account, which this ViNS belongs to.
- **id** (String) The ID of this resource.
- **rg_id** (Number) Unique ID of the resource group, where this ViNS is belongs to (for ViNS created at resource group level, 0 otherwise).
- **timeouts** (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- **account_name** (String) Name of the account, which this ViNS belongs to.
- **description** (String) User-defined text description of this ViNS.
- **ext_ip_addr** (String) IP address of the external connection (valid for ViNS connected to external network, empty string otherwise).
- **ext_net_id** (Number) ID of the external network this ViNS is connected to (-1 means no external connection).
- **ipcidr** (String) Network address used by this ViNS.
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Optional:
- **default** (String)
- **read** (String)

31
docs/index.md Normal file
View File

@@ -0,0 +1,31 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort Provider"
subcategory: ""
description: |-
---
# decort Provider
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- **authenticator** (String) Authentication mode to use when connecting to DECORT cloud API. Should be one of 'oauth2', 'legacy' or 'jwt'.
- **controller_url** (String) URL of DECORT Cloud controller to use. API calls will be directed to this URL.
### Optional
- **allow_unverified_ssl** (Boolean) If true, DECORT API will not verify SSL certificates. Use this with caution and in trusted environments only!
- **app_id** (String) Application ID to access DECORT cloud API in 'oauth2' authentication mode.
- **app_secret** (String) Application secret to access DECORT cloud API in 'oauth2' authentication mode.
- **jwt** (String) JWT to access DECORT cloud API in 'jwt' authentication mode.
- **oauth2_url** (String) OAuth2 application URL in 'oauth2' authentication mode.
- **password** (String) User password for DECORT cloud API operations in 'legacy' authentication mode.
- **user** (String) User name for DECORT cloud API operations in 'legacy' authentication mode.

51
docs/resources/disk.md Normal file
View File

@@ -0,0 +1,51 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_disk Resource - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_disk (Resource)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- **pool** (String) Pool where this disk is located. Cannot be changed for existing disk.
- **sep_id** (Number) Storage end-point provider serving this disk. Cannot be changed for existing disk.
- **size** (Number) Size of the disk in GB. Note, that existing disks can only be grown in size.
### Optional
- **account_id** (Number) ID of the account this disk belongs to.
- **description** (String) Optional user-defined text description of this disk.
- **disk_id** (Number) ID of the disk to get. If disk ID is specified, then disk name and account ID are ignored.
- **id** (String) The ID of this resource.
- **name** (String) Name of this disk. NOTE: disk names are NOT unique within an account. If disk ID is specified, disk name is ignored.
- **timeouts** (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- **account_name** (String) Name of the account this disk belongs to.
- **image_id** (Number) ID of the image, which this disk was cloned from (if ever cloned).
- **sep_type** (String) Type of the storage end-point provider serving this disk.
- **type** (String) Type of this disk.
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Optional:
- **create** (String)
- **default** (String)
- **delete** (String)
- **read** (String)
- **update** (String)

55
docs/resources/k8s.md Normal file
View File

@@ -0,0 +1,55 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_k8s Resource - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_k8s (Resource)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- **k8sci_id** (Number) ID of the k8s catalog item to base this instance on.
- **name** (String) Name of the cluster.
- **rg_id** (Number) Resource group ID that this instance belongs to.
### Optional
- **id** (String) The ID of this resource.
- **masters** (Block List, Max: 1) Master node(s) configuration. (see [below for nested schema](#nestedblock--masters))
- **workers** (Block List, Max: 1) Worker node(s) configuration. (see [below for nested schema](#nestedblock--workers))
### Read-Only
- **default_wg_id** (Number) ID of default workers group for this instace.
<a id="nestedblock--masters"></a>
### Nested Schema for `masters`
Required:
- **cpu** (Number) Node CPU count.
- **disk** (Number) Node boot disk size in GB.
- **num** (Number) Number of nodes to create.
- **ram** (Number) Node RAM in MB.
<a id="nestedblock--workers"></a>
### Nested Schema for `workers`
Required:
- **cpu** (Number) Node CPU count.
- **disk** (Number) Node boot disk size in GB.
- **num** (Number) Number of nodes to create.
- **ram** (Number) Node RAM in MB.

30
docs/resources/k8s_wg.md Normal file
View File

@@ -0,0 +1,30 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_k8s_wg Resource - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_k8s_wg (Resource)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- **k8s_id** (Number) ID of k8s instance.
### Optional
- **cpu** (Number) Worker node CPU count.
- **disk** (Number) Worker node boot disk size. If unspecified or 0, size is defined by OS image size.
- **id** (String) The ID of this resource.
- **num** (Number) Number of worker nodes to create.
- **ram** (Number) Worker node RAM in MB.

85
docs/resources/kvmvm.md Normal file
View File

@@ -0,0 +1,85 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_kvmvm Resource - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_kvmvm (Resource)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- **boot_disk_size** (Number) This compute instance boot disk size in GB. Make sure it is large enough to accomodate selected OS image.
- **cpu** (Number) Number of CPUs to allocate to this compute instance.
- **driver** (String) Hardware architecture of this compute instance.
- **image_id** (Number) ID of the OS image to base this compute instance on.
- **name** (String) Name of this compute. Compute names are case sensitive and must be unique in the resource group.
- **ram** (Number) Amount of RAM in MB to allocate to this compute instance.
- **rg_id** (Number) ID of the resource group where this compute should be deployed.
### Optional
- **cloud_init** (String) Optional cloud_init parameters. Applied when creating new compute instance only, ignored in all other cases.
- **description** (String) Optional text description of this compute instance.
- **extra_disks** (Set of Number) Optional list of IDs of extra disks to attach to this compute. You may specify several extra disks.
- **id** (String) The ID of this resource.
- **network** (Block Set, Max: 8) Optional network connection(s) for this compute. You may specify several network blocks, one for each connection. (see [below for nested schema](#nestedblock--network))
- **started** (Boolean) Is compute started.
- **timeouts** (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- **account_id** (Number) ID of the account this compute instance belongs to.
- **account_name** (String) Name of the account this compute instance belongs to.
- **boot_disk_id** (Number) This compute instance boot disk ID.
- **os_users** (List of Object) Guest OS users provisioned on this compute instance. (see [below for nested schema](#nestedatt--os_users))
- **rg_name** (String) Name of the resource group where this compute instance is located.
<a id="nestedblock--network"></a>
### Nested Schema for `network`
Required:
- **net_id** (Number) ID of the network for this connection.
- **net_type** (String) Type of the network for this connection, either EXTNET or VINS.
Optional:
- **ip_address** (String) Optional IP address to assign to this connection. This IP should belong to the selected network and free for use.
Read-Only:
- **mac** (String) MAC address associated with this connection. MAC address is assigned automatically.
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Optional:
- **create** (String)
- **default** (String)
- **delete** (String)
- **read** (String)
- **update** (String)
<a id="nestedatt--os_users"></a>
### Nested Schema for `os_users`
Read-Only:
- **guid** (String)
- **login** (String)
- **password** (String)
- **public_key** (String)

46
docs/resources/pfw.md Normal file
View File

@@ -0,0 +1,46 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_pfw Resource - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_pfw (Resource)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- **compute_id** (Number) ID of compute instance.
- **local_base_port** (Number) Internal base port number.
- **proto** (String) Network protocol, either 'tcp' or 'udp'.
- **public_port_start** (Number) External start port number for the rule.
### Optional
- **id** (String) The ID of this resource.
- **public_port_end** (Number) End port number (inclusive) for the ranged rule.
- **timeouts** (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- **local_ip** (String) IP address of compute instance.
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Optional:
- **create** (String)
- **default** (String)
- **delete** (String)
- **read** (String)
- **update** (String)

View File

@@ -0,0 +1,63 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_resgroup Resource - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_resgroup (Resource)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- **account_id** (Number) Unique ID of the account, which this resource group belongs to.
- **name** (String) Name of this resource group. Names are case sensitive and unique within the context of a account.
### Optional
- **def_net_type** (String) Type of the network, which this resource group will use as default for its computes - PRIVATE or PUBLIC or NONE.
- **description** (String) User-defined text description of this resource group.
- **ext_ip** (String) IP address on the external netowrk to request when def_net_type=PRIVATE and ext_net_id is not 0
- **ext_net_id** (Number) 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
- **id** (String) The ID of this resource.
- **ipcidr** (String) Address of the netowrk inside the private network segment (aka ViNS) if def_net_type=PRIVATE
- **quota** (Block List, Max: 1) Quota settings for this resource group. (see [below for nested schema](#nestedblock--quota))
- **timeouts** (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- **account_name** (String) Name of the account, which this resource group belongs to.
- **def_net_id** (Number) ID of the default network for this resource group (if any).
<a id="nestedblock--quota"></a>
### Nested Schema for `quota`
Optional:
- **cpu** (Number) Limit on the total number of CPUs in this resource group.
- **disk** (Number) Limit on the total volume of storage resources in this resource group, specified in GB.
- **ext_ips** (Number) Limit on the total number of external IP addresses this resource group can use.
- **ext_traffic** (Number) Limit on the total ingress network traffic for this resource group, specified in GB.
- **gpu_units** (Number) Limit on the total number of virtual GPUs this resource group can use.
- **ram** (Number) Limit on the total amount of RAM in this resource group, specified in MB.
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Optional:
- **create** (String)
- **default** (String)
- **delete** (String)
- **read** (String)
- **update** (String)

48
docs/resources/vins.md Normal file
View File

@@ -0,0 +1,48 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "decort_vins Resource - terraform-provider-decort"
subcategory: ""
description: |-
---
# decort_vins (Resource)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- **account_id** (Number) ID of the account, which this ViNS belongs to. For ViNS created at account level, resource group ID is 0.
- **ext_net_id** (Number) ID of the external network this ViNS is connected to. Pass 0 if no external connection required.
- **name** (String) Name of the ViNS. Names are case sensitive and unique within the context of an account or resource group.
### Optional
- **description** (String) Optional user-defined text description of this ViNS.
- **id** (String) The ID of this resource.
- **ipcidr** (String) Network address to use by this ViNS. This parameter is only valid when creating new ViNS.
- **rg_id** (Number) ID of the resource group, where this ViNS belongs to. Non-zero for ViNS created at resource group level, 0 otherwise.
- **timeouts** (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
### Read-Only
- **account_name** (String) Name of the account, which this ViNS belongs to.
- **ext_ip_addr** (String) IP address of the external connection (valid for ViNS connected to external network, ignored otherwise).
<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`
Optional:
- **create** (String)
- **default** (String)
- **delete** (String)
- **read** (String)
- **update** (String)

2
go.mod
View File

@@ -4,6 +4,8 @@ go 1.15
require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/google/uuid v1.1.2
github.com/hashicorp/terraform-plugin-docs v0.5.1
github.com/hashicorp/terraform-plugin-sdk v1.16.0
github.com/sirupsen/logrus v1.7.0
)

145
go.sum
View File

@@ -34,11 +34,26 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ=
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=
github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/andybalholm/crlf v0.0.0-20171020200849-670099aa064f/go.mod h1:k8feO4+kXDxro6ErPXBRTJ/ro2mf0SsFG8s7doP9kJE=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/apparentlymart/go-cidr v1.0.1 h1:NmIwLZ/KdsjIUlhf+/Np40atNXm/+lZ5txfTJ/SpF+U=
github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=
@@ -47,9 +62,12 @@ github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFU
github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0=
github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
github.com/aws/aws-sdk-go v1.25.3 h1:uM16hIw9BotjZKMZlX05SN2EFtaWfi/NonPKIARiBLQ=
@@ -71,6 +89,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -78,12 +97,22 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8=
github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM=
github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4=
github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -124,8 +153,9 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs=
@@ -138,20 +168,24 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=
github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY=
github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02 h1:l1KB3bHVdvegcIf5upQ5mjcHjs2qsWnKh4Yr9xgIuu8=
github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY=
github.com/hashicorp/go-getter v1.5.3 h1:NF5+zOlQegim+w/EUhSLh6QhXHmZMEeHLQzllkQ3ROU=
github.com/hashicorp/go-getter v1.5.3/go.mod h1:BrrV/1clo8cCYu6mxvboYg+KutTiFnXjMEgDD8+i7ZI=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
@@ -166,8 +200,9 @@ github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw=
github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f h1:UdxlrJz4JOnY8W+DbLISwf2B8WXEolNRA8BGCwI9jws=
@@ -180,7 +215,13 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/terraform-config-inspect v0.0.0-20191115094559-17f92b0546e8 h1:+RyjwU+Gnd/aTJBPZVDNm903eXVjjqhbaR4Ypx3xYyY=
github.com/hashicorp/terraform-config-inspect v0.0.0-20191115094559-17f92b0546e8/go.mod h1:p+ivJws3dpqbp1iP84+npOyAmTTOLMgCzrXd3GSdn/A=
github.com/hashicorp/terraform-exec v0.10.0/go.mod h1:tOT8j1J8rP05bZBGWXfMyU3HkLi1LWyqL3Bzsc3CJjo=
github.com/hashicorp/terraform-exec v0.15.0 h1:cqjh4d8HYNQrDoEmlSGelHmg2DYDh5yayckvJ5bV18E=
github.com/hashicorp/terraform-exec v0.15.0/go.mod h1:H4IG8ZxanU+NW0ZpDRNsvh9f0ul7C0nHP+rUR/CHs7I=
github.com/hashicorp/terraform-json v0.5.0/go.mod h1:eAbqb4w0pSlRmdvl8fOyHAi/+8jnkVYN28gJkSJrLhU=
github.com/hashicorp/terraform-json v0.13.0 h1:Li9L+lKD1FO5RVFRM1mMMIBDoUHslOniyEi5CM+FWGY=
github.com/hashicorp/terraform-json v0.13.0/go.mod h1:y5OdLBCT+rxbwnpxZs9kGL7R9ExU76+cpdY8zHwoazk=
github.com/hashicorp/terraform-plugin-docs v0.5.1 h1:WwrUcamix9x0TqfTw/WGHMRqoTe1QPZKaeWJPuFb4lQ=
github.com/hashicorp/terraform-plugin-docs v0.5.1/go.mod h1:SQwEgy0/B0UPQ07rNEG1Wpt6E3jvRcCwkVHPNybGgc0=
github.com/hashicorp/terraform-plugin-sdk v1.16.0 h1:NrkXMRjHErUPPTHQkZ6JIn6bByiJzGnlJzH1rVdNEuE=
github.com/hashicorp/terraform-plugin-sdk v1.16.0/go.mod h1:5sVxrwW6/xzFhZyql+Q9zXCUEJaGWcBIxBbZFLpVXOI=
github.com/hashicorp/terraform-plugin-test/v2 v2.1.2/go.mod h1:jerO5mrd+jVNALy8aiq+VZOg/CR8T2T1QR3jd6JKGOI=
@@ -189,10 +230,17 @@ github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596/go.mod
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@@ -202,10 +250,16 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck=
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ=
github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -213,19 +267,25 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mitchellh/cli v1.1.1 h1:J64v/xD7Clql+JVKSvkYojLOXu1ibnY9ZjGLwSt/89w=
github.com/mitchellh/cli v1.1.1/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/cli v1.1.2 h1:PvH+lL2B7IQ101xQL63Of8yFS2y+aDlsFcsqNc+u/Kw=
github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -239,14 +299,16 @@ github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUb
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE=
github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
@@ -254,9 +316,14 @@ github.com/posener/complete v1.2.1 h1:LrvDIY//XNo65Lq84G/akBuMGlawHvGBABv8f/ZN6D
github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
@@ -264,25 +331,38 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/ulikunitz/xz v0.5.7 h1:YvTNdFzX6+W5m9msiYg/zpkSURPPtOlzbqYjrFn7Yt4=
github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack v4.0.1+incompatible h1:RMF1enSPeKTlXrXdOcqjFUElywVZjjC6pqse21bKbEU=
github.com/vmihailenco/msgpack v4.0.1+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U=
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY=
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zclconf/go-cty v1.0.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.2.1 h1:vGMsygfmeCl4Xb6OA5U5XVAaQZ69FvoG7X2jUtQujb8=
github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.9.1/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0=
github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
github.com/zclconf/go-cty-yaml v1.0.1 h1:up11wlgAaDvlAGENcFDnZgkn0qUJurso7k6EpURKNF8=
github.com/zclconf/go-cty-yaml v1.0.1/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@@ -298,8 +378,11 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -359,8 +442,10 @@ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210326060303-6b1517762897 h1:KrsHThm5nFk34YtATK1LsThyGhGbGe1olrte/HInHvs=
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -377,6 +462,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -388,6 +474,7 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -403,14 +490,23 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -536,14 +632,19 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -38,6 +38,8 @@ import (
"github.com/rudecs/terraform-provider-decort/decort"
)
//go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs
func main() {
log.SetLevel(log.DebugLevel)
log.Debug("Debug logging enabled")

View File

@@ -0,0 +1,6 @@
{
"version": 1,
"metadata": {
"protocol_versions": ["5.0"]
}
}

8
tools/tools.go Normal file
View File

@@ -0,0 +1,8 @@
// +build tools
package tools
import (
// document generation
_ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs"
)