-
Notifications
You must be signed in to change notification settings - Fork 67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: machine proxy resource and data source #809
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "octopusdeploy_machine_proxies Data Source - terraform-provider-octopusdeploy" | ||
subcategory: "" | ||
description: |- | ||
Provides information about existing Octopus Deploy machine proxies. | ||
--- | ||
|
||
# octopusdeploy_machine_proxies (Data Source) | ||
|
||
Provides information about existing Octopus Deploy machine proxies. | ||
|
||
|
||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Optional | ||
|
||
- `ids` (List of String) A filter to search by a list of IDs. | ||
- `partial_name` (String) A filter to search by a partial name. | ||
- `skip` (Number) A filter to specify the number of items to skip in the response. | ||
- `space_id` (String) A Space ID to filter by. Will revert what is specified on the provider if not set | ||
- `take` (Number) A filter to specify the number of items to take (or return) in the response. | ||
|
||
### Read-Only | ||
|
||
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified. | ||
- `machine_proxies` (Attributes List) A list of machine proxies that match the filter(s). (see [below for nested schema](#nestedatt--machine_proxies)) | ||
|
||
<a id="nestedatt--machine_proxies"></a> | ||
### Nested Schema for `machine_proxies` | ||
|
||
Read-Only: | ||
|
||
- `host` (String) DNS hostname of the proxy server | ||
- `id` (String) | ||
- `name` (String) | ||
- `port` (Number) The port number for the proxy server. | ||
- `space_id` (String) The space ID associated with this machine proxy. | ||
- `username` (String) Username for the proxy server | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "octopusdeploy_machine_proxy Resource - terraform-provider-octopusdeploy" | ||
subcategory: "" | ||
description: |- | ||
This resource manages machine proxies in Octopus Deploy. | ||
--- | ||
|
||
# octopusdeploy_machine_proxy (Resource) | ||
|
||
This resource manages machine proxies in Octopus Deploy. | ||
|
||
|
||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `host` (String) DNS hostname of the proxy server | ||
- `name` (String) The name of this resource. | ||
- `password` (String, Sensitive) Password of the proxy server | ||
- `username` (String) Username of the proxy server | ||
|
||
### Optional | ||
|
||
- `port` (Number) The port number for the proxy server. | ||
- `space_id` (String) The space ID associated with this machine_proxy. | ||
|
||
### Read-Only | ||
|
||
- `id` (String) The unique ID for this resource. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package octopusdeploy_framework | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/proxies" | ||
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas" | ||
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util" | ||
"github.com/hashicorp/terraform-plugin-framework/datasource" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
"time" | ||
) | ||
|
||
var _ datasource.DataSource = &machineProxyDataSource{} | ||
|
||
type machineProxyDataSource struct { | ||
*Config | ||
} | ||
|
||
func NewMachineProxyDataSource() datasource.DataSource { | ||
return &machineProxyDataSource{} | ||
} | ||
|
||
func (p *machineProxyDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { | ||
resp.TypeName = util.GetTypeName(schemas.MachineProxyDataSourceName) | ||
} | ||
|
||
func (p *machineProxyDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { | ||
resp.Schema = schemas.MachineProxySchema{}.GetDatasourceSchema() | ||
} | ||
|
||
func (p *machineProxyDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { | ||
p.Config = DataSourceConfiguration(req, resp) | ||
} | ||
|
||
func (p *machineProxyDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { | ||
var data schemas.MachineProxyDataSourceModel | ||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
query := proxies.ProxiesQuery{ | ||
PartialName: data.PartialName.ValueString(), | ||
Skip: int(data.Skip.ValueInt64()), | ||
Take: int(data.Take.ValueInt64()), | ||
} | ||
|
||
util.DatasourceReading(ctx, "machine proxies", query) | ||
|
||
if !data.IDs.IsNull() { | ||
var ids []string | ||
resp.Diagnostics.Append(data.IDs.ElementsAs(ctx, &ids, false)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
query.IDs = ids | ||
} | ||
|
||
spaceID := data.SpaceID.ValueString() | ||
|
||
proxiesData, err := proxies.Get(p.Client, spaceID, query) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Unable to query proxies", err.Error()) | ||
return | ||
} | ||
|
||
util.DatasourceResultCount(ctx, "proxies", len(proxiesData.Items)) | ||
|
||
data.Proxies = make([]schemas.ProxyDatasourceModel, 0, len(proxiesData.Items)) | ||
for _, proxy := range proxiesData.Items { | ||
proxyModel := mapMachineProxyRequestToModel(proxy, &schemas.MachineProxyResourceModel{}) | ||
data.Proxies = append(data.Proxies, schemas.ProxyDatasourceModel{ | ||
ID: proxyModel.ID, | ||
SpaceID: proxyModel.SpaceID, | ||
Name: proxyModel.Name, | ||
Host: proxyModel.Host, | ||
Username: proxyModel.Username, | ||
Port: proxyModel.Port, | ||
}) | ||
} | ||
|
||
data.ID = types.StringValue(fmt.Sprintf("Proxies-%s", time.Now().UTC().String())) | ||
|
||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package octopusdeploy_framework | ||
|
||
import ( | ||
"context" | ||
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core" | ||
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/proxies" | ||
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors" | ||
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas" | ||
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util" | ||
"github.com/hashicorp/terraform-plugin-framework/resource" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
) | ||
|
||
var _ resource.Resource = &machineProxyResource{} | ||
|
||
type machineProxyResource struct { | ||
*Config | ||
} | ||
|
||
func NewMachineProxyResource() resource.Resource { | ||
return &machineProxyResource{} | ||
} | ||
|
||
func (r *machineProxyResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { | ||
resp.TypeName = util.GetTypeName(schemas.MachineProxyResourceName) | ||
} | ||
|
||
func (r *machineProxyResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { | ||
resp.Schema = schemas.MachineProxySchema{}.GetResourceSchema() | ||
} | ||
|
||
func (r *machineProxyResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { | ||
r.Config = ResourceConfiguration(req, resp) | ||
} | ||
|
||
func (r *machineProxyResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { | ||
var plan schemas.MachineProxyResourceModel | ||
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
machineProxy := mapMachineProxyModelToRequest(&plan) | ||
createdProxy, err := proxies.Add(r.Client, machineProxy) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Error creating machine proxy", err.Error()) | ||
return | ||
} | ||
|
||
proxyModel := mapMachineProxyRequestToModel(createdProxy, &plan) | ||
|
||
diags := resp.State.Set(ctx, proxyModel) | ||
resp.Diagnostics.Append(diags...) | ||
} | ||
|
||
func (r *machineProxyResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { | ||
var state schemas.MachineProxyResourceModel | ||
diags := req.State.Get(ctx, &state) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
machineProxy, err := proxies.GetByID(r.Client, state.SpaceID.ValueString(), state.ID.ValueString()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm sure it's handled, but just for my clarity: if the user doesn't provide a SpaceId on the Datasource, will this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, that happens inside the Go client, if the space ID is "" (go will not let it be nil) we will use the space provided on the provider, if one is not provided by the provider it will use default space, if you don't have a default space set it will error gracefully. |
||
if err != nil { | ||
if err := errors.ProcessApiErrorV2(ctx, resp, state, err, "machine proxy"); err != nil { | ||
resp.Diagnostics.AddError("Error reading machine proxy", err.Error()) | ||
} | ||
return | ||
} | ||
|
||
proxyModel := mapMachineProxyRequestToModel(machineProxy, &state) | ||
|
||
resp.Diagnostics.Append(resp.State.Set(ctx, proxyModel)...) | ||
} | ||
|
||
func (r *machineProxyResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { | ||
var plan schemas.MachineProxyResourceModel | ||
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
existingProxy, err := proxies.GetByID(r.Client, plan.SpaceID.ValueString(), plan.ID.ValueString()) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Error retrieving machine proxy", err.Error()) | ||
return | ||
} | ||
|
||
updatedProxy := mapMachineProxyModelToRequest(&plan) | ||
updatedProxy.ID = existingProxy.ID | ||
updatedProxy.Links = existingProxy.Links | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Eww :) do we have to? I assume so, but would love if TFP didn't need to concern itself with this detail. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same. At least its not exposed to user. |
||
|
||
updatedProxy, err = proxies.Update(r.Client, updatedProxy) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Error updating machine proxy", err.Error()) | ||
return | ||
} | ||
|
||
proxyModel := mapMachineProxyRequestToModel(updatedProxy, &plan) | ||
|
||
diags := resp.State.Set(ctx, proxyModel) | ||
resp.Diagnostics.Append(diags...) | ||
} | ||
|
||
func (r *machineProxyResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { | ||
var state schemas.MachineProxyResourceModel | ||
resp.Diagnostics.Append(req.State.Get(ctx, &state)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
err := proxies.DeleteByID(r.Client, state.SpaceID.ValueString(), state.ID.ValueString()) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Error deleting machine proxy", err.Error()) | ||
return | ||
} | ||
|
||
resp.State.RemoveResource(ctx) | ||
} | ||
|
||
func mapMachineProxyModelToRequest(model *schemas.MachineProxyResourceModel) *proxies.Proxy { | ||
password := core.NewSensitiveValue(model.Password.ValueString()) | ||
proxy := proxies.NewProxy(model.Name.ValueString(), model.Host.ValueString(), model.Username.ValueString(), password) | ||
proxy.SpaceID = model.SpaceID.ValueString() | ||
portNumber := model.Port.ValueInt32() | ||
proxy.Port = int(portNumber) | ||
return proxy | ||
} | ||
|
||
func mapMachineProxyRequestToModel(proxy *proxies.Proxy, state *schemas.MachineProxyResourceModel) *schemas.MachineProxyResourceModel { | ||
proxyModel := &schemas.MachineProxyResourceModel{ | ||
SpaceID: types.StringValue(proxy.SpaceID), | ||
Name: types.StringValue(proxy.Name), | ||
Host: types.StringValue(proxy.Host), | ||
Username: types.StringValue(proxy.Username), | ||
Password: types.StringValue(state.Password.ValueString()), | ||
Port: types.Int32Value(int32(proxy.Port)), | ||
} | ||
proxyModel.ID = types.StringValue(proxy.ID) | ||
|
||
return proxyModel | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this do for TF state if, for example, the datasource was directly set as the value of an output? Do we do this form of ID'ing in other datasources?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is how terraform recommends handling state for data sources, we do it in all our data sources. This ID is internal for terraform, it uses it to understand and track when the data source changes.