Compare commits

..

3 Commits

Author SHA1 Message Date
Sergey Shubin svs1370
a5f6c60a71 Improve stability of PFW check presence method 2021-10-11 19:29:17 +03:00
Sergey Shubin svs1370
105273af48 Implement more robust create and delete methods for PFW 2021-10-08 12:17:53 +03:00
Sergey Shubin svs1370
e501417166 PFW data source and resource initial implementation 2021-10-07 23:12:10 +03:00
37 changed files with 1076 additions and 1242 deletions

View File

@@ -1,56 +0,0 @@
# 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.25 is designed for DECORT API 3.7.x. For older API versions please use:
NOTE: provider rc-1.40 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

@@ -16,15 +16,16 @@ limitations under the License.
*/
/*
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
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.
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
*/
package decort
import (
"bytes"
"crypto/tls"
"fmt"
@@ -33,7 +34,6 @@ import (
"net/url"
"strconv"
"strings"
// "time"
log "github.com/sirupsen/logrus"
@@ -42,41 +42,42 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
// "github.com/hashicorp/terraform-plugin-sdk/terraform"
)
// enumerated constants that define authentication modes
// enumerated constants that define authentication modes
const (
MODE_UNDEF = iota // this is the invalid mode - it should never be seen
MODE_LEGACY = iota
MODE_OAUTH2 = iota
MODE_JWT = iota
MODE_UNDEF = iota // this is the invalid mode - it should never be seen
MODE_LEGACY = iota
MODE_OAUTH2 = iota
MODE_JWT = iota
)
type ControllerCfg struct {
controller_url string // always required
auth_mode_code int // always required
auth_mode_txt string // always required, it is a text representation of auth mode
legacy_user string // required for legacy mode
legacy_password string // required for legacy mode
legacy_sid string // obtained from DECORT controller on successful login in legacy mode
jwt string // obtained from Outh2 provider on successful login in oauth2 mode, required in jwt mode
app_id string // required for oauth2 mode
app_secret string // required for oauth2 mode
oauth2_url string // always required
decort_username string // assigned to either legacy_user (legacy mode) or Oauth2 user (oauth2 mode) upon successful verification
cc_client *http.Client // assigned when all initial checks successfully passed
controller_url string // always required
auth_mode_code int // always required
auth_mode_txt string // always required, it is a text representation of auth mode
legacy_user string // required for legacy mode
legacy_password string // required for legacy mode
legacy_sid string // obtained from DECORT controller on successful login in legacy mode
jwt string // obtained from Outh2 provider on successful login in oauth2 mode, required in jwt mode
app_id string // required for oauth2 mode
app_secret string // required for oauth2 mode
oauth2_url string // always required
decort_username string // assigned to either legacy_user (legacy mode) or Oauth2 user (oauth2 mode) upon successful verification
cc_client *http.Client // assigned when all initial checks successfully passed
}
func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) {
// This function first will check that all required provider parameters for the
// This function first will check that all required provider parameters for the
// selected authenticator mode are set correctly and initialize ControllerCfg structure
// based on the provided parameters.
//
// Next, it will check for validity of supplied credentials by initiating connection to the specified
// DECORT controller URL and, if succeeded, completes ControllerCfg structure with the rest of computed
// Next, it will check for validity of supplied credentials by initiating connection to the specified
// DECORT controller URL and, if succeeded, completes ControllerCfg structure with the rest of computed
// parameters (e.g. JWT, session ID and Oauth2 user name).
//
// The structure created by this function should be used with subsequent calls to decortAPICall() method,
// The structure created by this function should be used with subsequent calls to decortAPICall() method,
// which is a DECORT authentication mode aware wrapper around standard HTTP requests.
ret_config := &ControllerCfg{
@@ -89,7 +90,7 @@ func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) {
app_id: d.Get("app_id").(string),
app_secret: d.Get("app_secret").(string),
oauth2_url: d.Get("oauth2_url").(string),
decort_username: "",
decort_username: "",
}
var allow_unverified_ssl bool
@@ -131,15 +132,15 @@ func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) {
}
ret_config.auth_mode_code = MODE_LEGACY
default:
return nil, fmt.Errorf("Unknown authenticator mode %q provided.", ret_config.auth_mode_txt)
return nil, fmt.Errorf("Unknown authenticator mode %s 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,
Timeout: Timeout180s,
}
} else {
ret_config.cc_client = &http.Client{
@@ -149,7 +150,7 @@ func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) {
switch ret_config.auth_mode_code {
case MODE_LEGACY:
ok, err := ret_config.validateLegacyUser()
ok, err := ret_config.validateLegacyUser()
if !ok {
return nil, err
}
@@ -161,13 +162,13 @@ func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) {
return nil, err
}
case MODE_OAUTH2:
// on success getOAuth2JWT will set config.jwt to the obtained JWT, so there is no
// on success getOAuth2JWT will set config.jwt to the obtained JWT, so there is no
// need to set it once again here
_, err := ret_config.getOAuth2JWT()
if err != nil {
return nil, err
}
// we are not verifying the JWT when parsing because actual verification is done on the
// we are not verifying the JWT when parsing because actual verification is done on the
// OVC controller side. Here we do parsing solely to extract Oauth2 user name (claim "user")
// and JWT issuer name (claim "iss")
parser := jwt.Parser{}
@@ -180,7 +181,7 @@ func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) {
tbuf.WriteString(claims["username"].(string))
tbuf.WriteString("@")
tbuf.WriteString(claims["iss"].(string))
ret_config.decort_username = tbuf.String()
ret_config.decort_username = tbuf.String()
} else {
return nil, fmt.Errorf("Failed to extract user and iss fields from JWT token in oauth2 mode.")
}
@@ -194,7 +195,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
}
@@ -204,7 +205,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 %q.", config.auth_mode_txt)
return "", fmt.Errorf("getOAuth2JWT method called for incompatible authorization mode %s.", config.auth_mode_txt)
}
params := url.Values{}
@@ -215,14 +216,14 @@ 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
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Content-Length", strconv.Itoa(len(params_str)))
resp, err := config.cc_client.Do(req)
resp, err := config.cc_client.Do(req)
if err != nil {
return "", err
}
@@ -230,16 +231,16 @@ 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 %q for APP_ID %q, request Body %q",
resp.StatusCode, req.URL, config.app_id, params_str)
return "", fmt.Errorf("getOauth2JWT: unexpected status code %d when obtaining JWT from %s for APP_ID %s, request Body %s",
resp.StatusCode, req.URL, config.app_id, params_str)
}
defer resp.Body.Close()
responseData, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
if err != nil {
return "", err
}
// validation successful - store JWT in the corresponding field of the ControllerCfg structure
config.jwt = strings.TrimSpace(string(responseData))
@@ -248,10 +249,10 @@ func (config *ControllerCfg) getOAuth2JWT() (string, error) {
func (config *ControllerCfg) validateJWT(jwt string) (bool, error) {
/*
Validate JWT against DECORT controller. JWT can be supplied as argument to this method. If empty string supplied as
argument, JWT will be taken from config attribute.
DECORT controller URL will always be taken from the config attribute assigned at instantiation.
Validation is accomplished by attempting API call that lists accounts for the invoking user.
Validate JWT against DECORT controller. JWT can be supplied as argument to this method. If empty string supplied as
argument, JWT will be taken from config attribute.
DECORT controller URL will always be taken from the config attribute assigned at instantiation.
Validation is accomplished by attempting API call that lists accounts for the invoking user.
*/
if jwt == "" {
if config.jwt == "" {
@@ -264,7 +265,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
}
@@ -272,14 +273,14 @@ func (config *ControllerCfg) validateJWT(jwt string) (bool, error) {
req.Header.Set("Authorization", fmt.Sprintf("bearer %s", jwt))
// req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
// req.Header.Set("Content-Length", strconv.Itoa(0))
resp, err := config.cc_client.Do(req)
resp, err := config.cc_client.Do(req)
if err != nil {
return false, err
}
if resp.StatusCode != http.StatusOK {
return false, fmt.Errorf("validateJWT: unexpected status code %d when validating JWT against %q.",
resp.StatusCode, req.URL)
return false, fmt.Errorf("validateJWT: unexpected status code %d when validating JWT against %s.",
resp.StatusCode, req.URL)
}
defer resp.Body.Close()
@@ -288,16 +289,16 @@ func (config *ControllerCfg) validateJWT(jwt string) (bool, error) {
func (config *ControllerCfg) validateLegacyUser() (bool, error) {
/*
Validate legacy user by obtaining a session key, which will be used for authenticating subsequent API calls
to DECORT controller.
If successful, the session key is stored in config.legacy_sid and true is returned. If unsuccessful for any
reason, the method will return false and error.
Validate legacy user by obtaining a session key, which will be used for authenticating subsequent API calls
to DECORT controller.
If successful, the session key is stored in config.legacy_sid and true is returned. If unsuccessful for any
reason, the method will return false and error.
*/
if config.auth_mode_code == MODE_UNDEF {
return false, fmt.Errorf("validateLegacyUser method called for undefined authorization mode.")
}
if config.auth_mode_code != MODE_LEGACY {
return false, fmt.Errorf("validateLegacyUser method called for incompatible authorization mode %q.", config.auth_mode_txt)
return false, fmt.Errorf("validateLegacyUser method called for incompatible authorization mode %s.", config.auth_mode_txt)
}
params := url.Values{}
@@ -305,7 +306,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
}
@@ -313,38 +314,40 @@ func (config *ControllerCfg) validateLegacyUser() (bool, error) {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Content-Length", strconv.Itoa(len(params_str)))
resp, err := config.cc_client.Do(req)
resp, err := config.cc_client.Do(req)
if err != nil {
return false, err
}
if resp.StatusCode != http.StatusOK {
return false, fmt.Errorf("validateLegacyUser: unexpected status code %d when validating legacy user %q against %q.",
resp.StatusCode, config.legacy_user, config.controller_url)
return false, fmt.Errorf("validateLegacyUser: unexpected status code %d when validating legacy user %s against %s.",
resp.StatusCode, config.legacy_user, config.controller_url)
}
defer resp.Body.Close()
responseData, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
if err != nil {
log.Fatal(err)
}
// validation successful - keep session ID for future use
config.legacy_sid = string(responseData)
return true, nil
}
func (config *ControllerCfg) decortAPICall(method string, api_name string, url_values *url.Values) (json_resp string, err error) {
// This is a convenience wrapper around standard HTTP request methods that is aware of the
func (config *ControllerCfg) decortAPICall(method string, api_name string, url_values *url.Values) (json_resp string, err error, hrc int) {
// 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.")
// 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
}
// Example: to create api_params, one would generally do the following:
//
//
// data := []byte(`{"machineId": "2638"}`)
// api_params := bytes.NewBuffer(data))
//
@@ -358,7 +361,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.")
return "", fmt.Errorf("decortAPICall method called for unknown authorization mode."), 0
}
if config.auth_mode_code == MODE_LEGACY {
@@ -366,41 +369,42 @@ 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
return "", err, 0
}
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))
}
}
resp, err := config.cc_client.Do(req)
if err != nil {
return "", err
return "", err, 0
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
body, err := ioutil.ReadAll(resp.Body)
if resp.StatusCode == http.StatusOK {
tmp_body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
log.Debugf("decortAPICall: %s %s\n %s", method, api_name, body)
return string(body), nil
return "", err, resp.StatusCode
}
json_resp := Jo2JSON(string(tmp_body))
log.Debugf("decortAPICall: %s %s\n %s", method, api_name, json_resp)
return json_resp, nil, resp.StatusCode
} else {
return "", fmt.Errorf("decortAPICall: unexpected status code %d when calling API %q with request Body %q",
resp.StatusCode, req.URL, params_str)
return "", fmt.Errorf("decortAPICall: unexpected status code %d when calling API %s with request Body %s",
resp.StatusCode, req.URL, params_str), resp.StatusCode
}
/*
if resp.StatusCode == StatusServiceUnavailable {
return nil, fmt.Errorf("decortAPICall method called for incompatible authorization mode %q.", config.auth_mode_txt)
}
if resp.StatusCode == StatusServiceUnavailable {
return nil, fmt.Errorf("decortAPICall method called for incompatible authorization mode %s.", config.auth_mode_txt), resp.StatusCode
}
*/
return "", err
return "", err, resp.StatusCode
}

View File

@@ -27,7 +27,6 @@ package decort
import (
"encoding/json"
"fmt"
// "net/url"
log "github.com/sirupsen/logrus"
@@ -37,20 +36,20 @@ import (
)
// Parse list of all disks from API compute/get into a list of "extra disks" attached to this compute
// Extra disks are all compute disks but a boot disk.
// Extra disks are all compute disks but a boot disk.
func parseComputeDisksToExtraDisks(disks []DiskRecord) []interface{} {
// this return value will be used to d.Set("extra_disks",) item of dataSourceCompute schema,
// this return value will be used to d.Set("extra_disks",) item of dataSourceCompute schema,
// which is a simple list of integer disk IDs excluding boot disk ID
length := len(disks)
log.Debugf("parseComputeDisksToExtraDisks: called for %d disks", length)
if length == 0 || (length == 1 && disks[0].Type == "B") {
if length == 0 || ( length == 1 && disks[0].Type == "B" ) {
// the disk list is empty (which is kind of strange - diskless compute?), or
// there is only one disk in the list and it is a boot disk;
// as we skip boot disks, the result will be of 0 length anyway
return make([]interface{}, 0)
}
result := make([]interface{}, length-1)
idx := 0
for _, value := range disks {
@@ -63,7 +62,7 @@ func parseComputeDisksToExtraDisks(disks []DiskRecord) []interface{} {
idx++
}
return result
return result
}
// NOTE: this is a legacy function, which is not used as of rc-1.10
@@ -71,18 +70,18 @@ func parseComputeDisksToExtraDisks(disks []DiskRecord) []interface{} {
func parseComputeDisks(disks []DiskRecord) []interface{} {
// Return value was designed to d.Set("disks",) item of dataSourceCompute schema
// However, this item was excluded from the schema as it is not directly
// managed through Terraform
// managed through Terraform
length := len(disks)
log.Debugf("parseComputeDisks: called for %d disks", length)
/*
if length == 1 && disks[0].Type == "B" {
// 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 lenght
length = 0
}
if length == 1 && disks[0].Type == "B" {
// 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 lenght
length = 0
}
*/
result := []interface{}{}
if length == 0 {
@@ -91,10 +90,10 @@ func parseComputeDisks(disks []DiskRecord) []interface{} {
for _, value := range disks {
/*
if value.Type == "B" {
// skip boot disk when parsing the list of disks
continue
}
if value.Type == "B" {
// skip boot disk when parsing the list of disks
continue
}
*/
elem := make(map[string]interface{})
// keys in this map should correspond to the Schema definition
@@ -113,11 +112,11 @@ func parseComputeDisks(disks []DiskRecord) []interface{} {
// elem["status"] = value.Status
// elem["tech_status"] = value.TechStatus
elem["compute_id"] = value.ComputeID
result = append(result, elem)
}
return result
return result
}
func parseBootDiskSize(disks []DiskRecord) int {
@@ -132,7 +131,7 @@ func parseBootDiskSize(disks []DiskRecord) int {
}
}
return 0
return 0
}
func parseBootDiskId(disks []DiskRecord) uint {
@@ -147,10 +146,10 @@ func parseBootDiskId(disks []DiskRecord) uint {
}
}
return 0
return 0
}
// Parse the list of interfaces from compute/get response into a list of networks
// Parse the list of interfaces from compute/get response into a list of networks
// attached to this compute
func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord) []interface{} {
// return value will be used to d.Set("network") item of dataSourceCompute schema
@@ -173,40 +172,14 @@ func parseComputeInterfacesToNetworks(ifaces []InterfaceRecord) []interface{} {
result = append(result, elem)
}
return result
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
// However, this item was excluded from the schema as it is not directly
// managed through Terraform
// managed through Terraform
length := len(ifaces)
log.Debugf("parseComputeInterfaces: called for %d ifaces", length)
@@ -238,7 +211,7 @@ func parseComputeInterfaces(ifaces []InterfaceRecord) []map[string]interface{} {
result[i] = elem
}
return result
return result
}
func flattenCompute(d *schema.ResourceData, compFacts string) error {
@@ -275,12 +248,6 @@ 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 {
@@ -410,24 +377,24 @@ func dataSourceCompute() *schema.Resource {
},
"extra_disks": {
Type: schema.TypeSet,
Computed: true,
Type: schema.TypeSet,
Computed: true,
MaxItems: MaxExtraDisksPerCompute,
Elem: &schema.Schema{
Type: schema.TypeInt,
Elem: &schema.Schema {
Type: schema.TypeInt,
},
Description: "IDs of the extra disk(s) attached to this compute.",
},
/*
"disks": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: dataSourceDiskSchemaMake(), // ID, type, name, size, account ID, SEP ID, SEP type, pool, status, tech status, compute ID, image ID
},
Description: "Detailed specification for all disks attached to this compute instance (including bood disk).",
"disks": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: dataSourceDiskSchemaMake(), // ID, type, name, size, account ID, SEP ID, SEP type, pool, status, tech status, compute ID, image ID
},
Description: "Detailed specification for all disks attached to this compute instance (including bood disk).",
},
*/
"network": {
@@ -441,14 +408,14 @@ func dataSourceCompute() *schema.Resource {
},
/*
"interfaces": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: interfaceSubresourceSchemaMake(),
},
Description: "Specification for the virtual NICs configured on this compute instance.",
"interfaces": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: interfaceSubresourceSchemaMake(),
},
Description: "Specification for the virtual NICs configured on this compute instance.",
},
*/
"os_users": {
@@ -472,31 +439,24 @@ 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,
Computed: true,
Description: "Current model status of this compute instance.",
},
/*
"status": {
Type: schema.TypeString,
Computed: true,
Description: "Current model status of this compute instance.",
},
"tech_status": {
Type: schema.TypeString,
Computed: true,
Description: "Current technical status of this compute instance.",
},
"tech_status": {
Type: schema.TypeString,
Computed: true,
Description: "Current technical status of this compute instance.",
},
"internal_ip": {
Type: schema.TypeString,
Computed: true,
Description: "Internal IP address of this Compute.",
},
"internal_ip": {
Type: schema.TypeString,
Computed: true,
Description: "Internal IP address of this Compute.",
},
*/
},
}

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
}

144
decort/data_source_pfw.go Normal file
View File

@@ -0,0 +1,144 @@
/*
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

@@ -105,12 +105,12 @@ type ResgroupUpdateParam struct {
// structures related to /cloudapi/rg/get API call
//
type QuotaRecord struct { // this is how quota is reported by /api/.../rg/get
Cpu int `json:"CU_C"` // CPU count in pcs
Ram float64 `json:"CU_M"` // RAM volume in MB, it is STILL reported as FLOAT
Disk int `json:"CU_D"` // Disk capacity in GB
ExtIPs int `json:"CU_I"` // Ext IPs count
ExtTraffic int `json:"CU_NP"` // Ext network traffic
GpuUnits int `json:"gpu_units"` // GPU count
Cpu int `json:"CU_C"` // CPU count in pcs
Ram float64 `json:"CU_M"` // RAM volume in MB, it is STILL reported as FLOAT
Disk int `json:"CU_D"` // Disk capacity in GB
ExtIPs int `json:"CU_I"` // Ext IPs count
ExtTraffic int `json:"CU_NP"` // Ext network traffic
GpuUnits int `json:"gpu_units"` // GPU count
}
type ResourceRecord struct { // this is how actual usage is reported by /api/.../rg/get
@@ -130,27 +130,27 @@ type UsageRecord struct {
const ResgroupGetAPI = "/restmachine/cloudapi/rg/get"
type ResgroupGetResp struct {
ACLs []UserAclRecord `json:"ACLs"`
Usage UsageRecord `json:"Resources"`
AccountID int `json:"accountId"`
AccountName string `json:"accountName"`
GridID int `json:"gid"`
CreatedBy string `json:"createdBy"`
CreatedTime uint64 `json:"createdTime"`
DefaultNetID int `json:"def_net_id"`
DefaultNetType string `json:"def_net_type"`
DeletedBy string `json:"deletedBy"`
DeletedTime uint64 `json:"deletedTime"`
Desc string `json:"desc"`
ID uint `json:"id"`
LockStatus string `json:"lockStatus"`
Name string `json:"name"`
Quota QuotaRecord `json:"resourceLimits"`
Status string `json:"status"`
UpdatedBy string `json:"updatedBy"`
UpdatedTime uint64 `json:"updatedTime"`
Vins []int `json:"vins"`
Computes []int `json:"vms"`
ACLs []UserAclRecord `json:"ACLs"`
Usage UsageRecord `json:"Resources"`
AccountID int `json:"accountId"`
AccountName string `json:"accountName"`
GridID int `json:"gid"`
CreatedBy string `json:"createdBy"`
CreatedTime uint64 `json:"createdTime"`
DefaultNetID int `json:"def_net_id"`
DefaultNetType string `json:"def_net_type"`
DeletedBy string `json:"deletedBy"`
DeletedTime uint64 `json:"deletedTime"`
Desc string `json:"desc"`
ID uint `json:"id"`
LockStatus string `json:"lockStatus"`
Name string `json:"name"`
Quota QuotaRecord `json:"resourceLimits"`
Status string `json:"status"`
UpdatedBy string `json:"updatedBy"`
UpdatedTime uint64 `json:"updatedTime"`
Vins []int `json:"vins"`
Computes []int `json:"vms"`
Ignored map[string]interface{} `json:"-"`
}
@@ -187,23 +187,22 @@ const KvmX86CreateAPI = "/restmachine/cloudapi/kvmx86/create"
const KvmPPCCreateAPI = "/restmachine/cloudapi/kvmppc/create"
type KvmVmCreateParam struct { // this is unified structure for both x86 and PPC based KVM VMs creation
RgID uint `json:"rgId"`
Name string `json:"name"`
Cpu int `json:"cpu"`
Ram int `json:"ram"`
ImageID int `json:"imageId"`
BootDisk int `json:"bootDisk"`
NetType string `json:"netType"`
NetId int `json:"netId"`
IPAddr string `json:"ipAddr"`
UserData string `json:"userdata"`
Desc string `json:"desc"`
Start bool `json:"start"`
RgID uint `json:"rgId"`
Name string `json:"name"`
Cpu int `json:"cpu"`
Ram int `json:"ram"`
ImageID int `json:"imageId"`
BootDisk int `json:"bootDisk"`
NetType string `json:"netType"`
NetId int `json:"netId"`
IPAddr string `json:"ipAddr"`
UserData string `json:"userdata"`
Desc string `json:"desc"`
Start bool `json:"start"`
}
// 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"
@@ -272,14 +271,14 @@ type ComputeRecord struct {
SnapSets []SnapSetRecord `json:"snapSets"`
Status string `json:"status"`
// Tags []string `json:"tags"` // Tags were reworked since DECORT 3.7.1
TechStatus string `json:"techStatus"`
TotalDiskSize int `json:"totalDiskSize"`
UpdatedBy string `json:"updatedBy"`
UpdateTime uint64 `json:"updateTime"`
UserManaged bool `json:"userManaged"`
Vgpus []int `json:"vgpus"`
VinsConnected int `json:"vinsConnected"`
VirtualImageID int `json:"virtualImageId"`
TechStatus string `json:"techStatus"`
TotalDiskSize int `json:"totalDiskSize"`
UpdatedBy string `json:"updatedBy"`
UpdateTime uint64 `json:"updateTime"`
UserManaged bool `json:"userManaged"`
Vgpus []int `json:"vgpus"`
VinsConnected int `json:"vinsConnected"`
VirtualImageID int `json:"virtualImageId"`
}
const ComputeListAPI = "/restmachine/cloudapi/compute/list"
@@ -303,7 +302,7 @@ type DiskRecord struct {
// ACLs `json:"ACL"` - it is a dictionary, special parsing required
// was - Acl map[string]string `json:"acl"`
AccountID int `json:"accountId"`
AccountName string `json:"accountName"` // NOTE: absent from compute/get output
AccountName string `json:"accountName"` // NOTE: absent from compute/get output
BootPartition int `json:"bootPartition"`
CreatedTime uint64 `json:"creationTime"`
DeletedTime uint64 `json:"deletionTime"`
@@ -326,7 +325,7 @@ type DiskRecord struct {
PurgeTime uint64 `json:"purgeTime"`
// Role string `json:"role"`
SepType string `json:"sepType"`
SepID int `json:"sepId"` // NOTE: absent from compute/get output
SepID int `json:"sepId"` // NOTE: absent from compute/get output
SizeMax int `json:"sizeMax"`
SizeUsed int `json:"sizeUsed"` // sum over all snapshots of this disk to report total consumed space
Snapshots []SnapshotRecord `json:"snapshots"`
@@ -377,14 +376,14 @@ type ComputeGetResp struct {
SnapSets []SnapSetRecord `json:"snapSets"`
Status string `json:"status"`
// Tags []string `json:"tags"` // Tags were reworked since DECORT 3.7.1
TechStatus string `json:"techStatus"`
TotalDiskSize int `json:"totalDiskSize"`
UpdatedBy string `json:"updatedBy"`
UpdateTime uint64 `json:"updateTime"`
UserManaged bool `json:"userManaged"`
Vgpus []int `json:"vgpus"`
VinsConnected int `json:"vinsConnected"`
VirtualImageID int `json:"virtualImageId"`
TechStatus string `json:"techStatus"`
TotalDiskSize int `json:"totalDiskSize"`
UpdatedBy string `json:"updatedBy"`
UpdateTime uint64 `json:"updateTime"`
UserManaged bool `json:"userManaged"`
Vgpus []int `json:"vgpus"`
VinsConnected int `json:"vinsConnected"`
VirtualImageID int `json:"virtualImageId"`
}
//
@@ -447,7 +446,20 @@ type AccountsListResp []AccountRecord
//
// structures related to /cloudapi/portforwarding/list API
//
type PfwRecord struct {
// 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 {
ID int `json:"id"`
LocalIP string `json:"localIp"`
LocalPort int `json:"localPort"`
@@ -457,9 +469,12 @@ type PfwRecord struct {
ComputeID int `json:"vmId"`
}
const ComputePfwListAPI = "/restmachine/cloudapi/compute/pfwList"
type ComputePfwListResp struct {
Header PfwPrefixRecord `json:"header"`
Rules []PfwRuleRecord `json:"rules"`
}
type ComputePfwListResp []PfwRecord
const ComputePfwListAPI = "/restmachine/cloudapi/compute/pfwList"
const ComputePfwAddAPI = "/restmachine/cloudapi/compute/pfwAdd"
@@ -469,12 +484,11 @@ const ComputePfwDelAPI = "/restmachine/cloudapi/compute/pfwDel"
// structures related to /cloudapi/compute/net Attach/Detach API
//
type ComputeNetMgmtRecord struct { // used to "cache" network specs when preparing to manage compute networks
ID int
Type string
IPAddress string
MAC string
ID int
Type string
IPAddress string
MAC string
}
const ComputeNetAttachAPI = "/restmachine/cloudapi/compute/netAttach"
const ComputeNetDetachAPI = "/restmachine/cloudapi/compute/netDetach"
@@ -514,52 +528,52 @@ const DisksRenameAPI = "/restmachine/cloudapi/disks/rename"
//
const DisksDeleteAPI = "/restmachine/cloudapi/disks/delete"
//
// ViNS structures
// ViNS structures
//
// this is the structure of the element in the list returned by vins/search API
type VinsSearchRecord struct {
ID int `json:"id"`
Name string `json:"name"`
IPCidr string `json:"network"`
VxLanID int `json:"vxlanId"`
ExternalIP string `json:"externalIP"`
AccountID int `json:"accountId"`
AccountName string `json:"accountName"`
RgID int `json:"rgId"`
RgName string `json:"rgName"`
type VinsSearchRecord struct {
ID int `json:"id"`
Name string `json:"name"`
IPCidr string `json:"network"`
VxLanID int `json:"vxlanId"`
ExternalIP string `json:"externalIP"`
AccountID int `json:"accountId"`
AccountName string `json:"accountName"`
RgID int `json:"rgId"`
RgName string `json:"rgName"`
}
const VinsSearchAPI = "/restmachine/cloudapi/vins/search"
type VinsSearchResp []VinsSearchRecord
type VnfRecord struct {
ID int `json:"id"`
AccountID int `json:"accountId"`
Type string `json:"type"` // "DHCP", "NAT", "GW" etc
Config map[string]interface{} `json:"config"` // NOTE: VNF specs vary by VNF type
ID int `json:"id"`
AccountID int `json:"accountId"`
Type string `json:"type"` // "DHCP", "NAT", "GW" etc
Config map[string]interface{} `json:"config"` // NOTE: VNF specs vary by VNF type
}
type VnfGwConfigRecord struct { // describes GW VNF config structure inside ViNS, as returned by API vins/get
ExtNetID int `json:"ext_net_id"`
ExtNetIP string `json:"ext_net_ip"`
ExtNetMask int `json:"ext_net_mask"`
DefaultGW string `json:"default_gw"`
ExtNetID int `json:"ext_net_id"`
ExtNetIP string `json:"ext_net_ip"`
ExtNetMask int `json:"ext_net_mask"`
DefaultGW string `json:"default_gw"`
}
type VinsRecord struct { // represents part of the response from API vins/get
ID int `json:"id"`
Name string `json:"name"`
IPCidr string `json:"network"`
VxLanID int `json:"vxlanId"`
ExternalIP string `json:"externalIP"`
AccountID int `json:"accountId"`
AccountName string `json:"accountName"`
RgID int `json:"rgid"`
RgName string `json:"rgName"`
VNFs map[string]VnfRecord `json:"vnfs"`
Desc string `json:"desc"`
ID int `json:"id"`
Name string `json:"name"`
IPCidr string `json:"network"`
VxLanID int `json:"vxlanId"`
ExternalIP string `json:"externalIP"`
AccountID int `json:"accountId"`
AccountName string `json:"accountName"`
RgID int `json:"rgid"`
RgName string `json:"rgName"`
VNFs map[string]VnfRecord `json:"vnfs"`
Desc string `json:"desc"`
}
const VinsGetAPI = "/restmachine/cloudapi/vins/get"
@@ -574,13 +588,13 @@ const VinsDeleteAPI = "/restmachine/cloudapi/vins/delete"
//
// Grid ID structures
//
//
type LocationRecord struct {
GridID int `json:"gid"`
Id int `json:"id"`
LocationCode string `json:"locationCode"`
Name string `json:"name"`
Flag string `json:"flag"`
GridID int `json:"gid"`
Id int `json:"id"`
LocationCode string `json:"locationCode"`
Name string `json:"name"`
Flag string `json:"flag"`
}
const LocationsListAPI = "/restmachine/cloudapi/locations/list" // Returns list of GridRecord on success

View File

@@ -103,7 +103,7 @@ func Provider() *schema.Provider {
"decort_kvmvm": resourceCompute(),
"decort_disk": resourceDisk(),
"decort_vins": resourceVins(),
// "decort_pfw": resourcePfw(),
"decort_pfw": resourcePfw(),
},
DataSourcesMap: map[string]*schema.Resource{
@@ -113,7 +113,7 @@ func Provider() *schema.Provider {
"decort_image": dataSourceImage(),
"decort_disk": dataSourceDisk(),
"decort_vins": dataSourceVins(),
// "decort_pfw": dataSourcePfw(),
"decort_pfw": dataSourcePfw(),
},
ConfigureFunc: providerConfigure,

View File

@@ -50,15 +50,15 @@ func cloudInitDiffSupperss(key, oldVal, newVal string, d *schema.ResourceData) b
}
func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
// we assume all mandatory parameters it takes to create a comptue instance are properly
// we assume all mandatory parameters it takes to create a comptue instance are properly
// specified - we rely on schema "Required" attributes to let Terraform validate them for us
log.Debugf("resourceComputeCreate: called for Compute name %q, RG ID %d", d.Get("name").(string), d.Get("rg_id").(int))
// create basic Compute (i.e. without extra disks and network connections - those will be attached
// by subsequent individual API calls).
// creating Compute is a multi-step workflow, which may fail at some step, so we use "partial" feature of Terraform
d.Partial(true)
d.Partial(true)
controller := m.(*ControllerCfg)
urlValues := &url.Values{}
urlValues.Add("rgId", fmt.Sprintf("%d", d.Get("rg_id").(int)))
@@ -68,32 +68,32 @@ func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
urlValues.Add("imageId", fmt.Sprintf("%d", d.Get("image_id").(int)))
urlValues.Add("bootDisk", fmt.Sprintf("%d", d.Get("boot_disk_size").(int)))
urlValues.Add("netType", "NONE") // at the 1st step create isolated compute
urlValues.Add("start", "0") // at the 1st step create compute in a stopped state
urlValues.Add("start", "0") // at the 1st step create compute in a stopped state
argVal, argSet := d.GetOk("description")
argVal, argSet := d.GetOk("description")
if argSet {
urlValues.Add("desc", argVal.(string))
}
/*
sshKeysVal, sshKeysSet := d.GetOk("ssh_keys")
if sshKeysSet {
// process SSH Key settings and set API values accordingly
log.Debugf("resourceComputeCreate: calling makeSshKeysArgString to setup SSH keys for guest login(s)")
urlValues.Add("userdata", makeSshKeysArgString(sshKeysVal.([]interface{})))
}
sshKeysVal, sshKeysSet := d.GetOk("ssh_keys")
if sshKeysSet {
// process SSH Key settings and set API values accordingly
log.Debugf("resourceComputeCreate: calling makeSshKeysArgString to setup SSH keys for guest login(s)")
urlValues.Add("userdata", makeSshKeysArgString(sshKeysVal.([]interface{})))
}
*/
computeCreateAPI := KvmX86CreateAPI
driver := d.Get("driver").(string)
if driver == "KVM_PPC" {
arch := d.Get("arch").(string)
if arch == "KVM_PPC" {
computeCreateAPI = KvmPPCCreateAPI
log.Debugf("resourceComputeCreate: creating Compute of type KVM VM PowerPC")
} else { // note that we do not validate arch value for explicit "KVM_X86" here
log.Debugf("resourceComputeCreate: creating Compute of type KVM VM x86")
}
argVal, argSet = d.GetOk("cloud_init")
argVal, argSet = d.GetOk("cloud_init")
if argSet {
// userdata must not be empty string and must not be a reserved keyword "applied"
userdata := argVal.(string)
@@ -101,8 +101,8 @@ func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
urlValues.Add("userdata", userdata)
}
}
apiResp, err := controller.decortAPICall("POST", computeCreateAPI, urlValues)
apiResp, err, _ := controller.decortAPICall("POST", computeCreateAPI, urlValues)
if err != nil {
return err
}
@@ -117,16 +117,16 @@ func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
d.SetPartial("image_id")
d.SetPartial("boot_disk_size")
/*
if sshKeysSet {
d.SetPartial("ssh_keys")
}
if sshKeysSet {
d.SetPartial("ssh_keys")
}
*/
log.Debugf("resourceComputeCreate: new simple Compute ID %d, name %s created", compId, d.Get("name").(string))
// Configure data disks if any
extraDisksOk := true
argVal, argSet = d.GetOk("extra_disks")
argVal, argSet = d.GetOk("extra_disks")
if argSet && argVal.(*schema.Set).Len() > 0 {
// urlValues.Add("desc", argVal.(string))
log.Debugf("resourceComputeCreate: calling utilityComputeExtraDisksConfigure to attach %d extra disk(s)", argVal.(*schema.Set).Len())
@@ -142,8 +142,8 @@ func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
// Configure external networks if any
netsOk := true
argVal, argSet = d.GetOk("network")
if argSet && argVal.(*schema.Set).Len() > 0 {
argVal, argSet = d.GetOk("network")
if argSet && argVal.(*schema.Set).Len() > 0 {
log.Debugf("resourceComputeCreate: calling utilityComputeNetworksConfigure to attach %d network(s)", argVal.(*schema.Set).Len())
err = controller.utilityComputeNetworksConfigure(d, false) // do_delta=false, as we are working on a new compute
if err != nil {
@@ -161,25 +161,23 @@ func resourceComputeCreate(d *schema.ResourceData, m interface{}) error {
d.Partial(false)
}
// Note bene: we created compute in a STOPPED state (this is required to properly attach 1st network interface),
// 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)
if err != nil {
return err
}
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)
if err != nil {
return err
}
log.Debugf("resourceComputeCreate: new Compute ID %d, name %s creation sequence complete", compId, d.Get("name").(string))
// We may reuse dataSourceComputeRead here as we maintain similarity
// We may reuse dataSourceComputeRead here as we maintain similarity
// between Compute resource and Compute data source schemas
// Compute read function will also update resource ID on success, so that Terraform
// Compute read function will also update resource ID on success, so that Terraform
// will know the resource exists
return dataSourceComputeRead(d, m)
return dataSourceComputeRead(d, m)
}
func resourceComputeRead(d *schema.ResourceData, m interface{}) error {
@@ -188,6 +186,7 @@ func resourceComputeRead(d *schema.ResourceData, m interface{}) error {
compFacts, err := utilityComputeCheckPresence(d, m)
if compFacts == "" {
d.SetId("")
if err != nil {
return err
}
@@ -211,12 +210,11 @@ func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
controller := m.(*ControllerCfg)
/*
1. Resize CPU/RAM
2. Resize (grow) boot disk
3. Update extra disks
4. Update networks
5. Start/stop
/*
1. Resize CPU/RAM
2. Resize (grow) boot disk
3. Update extra disks
4. Update networks
*/
// 1. Resize CPU/RAM
@@ -233,7 +231,7 @@ func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
} else {
params.Add("cpu", "0") // no change to CPU allocation
}
oldRam, newRam := d.GetChange("ram")
if oldRam.(int) != newRam.(int) {
params.Add("ram", fmt.Sprintf("%d", newRam.(int)))
@@ -244,9 +242,9 @@ func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
if doUpdate {
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)
oldCpu.(int), newCpu.(int),
oldRam.(int), newRam.(int))
_, err, _ := controller.decortAPICall("POST", ComputeResizeAPI, params)
if err != nil {
return err
}
@@ -254,15 +252,15 @@ func resourceComputeUpdate(d *schema.ResourceData, m interface{}) error {
d.SetPartial("ram")
}
// 2. Resize (grow) Boot disk
// 2. Resize (grow) Boot disk
oldSize, newSize := d.GetChange("boot_disk_size")
if oldSize.(int) < newSize.(int) {
bdsParams := &url.Values{}
bdsParams.Add("diskId", fmt.Sprintf("%d", d.Get("boot_disk_id").(int)))
bdsParams.Add("size", fmt.Sprintf("%d", newSize.(int)))
log.Debugf("resourceComputeUpdate: compute ID %s, boot disk ID %d resize %d -> %d",
d.Id(), d.Get("boot_disk_id").(int), oldSize.(int), newSize.(int))
_, err := controller.decortAPICall("POST", DisksResizeAPI, params)
d.Id(), d.Get("boot_disk_id").(int), oldSize.(int), newSize.(int))
_, err, _ := controller.decortAPICall("POST", DisksResizeAPI, params)
if err != nil {
return err
}
@@ -287,32 +285,17 @@ 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
// we may reuse dataSourceComputeRead here as we maintain similarity
// between Compute resource and Compute data source schemas
return dataSourceComputeRead(d, m)
return dataSourceComputeRead(d, m)
}
func resourceComputeDelete(d *schema.ResourceData, m interface{}) error {
// NOTE: this function destroys target Compute instance "permanently", so
// there is no way to restore it.
// If compute being destroyed has some extra disks attached, they are
// NOTE: this function destroys target Compute instance "permanently", so
// there is no way to restore it.
// If compute being destroyed has some extra disks attached, they are
// detached from the compute
log.Debugf("resourceComputeDelete: called for Compute name %s, RG ID %d",
d.Get("name").(string), d.Get("rg_id").(int))
@@ -330,7 +313,7 @@ func resourceComputeDelete(d *schema.ResourceData, m interface{}) error {
log.Debugf("resourceComputeDelete: ready to unmarshal string %s", compFacts)
err = json.Unmarshal([]byte(compFacts), &model)
if err == nil && len(model.Disks) > 0 {
// prepare to detach data disks from compute - do it only if compFacts unmarshalled
// prepare to detach data disks from compute - do it only if compFacts unmarshalled
// properly and the resulting model contains non-empty Disks list
for _, diskFacts := range model.Disks {
if diskFacts.Type == "B" {
@@ -344,7 +327,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)
@@ -356,8 +339,8 @@ func resourceComputeDelete(d *schema.ResourceData, m interface{}) error {
params.Add("computeId", d.Id())
params.Add("permanently", "1")
// TODO: this is for the upcoming API update - params.Add("detachdisks", "1")
_, err = controller.decortAPICall("POST", ComputeDeleteAPI, params)
_, err, _ = controller.decortAPICall("POST", ComputeDeleteAPI, params)
if err != nil {
return err
}
@@ -416,13 +399,13 @@ func resourceCompute() *schema.Resource {
Description: "ID of the resource group where this compute should be deployed.",
},
"driver": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
StateFunc: stateFuncToUpper,
"arch": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
StateFunc: stateFuncToUpper,
ValidateFunc: validation.StringInSlice([]string{"KVM_X86", "KVM_PPC"}, false), // observe case while validating
Description: "Hardware architecture of this compute instance.",
Description: "Hardware architecture of this compute instance.",
},
"cpu": {
@@ -440,16 +423,16 @@ func resourceCompute() *schema.Resource {
},
"image_id": {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
Type: schema.TypeInt,
Required: true,
ForceNew: true,
ValidateFunc: validation.IntAtLeast(1),
Description: "ID of the OS image to base this compute instance on.",
Description: "ID of the OS image to base this compute instance on.",
},
"boot_disk_size": {
Type: schema.TypeInt,
Required: true,
Type: schema.TypeInt,
Required: true,
Description: "This compute instance boot disk size in GB. Make sure it is large enough to accomodate selected OS image.",
},
@@ -474,15 +457,15 @@ func resourceCompute() *schema.Resource {
},
/*
"ssh_keys": {
Type: schema.TypeList,
Optional: true,
MaxItems: MaxSshKeysPerCompute,
Elem: &schema.Resource{
Schema: sshSubresourceSchemaMake(),
},
Description: "SSH keys to authorize on this compute instance.",
"ssh_keys": {
Type: schema.TypeList,
Optional: true,
MaxItems: MaxSshKeysPerCompute,
Elem: &schema.Resource{
Schema: sshSubresourceSchemaMake(),
},
Description: "SSH keys to authorize on this compute instance.",
},
*/
"description": {
@@ -491,12 +474,13 @@ func resourceCompute() *schema.Resource {
Description: "Optional text description of this compute instance.",
},
"cloud_init": {
Type: schema.TypeString,
Optional: true,
Default: "applied",
Type: schema.TypeString,
Optional: true,
Default: "applied",
DiffSuppressFunc: cloudInitDiffSupperss,
Description: "Optional cloud_init parameters. Applied when creating new compute instance only, ignored in all other cases.",
Description: "Optional cloud_init parameters. Applied when creating new compute instance only, ignored in all other cases.",
},
// The rest are Compute properties, which are "computed" once it is created
@@ -533,44 +517,37 @@ 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,
Computed: true,
Elem: &schema.Resource{
Schema: dataSourceDiskSchemaMake(), // ID, type, name, size, account ID, SEP ID, SEP type, pool, status, tech status, compute ID, image ID
},
Description: "Detailed specification for all disks attached to this compute instance (including bood disk).",
},
/*
"disks": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: dataSourceDiskSchemaMake(), // ID, type, name, size, account ID, SEP ID, SEP type, pool, status, tech status, compute ID, image ID
},
Description: "Detailed specification for all disks attached to this compute instance (including bood disk).",
},
"interfaces": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: interfaceSubresourceSchemaMake(),
},
Description: "Specification for the virtual NICs configured on this compute instance.",
"interfaces": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: interfaceSubresourceSchemaMake(),
},
Description: "Specification for the virtual NICs configured on this compute instance.",
},
"status": {
Type: schema.TypeString,
Computed: true,
Description: "Current model status of this compute instance.",
},
"status": {
Type: schema.TypeString,
Computed: true,
Description: "Current model status of this compute instance.",
},
"tech_status": {
Type: schema.TypeString,
Computed: true,
Description: "Current technical status of this compute instance.",
},
"tech_status": {
Type: schema.TypeString,
Computed: true,
Description: "Current technical status of this compute instance.",
},
*/
},
}

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
}

212
decort/resource_pfw.go Normal file
View File

@@ -0,0 +1,212 @@
/*
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"
log "github.com/sirupsen/logrus"
"net/url"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
)
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))
controller := m.(*ControllerCfg)
apiErrCount := 0
var lastSavedError error
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 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)
}
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))
// return resourcePfwRead(d, m)
}
func resourcePfwDelete(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("resourcePfwDelete: no PFW rules defined for compute ID %d - nothing to delete", compId.(int))
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
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)
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 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))
pfwFacts, err := utilityPfwCheckPresence(d, m)
if pfwFacts == "" {
if err != nil {
return false, err
}
return false, nil
}
return true, nil
}
func resourcePfw() *schema.Resource {
return &schema.Resource{
SchemaVersion: 1,
Create: resourcePfwCreate,
Read: resourcePfwRead,
Update: resourcePfwUpdate,
Delete: resourcePfwDelete,
Exists: resourcePfwExists,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Timeouts: &schema.ResourceTimeout{
Create: &Timeout180s,
Read: &Timeout30s,
Update: &Timeout180s,
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.",
},
},
}
}

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

@@ -0,0 +1,77 @@
/*
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
}

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
}

208
decort/utility_pfw.go Normal file
View File

@@ -0,0 +1,208 @@
/*
Copyright (c) 2020-2021 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Author: Sergey Shubin, <sergey.shubin@digitalenergy.online>, <svs1370@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
This file is part of Terraform (by Hashicorp) provider for Digital Energy Cloud Orchestration
Technology platfom.
Visit https://github.com/rudecs/terraform-provider-decort for full source code package and updates.
*/
package decort
import (
"encoding/json"
"fmt"
"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
//
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
}
if err != nil {
return "", 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
}
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)
if err != nil {
log.Errorf("utilityPfwCheckPresence: failed to unmarshal prefix part of API response: %s", err)
return "", 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
}
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
}
// 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
}

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

@@ -1,37 +0,0 @@
---
# 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)

View File

@@ -1,45 +0,0 @@
---
# 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

@@ -1,44 +0,0 @@
---
# 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

@@ -1,81 +0,0 @@
---
# 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.
- **arch** (String) Hardware architecture of this compute instance.
- **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.
- **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

@@ -1,58 +0,0 @@
---
# 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)

View File

@@ -1,45 +0,0 @@
---
# 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)

View File

@@ -1,31 +0,0 @@
---
# 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.

View File

@@ -1,51 +0,0 @@
---
# 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)

View File

@@ -1,85 +0,0 @@
---
# 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)

View File

@@ -1,63 +0,0 @@
---
# 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)

View File

@@ -1,48 +0,0 @@
---
# 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)

1
go.mod
View File

@@ -4,7 +4,6 @@ go 1.15
require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
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,26 +34,11 @@ 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=
@@ -62,12 +47,9 @@ 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=
@@ -89,7 +71,6 @@ 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=
@@ -97,22 +78,12 @@ 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=
@@ -153,9 +124,8 @@ 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=
@@ -168,24 +138,20 @@ 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=
@@ -200,9 +166,8 @@ 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=
@@ -215,13 +180,7 @@ 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=
@@ -230,17 +189,10 @@ 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=
@@ -250,16 +202,10 @@ 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/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 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
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=
@@ -267,25 +213,19 @@ 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=
@@ -299,16 +239,14 @@ 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/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 h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
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=
@@ -316,14 +254,9 @@ 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=
@@ -331,38 +264,25 @@ 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=
@@ -378,11 +298,8 @@ 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=
@@ -442,10 +359,8 @@ 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=
@@ -462,7 +377,6 @@ 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=
@@ -474,7 +388,6 @@ 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=
@@ -490,23 +403,14 @@ 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=
@@ -632,19 +536,14 @@ 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,8 +38,6 @@ 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

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

View File

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