package provider import ( "context" "crypto/tls" "net/http" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" log "github.com/sirupsen/logrus" decort "repository.basistech.ru/BASIS/decort-golang-sdk" sdk_config "repository.basistech.ru/BASIS/decort-golang-sdk/config" ) // enumerated constants that define authentication modes for Configure const ( MODE_UNDEF = iota // this is the invalid mode - it should never be seen MODE_LEGACY MODE_DECS3O MODE_JWT MODE_BVS ) // Ensure DynamixProvider satisfies various provider interfaces. var _ provider.Provider = &DynamixProvider{} // DynamixProvider defines the provider implementation. type DynamixProvider struct { // version is set to the provider version on release, "dev" when the // provider is built and ran locally, and "test" when running acceptance // testing. version string } // dynamixProviderModel describes the provider data model. type dynamixProviderModel struct { Authenticator types.String `tfsdk:"authenticator"` Oauth2Url types.String `tfsdk:"oauth2_url"` ControllerUrl types.String `tfsdk:"controller_url"` User types.String `tfsdk:"user"` Password types.String `tfsdk:"password"` BvsUser types.String `tfsdk:"bvs_user"` BvsPassword types.String `tfsdk:"bvs_password"` Domain types.String `tfsdk:"domain"` AppId types.String `tfsdk:"app_id"` AppSecret types.String `tfsdk:"app_secret"` Jwt types.String `tfsdk:"jwt"` AllowUnverifiedSsl types.Bool `tfsdk:"allow_unverified_ssl"` PathConfig types.String `tfsdk:"path_config"` PathToken types.String `tfsdk:"path_token"` TimeToRefresh types.Int64 `tfsdk:"time_to_refresh"` } func (p *DynamixProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) { resp.TypeName = "dynamix" resp.Version = p.version } func (p *DynamixProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ "authenticator": schema.StringAttribute{ MarkdownDescription: "Authentication mode to use when connecting to DECORT cloud API. Should be one of 'decs3o', 'legacy', 'jwt' or 'bvs'.", Required: true, Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive("decs3o", "legacy", "jwt", "bvs"), // ignore case while validating }, }, "oauth2_url": schema.StringAttribute{ MarkdownDescription: "OAuth2 application URL in 'decs3o' and 'bvs' authentication mode.", Optional: true, }, "controller_url": schema.StringAttribute{ MarkdownDescription: "URL of DECORT Cloud controller to use. API calls will be directed to this URL.", Required: true, }, "user": schema.StringAttribute{ MarkdownDescription: "User name for DECORT cloud API operations in 'legacy' authentication mode.", Optional: true, }, "password": schema.StringAttribute{ MarkdownDescription: "User password for DECORT cloud API operations in 'legacy' authentication mode.", Optional: true, }, "bvs_user": schema.StringAttribute{ MarkdownDescription: "User name for DECORT cloud API operations in 'bvs' authentication mode.", Optional: true, }, "bvs_password": schema.StringAttribute{ MarkdownDescription: "User password for DECORT cloud API operations in 'bvs' authentication mode.", Optional: true, }, "domain": schema.StringAttribute{ MarkdownDescription: "User password for DECORT cloud API operations in 'bvs' authentication mode.", Optional: true, }, "app_id": schema.StringAttribute{ MarkdownDescription: "Application ID to access DECORT cloud API in 'decs3o' and 'bvs' authentication mode.", Optional: true, }, "app_secret": schema.StringAttribute{ MarkdownDescription: "Application secret to access DECORT cloud API in 'decs3o' and 'bvs' authentication mode.", Optional: true, }, "jwt": schema.StringAttribute{ MarkdownDescription: "JWT to access DECORT cloud API in 'jwt' authentication mode.", Optional: true, }, "allow_unverified_ssl": schema.BoolAttribute{ MarkdownDescription: "If true, DECORT API will not verify SSL certificates. Use this with caution and in trusted environments only! Default is false.", Optional: true, }, "path_config": schema.StringAttribute{ MarkdownDescription: "The path of the configuration file entry.", Optional: true, }, "path_token": schema.StringAttribute{ MarkdownDescription: "The path of the token file entry.", Optional: true, }, "time_to_refresh": schema.Int64Attribute{ MarkdownDescription: "The number of minutes before the expiration of the token, a refresh will be made.", Optional: true, }, }, } } func (p *DynamixProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { // Retrieve provider data from configuration var config dynamixProviderModel diags := req.Config.Get(ctx, &config) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { log.Debugf("Provider Configure error after req.Config.Get") return } // Set up default values, values from env and save user provided values into decortConfig dynamixConfig := dynamixProviderConfig{} dynamixConfig.new(config) // Validate and set up authentication mode mode, err := dynamixConfig.validateAuthenticator() if err != nil { log.Debug(err) return } // Set up client transport if dynamixConfig.allowUnverifiedSsl { log.Warn("Provider Configure: allow_unverified_ssl is set - will not check certificates!") transCfg := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} //nolint:gosec dynamixConfig.cc_client = &http.Client{ Transport: transCfg, } } else { dynamixConfig.cc_client = &http.Client{} } // Set up clients for data sources and resources depending on authentication mode switch mode { case MODE_LEGACY: legacyConf := sdk_config.LegacyConfig{ Username: dynamixConfig.user, Password: dynamixConfig.password, DecortURL: dynamixConfig.controllerUrl, SSLSkipVerify: dynamixConfig.allowUnverifiedSsl, } legacyClient := decort.NewLegacy(legacyConf) resp.DataSourceData = legacyClient resp.ResourceData = legacyClient case MODE_JWT: case MODE_DECS3O: sdkConf := sdk_config.Config{ AppID: dynamixConfig.appId, AppSecret: dynamixConfig.appSecret, SSOURL: dynamixConfig.oauth2Url, DecortURL: dynamixConfig.controllerUrl, SSLSkipVerify: dynamixConfig.allowUnverifiedSsl, } decortClient := decort.New(sdkConf) resp.DataSourceData = decortClient resp.ResourceData = decortClient case MODE_BVS: bvsConf := sdk_config.BVSConfig{ AppID: dynamixConfig.appId, AppSecret: dynamixConfig.appSecret, SSOURL: dynamixConfig.oauth2Url, DecortURL: dynamixConfig.controllerUrl, SSLSkipVerify: dynamixConfig.allowUnverifiedSsl, Username: dynamixConfig.bvsUser, Password: dynamixConfig.bvsPassword, Domain: dynamixConfig.domain, Token: dynamixConfig.token, PathCfg: dynamixConfig.pathConfig, PathToken: dynamixConfig.pathToken, TimeToRefresh: dynamixConfig.timeToRefresh, } bvsClient := decort.NewBVS(bvsConf) resp.DataSourceData = bvsClient resp.ResourceData = bvsClient default: log.Debugf("unknown authenticator mode code %d provided", mode) return } } func (p *DynamixProvider) Resources(_ context.Context) []func() resource.Resource { return newResourcesMap() } func (p *DynamixProvider) DataSources(_ context.Context) []func() datasource.DataSource { return newDataSourcesMap() } func New(version string) func() provider.Provider { return func() provider.Provider { return &DynamixProvider{ version: version, } } }