-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
feec9cd
commit b064d59
Showing
5 changed files
with
232 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package api | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/google/uuid" | ||
) | ||
|
||
// BotsClient is a client for working with Service Accounts | ||
type BotsClient interface { | ||
Get(ctx context.Context, id uuid.UUID) (*Bot, error) | ||
} | ||
|
||
// BotAPIKey represents the nested API Key | ||
// included in a Service Account response | ||
type BotAPIKey struct { | ||
BaseModel | ||
Name string `json:"name"` | ||
Key *string `json:"key"` | ||
Expiration *time.Time `json:"expiration"` | ||
} | ||
|
||
// Bot is the base representation of a Service Account | ||
type Bot struct { | ||
BaseModel | ||
Name string `json:"name"` | ||
AccountID uuid.UUID `json:"account_id"` | ||
AccountRoleName string `json:"account_role_name"` | ||
APIKey *BotAPIKey `json:"api_key"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package client | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/google/uuid" | ||
"github.com/prefecthq/terraform-provider-prefect/internal/api" | ||
) | ||
|
||
var _ = api.BotsClient(&BotsClient{}) | ||
|
||
// BotsClient is a client for working with service accounts. | ||
type BotsClient struct { | ||
hc *http.Client | ||
apiKey string | ||
routePrefix string | ||
} | ||
|
||
// Bots returns a BotsClient. | ||
func (c *Client) Bots() (api.BotsClient, error) { | ||
return &BotsClient{ | ||
hc: c.hc, | ||
apiKey: c.apiKey, | ||
routePrefix: fmt.Sprintf("%s/api/accounts/%s/bots", c.endpoint, c.defaultAccountID), | ||
}, nil | ||
} | ||
|
||
// Get a single bot by ID | ||
func (c *BotsClient) Get(ctx context.Context, id uuid.UUID) (*api.Bot, error) { | ||
path := fmt.Sprintf("%s/%s", c.routePrefix, id.String()) | ||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, path, http.NoBody) | ||
if err != nil { | ||
return nil, fmt.Errorf("error creating request: %w", err) | ||
} | ||
|
||
setDefaultHeaders(req, c.apiKey) | ||
|
||
resp, err := c.hc.Do(req) | ||
if err != nil { | ||
return nil, fmt.Errorf("http error: %w", err) | ||
} | ||
defer resp.Body.Close() | ||
|
||
if resp.StatusCode != http.StatusOK { | ||
return nil, fmt.Errorf("status code %s", resp.Status) | ||
} | ||
|
||
var bot api.Bot | ||
if err := json.NewDecoder(resp.Body).Decode(&bot); err != nil { | ||
return nil, fmt.Errorf("failed to decode response: %w", err) | ||
} | ||
|
||
return &bot, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
package datasources | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/datasource" | ||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
"github.com/prefecthq/terraform-provider-prefect/internal/api" | ||
"github.com/prefecthq/terraform-provider-prefect/internal/provider/customtypes" | ||
) | ||
|
||
// Ensure the implementation satisfies the expected interfaces. | ||
var ( | ||
_ datasource.DataSource = &BotDataSource{} | ||
_ datasource.DataSourceWithConfigure = &BotDataSource{} | ||
) | ||
|
||
// BotDataSource contains state for the data source modeling a Prefect Service Account. | ||
type BotDataSource struct { | ||
client api.PrefectClient | ||
} | ||
|
||
// AccountDataSourceModel defines the Terraform data source model. | ||
// the TF data source configuration will be unmarsheled into this struct | ||
// NOTE: the APIKey field is not included in bot fetches and | ||
// is excluded from this datasource model | ||
type BotDataSourceModel struct { | ||
ID customtypes.UUIDValue `tfsdk:"id"` | ||
Created customtypes.TimestampValue `tfsdk:"created"` | ||
Updated customtypes.TimestampValue `tfsdk:"updated"` | ||
|
||
Name types.String `tfsdk:"name"` | ||
AccountID customtypes.UUIDValue `tfsdk:"account_id"` | ||
AccountRoleName types.String `tfsdk:"account_role_name"` | ||
} | ||
|
||
func NewBotDataSource() datasource.DataSource { | ||
return &BotDataSource{} | ||
} | ||
|
||
// Metadata returns the data source type name. | ||
func (d *BotDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { | ||
resp.TypeName = req.ProviderTypeName + "_bot" | ||
} | ||
|
||
func (d *BotDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { | ||
resp.Schema = schema.Schema{ | ||
Description: "Data Source representing a Prefect Service Account", | ||
Attributes: map[string]schema.Attribute{ | ||
"id": schema.StringAttribute{ | ||
Required: true, | ||
CustomType: customtypes.UUIDType{}, | ||
Description: "Service Account UUID", | ||
}, | ||
"created": schema.StringAttribute{ | ||
Computed: true, | ||
CustomType: customtypes.TimestampType{}, | ||
Description: "Date and time of the Service Account creation in RFC 3339 format", | ||
}, | ||
"updated": schema.StringAttribute{ | ||
Computed: true, | ||
CustomType: customtypes.TimestampType{}, | ||
Description: "Date and time that the Service Account was last updated in RFC 3339 format", | ||
}, | ||
"name": schema.StringAttribute{ | ||
Computed: true, | ||
Description: "Name of the Service Account", | ||
}, | ||
"account_id": schema.StringAttribute{ | ||
Computed: true, | ||
CustomType: customtypes.UUIDType{}, | ||
Description: "Account UUID where Service Account resides", | ||
}, | ||
"account_role_name": schema.StringAttribute{ | ||
Computed: true, | ||
Description: "Name of the Service Account", | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
// Configure adds the provider-configured client to the data source. | ||
func (d *BotDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { | ||
if req.ProviderData == nil { | ||
return | ||
} | ||
|
||
client, ok := req.ProviderData.(api.PrefectClient) | ||
if !ok { | ||
resp.Diagnostics.AddError( | ||
"Unexpected Data Source Configure Type", | ||
fmt.Sprintf("Expected api.PrefectClient, got: %T. Please report this issue to the provider developers.", req.ProviderData), | ||
) | ||
|
||
return | ||
} | ||
|
||
d.client = client | ||
} | ||
|
||
func (d *BotDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { | ||
var model BotDataSourceModel | ||
|
||
// Populate the model from data source configuration and emit diagnostics on error | ||
resp.Diagnostics.Append(req.Config.Get(ctx, &model)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
client, err := d.client.Bots() | ||
if err != nil { | ||
resp.Diagnostics.AddError( | ||
"Error creating the Bots client", | ||
fmt.Sprintf("Could not create Bots client, unexpected error: %s. This is a bug in the provider, please report this to the maintainers.", err.Error()), | ||
) | ||
return | ||
} | ||
|
||
bot, err := client.Get(ctx, model.ID.ValueUUID()) | ||
if err != nil { | ||
resp.Diagnostics.AddError( | ||
"Failed to fetch Bot and refresh state", | ||
fmt.Sprintf("Could not fetch Bot, unexpected error: %s", err.Error()), | ||
) | ||
return | ||
} | ||
|
||
model.ID = customtypes.NewUUIDValue(bot.ID) | ||
model.Created = customtypes.NewTimestampPointerValue(bot.Created) | ||
model.Updated = customtypes.NewTimestampPointerValue(bot.Updated) | ||
|
||
model.Name = types.StringValue(bot.Name) | ||
model.AccountID = customtypes.NewUUIDValue(bot.AccountID) | ||
model.AccountRoleName = types.StringValue(bot.AccountRoleName) | ||
|
||
resp.Diagnostics.Append(resp.State.Set(ctx, &model)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters