-
Notifications
You must be signed in to change notification settings - Fork 3
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
Showing
10 changed files
with
488 additions
and
19 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
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,23 @@ | ||
package docker | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/resource" | ||
"go.clever-cloud.dev/client" | ||
) | ||
|
||
type ResourceDocker struct { | ||
cc *client.Client | ||
org string | ||
} | ||
|
||
func NewResourceDocker() func() resource.Resource { | ||
return func() resource.Resource { | ||
return &ResourceDocker{} | ||
} | ||
} | ||
|
||
func (r *ResourceDocker) Metadata(ctx context.Context, req resource.MetadataRequest, res *resource.MetadataResponse) { | ||
res.TypeName = req.ProviderTypeName + "_docker" | ||
} |
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,3 @@ | ||
Manage [Docker](https://) applications. | ||
|
||
See [Docker product](https://www.clever-cloud.com/doc/getting-started/by-language/docker/) specification. |
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,198 @@ | ||
package docker | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/path" | ||
"github.com/hashicorp/terraform-plugin-framework/resource" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
"github.com/hashicorp/terraform-plugin-log/tflog" | ||
"go.clever-cloud.com/terraform-provider/pkg" | ||
"go.clever-cloud.com/terraform-provider/pkg/application" | ||
"go.clever-cloud.com/terraform-provider/pkg/provider" | ||
"go.clever-cloud.com/terraform-provider/pkg/tmp" | ||
) | ||
|
||
// Weird behaviour, but TF can ask for a Resource without having configured a Provider (maybe for Meta and Schema) | ||
// So we need to handle the case there is no ProviderData | ||
func (r *ResourceDocker) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { | ||
tflog.Debug(ctx, "ResourceDocker.Configure()") | ||
|
||
// Prevent panic if the provider has not been configured. | ||
if req.ProviderData == nil { | ||
return | ||
} | ||
|
||
provider, ok := req.ProviderData.(provider.Provider) | ||
if ok { | ||
r.cc = provider.Client() | ||
r.org = provider.Organization() | ||
} | ||
|
||
tflog.Debug(ctx, "AFTER CONFIGURED", map[string]interface{}{"cc": r.cc == nil, "org": r.org}) | ||
} | ||
|
||
// Create a new resource | ||
func (r *ResourceDocker) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { | ||
plan := Docker{} | ||
|
||
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
instance := application.LookupInstance(ctx, r.cc, "docker", "Docker", resp.Diagnostics) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
vhosts := []string{} | ||
resp.Diagnostics.Append(plan.AdditionalVHosts.ElementsAs(ctx, &vhosts, false)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
environment := plan.toEnv(ctx, resp.Diagnostics) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
createAppReq := application.CreateReq{ | ||
Client: r.cc, | ||
Organization: r.org, | ||
Application: tmp.CreateAppRequest{ | ||
Name: plan.Name.ValueString(), | ||
Deploy: "git", | ||
Description: plan.Description.ValueString(), | ||
InstanceType: instance.Type, | ||
InstanceVariant: instance.Variant.ID, | ||
InstanceVersion: instance.Version, | ||
BuildFlavor: plan.BuildFlavor.ValueString(), | ||
MinFlavor: plan.SmallestFlavor.ValueString(), | ||
MaxFlavor: plan.BiggestFlavor.ValueString(), | ||
MinInstances: plan.MinInstanceCount.ValueInt64(), | ||
MaxInstances: plan.MaxInstanceCount.ValueInt64(), | ||
StickySessions: plan.StickySessions.ValueBool(), | ||
ForceHttps: application.FromForceHTTPS(plan.RedirectHTTPS.ValueBool()), | ||
Zone: plan.Region.ValueString(), | ||
CancelOnPush: false, | ||
}, | ||
Environment: environment, | ||
VHosts: vhosts, | ||
Deployment: plan.toDeployment(), | ||
} | ||
|
||
createAppRes, diags := application.CreateApp(ctx, createAppReq) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
tflog.Debug(ctx, "BUILD FLAVOR RES"+createAppRes.Application.BuildFlavor.Name, map[string]interface{}{}) | ||
plan.ID = pkg.FromStr(createAppRes.Application.ID) | ||
plan.DeployURL = pkg.FromStr(createAppRes.Application.DeployURL) | ||
plan.VHost = pkg.FromStr(createAppRes.Application.Vhosts[0].Fqdn) | ||
|
||
resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
} | ||
|
||
// Read resource information | ||
func (r *ResourceDocker) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { | ||
var state Docker | ||
|
||
resp.Diagnostics.Append(req.State.Get(ctx, &state)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
appPHP, diags := application.ReadApp(ctx, r.cc, r.org, state.ID.ValueString()) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
if appPHP.AppIsDeleted { | ||
resp.State.RemoveResource(ctx) | ||
return | ||
} | ||
|
||
state.Name = pkg.FromStr(appPHP.App.Name) | ||
state.Description = pkg.FromStr(appPHP.App.Description) | ||
state.MinInstanceCount = pkg.FromI(int64(appPHP.App.Instance.MinInstances)) | ||
state.MaxInstanceCount = pkg.FromI(int64(appPHP.App.Instance.MaxInstances)) | ||
state.SmallestFlavor = pkg.FromStr(appPHP.App.Instance.MinFlavor.Name) | ||
state.BiggestFlavor = pkg.FromStr(appPHP.App.Instance.MaxFlavor.Name) | ||
state.Region = pkg.FromStr(appPHP.App.Zone) | ||
state.DeployURL = pkg.FromStr(appPHP.App.DeployURL) | ||
|
||
if appPHP.App.SeparateBuild { | ||
state.BuildFlavor = pkg.FromStr(appPHP.App.BuildFlavor.Name) | ||
} else { | ||
state.BuildFlavor = types.StringNull() | ||
} | ||
|
||
vhosts := pkg.Map(appPHP.App.Vhosts, func(vhost tmp.Vhost) string { | ||
return vhost.Fqdn | ||
}) | ||
hasDefaultVHost := pkg.HasSome(vhosts, func(vhost string) bool { | ||
return pkg.VhostCleverAppsRegExp.MatchString(vhost) | ||
}) | ||
if hasDefaultVHost { | ||
cleverapps := *pkg.First(vhosts, func(vhost string) bool { | ||
return pkg.VhostCleverAppsRegExp.MatchString(vhost) | ||
}) | ||
state.VHost = pkg.FromStr(cleverapps) | ||
} else { | ||
state.VHost = types.StringNull() | ||
} | ||
|
||
vhostsWithoutDefault := pkg.Filter(vhosts, func(vhost string) bool { | ||
ok := pkg.VhostCleverAppsRegExp.MatchString(vhost) | ||
return !ok | ||
}) | ||
if len(vhostsWithoutDefault) > 0 { | ||
state.AdditionalVHosts = pkg.FromListString(vhostsWithoutDefault) | ||
} else { | ||
state.AdditionalVHosts = types.ListNull(types.StringType) | ||
} | ||
|
||
resp.Diagnostics.Append(resp.State.Set(ctx, state)...) | ||
} | ||
|
||
// Update resource | ||
func (r *ResourceDocker) Update(ctx context.Context, req resource.UpdateRequest, res *resource.UpdateResponse) { | ||
// TODO | ||
} | ||
|
||
// Delete resource | ||
func (r *ResourceDocker) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { | ||
var state Docker | ||
|
||
resp.Diagnostics.Append(req.State.Get(ctx, &state)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
tflog.Debug(ctx, "DOCKER DELETE", map[string]interface{}{"state": state}) | ||
|
||
res := tmp.DeleteApp(ctx, r.cc, r.org, state.ID.ValueString()) | ||
if res.IsNotFoundError() { | ||
resp.State.RemoveResource(ctx) | ||
return | ||
} | ||
if res.HasError() { | ||
resp.Diagnostics.AddError("failed to delete app", res.Error().Error()) | ||
return | ||
} | ||
|
||
resp.State.RemoveResource(ctx) | ||
} | ||
|
||
// Import resource | ||
func (r *ResourceDocker) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { | ||
// Save the import identifier in the id attribute | ||
// and call Read() to fill fields | ||
attr := path.Root("id") | ||
resource.ImportStatePassthroughID(ctx, attr, req, resp) | ||
} |
Oops, something went wrong.