Skip to content

Commit

Permalink
release v0.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Clivern committed Apr 7, 2024
1 parent f71e5f0 commit db1749d
Show file tree
Hide file tree
Showing 11 changed files with 1,073 additions and 34 deletions.
95 changes: 91 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<p align="center">
<img alt="Lynx Logo" src="https://www.vectorlogo.zone/logos/hashicorp/hashicorp-icon.svg" width="180" />
<h3 align="center">Lynx Terraform Provider</h3>
<h3 align="center"></h3>
<p align="center">
<a href="https://github.com/Clivern/terraform-provider-lynx/actions/workflows/test.yml">
<img src="https://github.com/Clivern/terraform-provider-lynx/actions/workflows/test.yml/badge.svg"/>
</a>
<a href="https://github.com/clivern/terraform-provider-lynx/releases">
<img src="https://img.shields.io/badge/Version-0.1.0-1abc9c.svg">
<img src="https://img.shields.io/badge/Version-0.2.0-1abc9c.svg">
</a>
<a href="https://github.com/clivern/terraform-provider-lynx/blob/master/LICENSE">
<img src="https://img.shields.io/badge/LICENSE-MIT-orange.svg">
Expand All @@ -18,8 +18,95 @@

### Usage

```zsh
$
Here is an example to setup team, team users, project, project environment and a snapshot.

```hcl
terraform {
required_providers {
lynx = {
source = "Clivern/lynx"
version = "0.2.0"
}
}
}
provider "lynx" {
api_url = "http://localhost:4000/api/v1"
api_key = "~api key here~"
}
resource "lynx_user" "stella" {
name = "Stella"
email = "[email protected]"
role = "regular"
password = "~password-here~"
}
resource "lynx_user" "skylar" {
name = "Skylar"
email = "[email protected]"
role = "regular"
password = "~password-here~"
}
resource "lynx_user" "erika" {
name = "Erika"
email = "[email protected]"
role = "regular"
password = "~password-here~"
}
resource "lynx_user" "adriana" {
name = "Adriana"
email = "[email protected]"
role = "regular"
password = "~password-here~"
}
resource "lynx_team" "monitoring" {
name = "Monitoring"
slug = "monitoring"
description = "System Monitoring Team"
members = [
lynx_user.stella.id,
lynx_user.skylar.id,
lynx_user.erika.id,
lynx_user.adriana.id
]
}
resource "lynx_project" "grafana" {
name = "Grafana"
slug = "grafana"
description = "Grafana Project"
team = {
id = lynx_team.monitoring.id
}
}
resource "lynx_environment" "prod" {
name = "Development"
slug = "dev"
username = "~username-here~"
secret = "~secret-here~"
project = {
id = lynx_project.grafana.id
}
}
resource "lynx_snapshot" "my_snapshot" {
title = "Grafana Project Snapshot"
description = "Grafana Project Snapshot"
record_type = "project"
record_id = lynx_project.grafana.id
team = {
id = lynx_team.monitoring.id
}
}
```


Expand Down
3 changes: 0 additions & 3 deletions examples/README.md

This file was deleted.

23 changes: 0 additions & 23 deletions examples/basics/main.tf

This file was deleted.

250 changes: 250 additions & 0 deletions internal/provider/environment_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,253 @@
// license that can be found in the LICENSE file.

package provider

import (
"context"
"fmt"

"github.com/clivern/terraform-provider-lynx/sdk"

"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
)

// Ensure provider defined types fully satisfy framework interfaces.
var _ resource.Resource = &EnvironmentResource{}
var _ resource.ResourceWithImportState = &EnvironmentResource{}

func NewEnvironmentResource() resource.Resource {
return &EnvironmentResource{}
}

// EnvironmentResource defines the resource implementation.
type EnvironmentResource struct {
client *sdk.Client
}

// EnvironmentResourceModel describes the resource data model.
type EnvironmentResourceModel struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Slug types.String `tfsdk:"slug"`
Username types.String `tfsdk:"username"`
Secret types.String `tfsdk:"secret"`
Project *ProjectResourceSmallModel `tfsdk:"project"`
}

// ProjectResourceSmallModel describes the nested project resource data model.
type ProjectResourceSmallModel struct {
ID types.String `tfsdk:"id"`
}

func (r *EnvironmentResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_environment"
}

func (r *EnvironmentResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "Environment resource",
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
MarkdownDescription: "Environment's name",
Required: true,
},
"slug": schema.StringAttribute{
MarkdownDescription: "Environment's slug",
Required: true,
},
"username": schema.StringAttribute{
MarkdownDescription: "Environment's username",
Required: true,
Sensitive: true,
},
"secret": schema.StringAttribute{
MarkdownDescription: "Environment's secret",
Required: true,
Sensitive: true,
},
"project": schema.SingleNestedAttribute{
MarkdownDescription: "Environment's project",
Required: true,
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Required: true,
MarkdownDescription: "Project identifier",
},
},
},
"id": schema.StringAttribute{
Computed: true,
MarkdownDescription: "Environment identifier",
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
},
}
}

func (r *EnvironmentResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*sdk.Client)

if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)

return
}

r.client = client
}

func (r *EnvironmentResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data EnvironmentResourceModel

// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

newEnvironment := sdk.Environment{
Name: data.Name.ValueString(),
Slug: data.Slug.ValueString(),
Username: data.Username.ValueString(),
Secret: data.Secret.ValueString(),
Project: sdk.Project{
ID: data.Project.ID.ValueString(),
},
}

createdEnvironment, err := r.client.CreateEnvironment(newEnvironment)

if err != nil {
resp.Diagnostics.AddError(
"Client Error",
fmt.Sprintf("Unable to create environment, got error: %s", err.Error()),
)
return
}

// Set the created environment's ID in the Terraform state
data.ID = types.StringValue(createdEnvironment.ID)
data.Name = types.StringValue(createdEnvironment.Name)
data.Slug = types.StringValue(createdEnvironment.Slug)
data.Username = types.StringValue(createdEnvironment.Username)
data.Secret = types.StringValue(createdEnvironment.Secret)
data.Project.ID = types.StringValue(createdEnvironment.Project.ID)

// Write logs using the tflog package
tflog.Trace(ctx, "created an environment")

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *EnvironmentResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data EnvironmentResourceModel

// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

// Retrieve the environment using the GetEnvironment method
environment, err := r.client.GetEnvironment(data.Project.ID.ValueString(), data.ID.ValueString())

if err != nil {
resp.Diagnostics.AddError(
"Client Error",
fmt.Sprintf("Unable to read environment, got error: %s", err.Error()),
)
return
}

// Update the data model with the retrieved environment information
data.Name = types.StringValue(environment.Name)
data.Slug = types.StringValue(environment.Slug)
data.Username = types.StringValue(environment.Username)
data.Secret = types.StringValue(environment.Secret)

data.Project = &ProjectResourceSmallModel{
ID: types.StringValue(environment.Project.ID),
}

// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *EnvironmentResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data EnvironmentResourceModel

// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

// Update the environment using the UpdateEnvironment method
updatedEnvironment := sdk.Environment{
ID: data.ID.ValueString(),
Name: data.Name.ValueString(),
Slug: data.Slug.ValueString(),
Username: data.Username.ValueString(),
Secret: data.Secret.ValueString(),
Project: sdk.Project{
ID: data.Project.ID.ValueString(),
},
}

_, err := r.client.UpdateEnvironment(updatedEnvironment)

if err != nil {
resp.Diagnostics.AddError(
"Client Error",
fmt.Sprintf("Unable to update environment, got error: %s", err.Error()),
)
return
}
// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *EnvironmentResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data EnvironmentResourceModel

// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

err := r.client.DeleteEnvironment(data.Project.ID.ValueString(), data.ID.ValueString())

if err != nil {
resp.Diagnostics.AddError(
"Client Error",
fmt.Sprintf("Unable to delete environment, got error: %s", err.Error()),
)
return
}
}

func (r *EnvironmentResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}
Loading

0 comments on commit db1749d

Please sign in to comment.