From 271ce9338728f44c7a71b7cd55ed78d0ed5bea62 Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Sun, 25 Jun 2023 00:33:39 +0200 Subject: Add jobs datasource --- CHANGELOG.md | 7 +- docs/data-sources/jobs.md | 112 ++++++++++++ internal/provider/jobs_data_source.go | 332 ++++++++++++++++++++++++++++++++++ internal/provider/provider.go | 1 + 4 files changed, 450 insertions(+), 2 deletions(-) create mode 100644 docs/data-sources/jobs.md create mode 100644 internal/provider/jobs_data_source.go diff --git a/CHANGELOG.md b/CHANGELOG.md index c777260..3920bec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ -## 0.0.3 - 2023-06-24 +## 0.0.3 - 2023-06-26 + +### Features +* Add jobs datasource ### Notes * Update projects data source schema to use an extended attributes definition @@ -10,6 +13,6 @@ ## 0.0.1 - 2023-06-19 -### FEATURES +### Features * Add projects datasource * Add project resource diff --git a/docs/data-sources/jobs.md b/docs/data-sources/jobs.md new file mode 100644 index 0000000..784e37b --- /dev/null +++ b/docs/data-sources/jobs.md @@ -0,0 +1,112 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "eventline_jobs Data Source - terraform-provider-eventline" +subcategory: "" +description: |- + Use this data source to retrieve information about existing eventline jobs. +--- + +# eventline_jobs (Data Source) + +Use this data source to retrieve information about existing eventline jobs. + + + + +## Schema + +### Required + +- `project_id` (String) The identifier of the project the jobs are part of. + +### Read-Only + +- `elements` (Attributes List) The list of jobs. (see [below for nested schema](#nestedatt--elements)) + + +### Nested Schema for `elements` + +Read-Only: + +- `disabled` (Boolean) Whether the job is disabled or not. +- `id` (String) The identifier of the job. +- `spec` (Attributes) The specification of the job. (see [below for nested schema](#nestedatt--elements--spec)) + + +### Nested Schema for `elements.spec` + +Read-Only: + +- `concurrent` (Boolean) Whether to allow concurrent executions for this job or not. +- `description` (String) A textual description of the job. +- `environment` (Map of String) A set of environment variables mapping names to values to be defined during job execution. +- `identities` (Set of String) Set of eventline identities names to inject during job execution. +- `name` (String) The name of the job. +- `parameters` (Attributes List) (see [below for nested schema](#nestedatt--elements--spec--parameters)) +- `retention` (Number) The number of days after which past executions of this job will be deleted. This value override the global job_retention setting. +- `runner` (Attributes) The specification of the runner used to execute the job. (see [below for nested schema](#nestedatt--elements--spec--runner)) +- `steps` (Attributes List) A list of steps which will be executed sequentially. (see [below for nested schema](#nestedatt--elements--spec--steps)) +- `trigger` (Attributes) The specification of a trigger indicating when to execute the job. (see [below for nested schema](#nestedatt--elements--spec--trigger)) + + +### Nested Schema for `elements.spec.parameters` + +Read-Only: + +- `description` (String) A textual description of the parameter. +- `environment` (String) The name of an environment variable to be used to inject the value of this parameter during execution. +- `name` (String) The name of the parameter. +- `type` (String) The type of the parameter. The following types are supported: + - number: Either an integer or an IEEE 754 double precision floating point value. + - integer: An integer. + - string: A character string. + - boolean: A boolean. +- `values` (List of String) For parameters of type string, the list of valid values. + + + +### Nested Schema for `elements.spec.runner` + +Read-Only: + +- `identity` (String) The name of an identity to use for runners which require authentication. For example the ssh runner needs an identity to initiate an ssh connection. +- `name` (String) The name of the runner. + + + +### Nested Schema for `elements.spec.steps` + +Read-Only: + +- `code` (String) The fragment of code to execute for this step. +- `command` (Attributes) The command to execute for this step. (see [below for nested schema](#nestedatt--elements--spec--steps--command)) +- `label` (String) A short description of the step which will be displayed on the web interface. +- `script` (Attributes) The command to execute for this step. (see [below for nested schema](#nestedatt--elements--spec--steps--script)) + + +### Nested Schema for `elements.spec.steps.script` + +Read-Only: + +- `arguments` (List of String) The list of arguments to pass to the command. +- `name` (String) The name of the command. + + + +### Nested Schema for `elements.spec.steps.script` + +Read-Only: + +- `arguments` (List of String) The list of arguments to pass to the command. +- `content` (String) The script file contents. +- `path` (String) The path of the script file relative to the job file. + + + + +### Nested Schema for `elements.spec.trigger` + +Read-Only: + +- `event` (String) The event to react to formatted as /. +- `identity` (String) The name of an identity to use for events which require authentication. For example the github/push event needs an identity to create the GitHub hook used to listen to push events. diff --git a/internal/provider/jobs_data_source.go b/internal/provider/jobs_data_source.go new file mode 100644 index 0000000..d3c3dcb --- /dev/null +++ b/internal/provider/jobs_data_source.go @@ -0,0 +1,332 @@ +package provider + +import ( + "context" + "fmt" + + "git.adyxax.org/adyxax/terraform-provider-eventline/external/evcli" + "github.com/exograd/go-daemon/ksuid" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type JobsDataSource struct { + client *evcli.Client +} + +var _ datasource.DataSource = &JobsDataSource{} // Ensure provider defined types fully satisfy framework interfaces +func NewJobsDataSource() datasource.DataSource { + return &JobsDataSource{} +} + +type JobsDataSourceModel struct { + Elements []JobDataSourceModel `tfsdk:"elements"` + ProjectId types.String `tfsdk:"project_id"` +} +type JobDataSourceModel struct { + Disabled types.Bool `tfsdk:"disabled"` + Id types.String `tfsdk:"id"` + Spec JobSpecDataSourceModel `tfsdk:"spec"` +} +type JobSpecDataSourceModel struct { + Concurrent types.Bool `tfsdk:"concurrent"` + Description types.String `tfsdk:"description"` + Environment types.Map `tfsdk:"environment"` + Identities types.Set `tfsdk:"identities"` + Name types.String `tfsdk:"name"` + Parameters []ParameterDataSourceModel `tfsdk:"parameters"` + Retention types.Int64 `tfsdk:"retention"` + Runner *RunnerDataSourceModel `tfsdk:"runner"` + Trigger *TriggerDataSourceModel `tfsdk:"trigger"` + Steps []StepDataSourceModel `tfsdk:"steps"` +} +type ParameterDataSourceModel struct { + Description types.String `tfsdk:"description"` + Environment types.String `tfsdk:"environment"` + Name types.String `tfsdk:"name"` + Type types.String `tfsdk:"type"` + Values types.List `tfsdk:"values"` +} +type RunnerDataSourceModel struct { + Name types.String `tfsdk:"name"` + Identity types.String `tfsdk:"identity"` +} +type StepDataSourceModel struct { + Code types.String `tfsdk:"code"` + Command *StepCommandDataSourceModel `tfsdk:"command"` + Label types.String `tfsdk:"label"` + Script *StepScriptDataSourceModel `tfsdk:"script"` +} +type StepCommandDataSourceModel struct { + Arguments types.List `tfsdk:"arguments"` + Name types.String `tfsdk:"name"` +} +type StepScriptDataSourceModel struct { + Arguments types.List `tfsdk:"arguments"` + Content types.String `tfsdk:"content"` + Path types.String `tfsdk:"path"` +} +type TriggerDataSourceModel struct { + Event types.String `tfsdk:"event"` + Identity types.String `tfsdk:"identity"` +} + +func (d *JobsDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_jobs" +} + +func (d *JobsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "elements": schema.ListNestedAttribute{ + Computed: true, + MarkdownDescription: "The list of jobs.", + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "disabled": schema.BoolAttribute{ + Computed: true, + MarkdownDescription: "Whether the job is disabled or not.", + }, + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The identifier of the job.", + }, + "spec": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "concurrent": schema.BoolAttribute{ + Computed: true, + MarkdownDescription: "Whether to allow concurrent executions for this job or not.", + }, + "description": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "A textual description of the job.", + }, + "environment": schema.MapAttribute{ + ElementType: types.StringType, + Computed: true, + MarkdownDescription: "A set of environment variables mapping names to values to be defined during job execution.", + }, + "identities": schema.SetAttribute{ + Computed: true, + ElementType: types.StringType, + MarkdownDescription: "Set of eventline identities names to inject during job execution.", + }, + "name": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The name of the job.", + }, + "parameters": schema.ListNestedAttribute{ + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "description": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "A textual description of the parameter.", + }, + "environment": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The name of an environment variable to be used to inject the value of this parameter during execution.", + }, + "name": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The name of the parameter.", + }, + "type": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The type of the parameter. The following types are supported:\n - number: Either an integer or an IEEE 754 double precision floating point value.\n - integer: An integer.\n - string: A character string.\n - boolean: A boolean.", + }, + "values": schema.ListAttribute{ + Computed: true, + ElementType: types.StringType, + MarkdownDescription: "For parameters of type string, the list of valid values.", + }, + }, + }, + }, + "retention": schema.Int64Attribute{ + Computed: true, + MarkdownDescription: "The number of days after which past executions of this job will be deleted. This value override the global job_retention setting.", + }, + "runner": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The name of the runner.", + }, + "identity": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The name of an identity to use for runners which require authentication. For example the ssh runner needs an identity to initiate an ssh connection.", + }, + }, + Computed: true, + MarkdownDescription: "The specification of the runner used to execute the job.", + }, + "trigger": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "event": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The event to react to formatted as /.", + }, + "identity": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The name of an identity to use for events which require authentication. For example the github/push event needs an identity to create the GitHub hook used to listen to push events.", + }, + }, + Computed: true, + MarkdownDescription: "The specification of a trigger indicating when to execute the job.", + }, + "steps": schema.ListNestedAttribute{ + Computed: true, + MarkdownDescription: "A list of steps which will be executed sequentially.", + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "code": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The fragment of code to execute for this step.", + }, + "command": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "arguments": schema.ListAttribute{ + Computed: true, + ElementType: types.StringType, + MarkdownDescription: "The list of arguments to pass to the command.", + }, + "name": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The name of the command.", + }, + }, + Computed: true, + MarkdownDescription: "The command to execute for this step.", + }, + "label": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "A short description of the step which will be displayed on the web interface.", + }, + "script": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "arguments": schema.ListAttribute{ + Computed: true, + ElementType: types.StringType, + MarkdownDescription: "The list of arguments to pass to the command.", + }, + "content": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The script file contents.", + }, + "path": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The path of the script file relative to the job file.", + }, + }, + Computed: true, + MarkdownDescription: "The command to execute for this step.", + }, + }, + }, + }, + }, + Computed: true, + MarkdownDescription: "The specification of the job.", + }, + }, + }, + }, + "project_id": schema.StringAttribute{ + MarkdownDescription: "The identifier of the project the jobs are part of.", + Required: true, + }, + }, + MarkdownDescription: "Use this data source to retrieve information about existing eventline jobs.", + } +} + +func (d *JobsDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + d.client, _ = req.ProviderData.(*evcli.Client) +} + +func (d *JobsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data JobsDataSourceModel + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + var id ksuid.KSUID + if err := id.Parse(data.ProjectId.ValueString()); err != nil { + resp.Diagnostics.AddError("KsuidParse", fmt.Sprintf("Unable to parse project id, got error: %s", err)) + return + } + d.client.ProjectId = &id + jobs, err := d.client.FetchJobs() + if err != nil { + resp.Diagnostics.AddError("FetchJobs", fmt.Sprintf("Unable to fetch jobs, got error: %s", err)) + return + } + jobList := make([]JobDataSourceModel, len(jobs)) + for i, job := range jobs { + environment, _ := types.MapValueFrom(ctx, types.StringType, job.Spec.Environment) + identities, _ := types.SetValueFrom(ctx, types.StringType, job.Spec.Identities) + jobList[i] = JobDataSourceModel{ + Disabled: types.BoolValue(job.Disabled), + Id: types.StringValue(job.Id.String()), + Spec: JobSpecDataSourceModel{ + Concurrent: types.BoolValue(job.Spec.Concurrent), + Description: types.StringValue(job.Spec.Description), + Environment: environment, + Identities: identities, + Name: types.StringValue(job.Spec.Name), + Retention: types.Int64Value(int64(job.Spec.Retention)), + }, + } + jobParameters := make([]ParameterDataSourceModel, len(job.Spec.Parameters)) + for j, parameter := range job.Spec.Parameters { + values, _ := types.ListValueFrom(ctx, types.StringType, parameter.Values) + jobParameters[j] = ParameterDataSourceModel{ + Description: types.StringValue(parameter.Description), + Environment: types.StringValue(parameter.Environment), + Name: types.StringValue(parameter.Name), + Type: types.StringValue(string(parameter.Type)), + Values: values, + } + } + jobList[i].Spec.Parameters = jobParameters + if job.Spec.Runner != nil { + jobList[i].Spec.Runner = &RunnerDataSourceModel{ + Name: types.StringValue(job.Spec.Runner.Name), + Identity: types.StringValue(job.Spec.Runner.Identity), + } + } + jobSteps := make([]StepDataSourceModel, len(job.Spec.Steps)) + for j, step := range job.Spec.Steps { + jobSteps[j] = StepDataSourceModel{ + Code: types.StringValue(step.Code), + Label: types.StringValue(step.Label), + } + if step.Command != nil { + arguments, _ := types.ListValueFrom(ctx, types.StringType, step.Command.Arguments) + jobSteps[j].Command = &StepCommandDataSourceModel{ + Arguments: arguments, + Name: types.StringValue(step.Command.Name), + } + } + if step.Script != nil { + arguments, _ := types.ListValueFrom(ctx, types.StringType, step.Script.Arguments) + jobSteps[j].Script = &StepScriptDataSourceModel{ + Arguments: arguments, + Content: types.StringValue(step.Script.Content), + Path: types.StringValue(step.Script.Path), + } + } + } + jobList[i].Spec.Steps = jobSteps + if job.Spec.Trigger != nil { + jobList[i].Spec.Trigger = &TriggerDataSourceModel{ + Event: types.StringValue(job.Spec.Trigger.Event.String()), + Identity: types.StringValue(job.Spec.Trigger.Identity), + } + } + } + data.Elements = jobList + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index a3fe206..6f3bb65 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -76,6 +76,7 @@ func (p *Provider) Resources(ctx context.Context) []func() resource.Resource { func (p *Provider) DataSources(ctx context.Context) []func() datasource.DataSource { return []func() datasource.DataSource{ + NewJobsDataSource, NewProjectsDataSource, } } -- cgit v1.2.3