Skip to content

Commit

Permalink
Added support of hosts management for server resource (#8)
Browse files Browse the repository at this point in the history
Added support of hosts management for server resource
Added datasource `pritunl_host`
  • Loading branch information
disc authored Oct 21, 2021
1 parent f0a9567 commit 7510b81
Show file tree
Hide file tree
Showing 12 changed files with 438 additions and 35 deletions.
3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
build:
go build -gcflags="all=-N -l" -o ~/.terraform.d/plugins/registry.terraform.io/disc/pritunl/0.0.1/darwin_amd64/terraform-provider-pritunl_v0.0.1 main.go
rm -rf terraform/.terraform/ terraform/.terraform.lock.hcl

test:
@docker rm tf_pritunl_acc_test -f || true
@docker run --name tf_pritunl_acc_test --rm -d --privileged -p 1194:1194/udp -p 1194:1194/tcp -p 80:80/tcp -p 443:443/tcp -p 27017:27017/tcp jippi/pritunl
@docker run --name tf_pritunl_acc_test --hostname pritunl.local --rm -d --privileged -p 1194:1194/udp -p 1194:1194/tcp -p 80:80/tcp -p 443:443/tcp -p 27017:27017/tcp jippi/pritunl

sleep 10

Expand Down
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ terraform {
required_providers {
pritunl = {
source = "disc/pritunl"
version = "0.0.7"
version = "0.1.0"
}
}
}
Expand Down Expand Up @@ -108,6 +108,28 @@ resource "pritunl_server" "example" {
}
}
```
### Multiple hosts per server (Replicated servers feature)
It also supports multiple host server's configuration with host datasource which can be matched by a hostname.
```hcl
data "pritunl_host" "main" {
hostname = "nyc1.vpn.host"
}
data "pritunl_host" "reserve" {
hostname = "nyc3.vpn.host"
}
resource "pritunl_server" "test" {
name = "some-server"
network = "192.168.250.0/24"
port = 15500
host_ids = [
data.pritunl_host.main.id,
data.pritunl_host.reserve.id,
]
}
```

## Importing exist resources

Expand Down
35 changes: 35 additions & 0 deletions examples/provider/multiple-hosts/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
terraform {
required_providers {
pritunl = {
version = "0.1.0"
source = "disc/pritunl"
}
}
}

provider "pritunl" {
url = var.pritunl_url
token = var.pritunl_api_token
secret = var.pritunl_api_secret

insecure = var.pritunl_insecure
}

data "pritunl_host" "main" {
hostname = "nyc1.vpn.host"
}

data "pritunl_host" "reserve" {
hostname = "nyc3.vpn.host"
}

resource "pritunl_server" "test" {
name = "some-server"
network = "192.168.250.0/24"
port = 15500

host_ids = [
data.pritunl_host.main.id,
data.pritunl_host.reserve.id,
]
}
19 changes: 19 additions & 0 deletions examples/provider/multiple-hosts/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
variable "pritunl_url" {
type = string
default = "http://localhost"
}

variable "pritunl_api_token" {
type = string
default = "secret"
}

variable "pritunl_api_secret" {
type = string
default = "secret"
}

variable "pritunl_insecure" {
type = bool
default = false
}
95 changes: 92 additions & 3 deletions internal/pritunl/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,13 @@ type Client interface {
DeleteRouteFromServer(serverId string, route Route) error
UpdateRouteOnServer(serverId string, route Route) error

GetHosts() ([]Host, error)
GetHostsByServer(serverId string) ([]Host, error)
AttachHostToServer(hostId, serverId string) error
DetachHostFromServer(hostId, serverId string) error

StartServer(serverId string) error
StopServer(serverId string) error
//RestartServer(serverId string) error
//DeleteServer(serverId string) error
}

type client struct {
Expand Down Expand Up @@ -491,7 +494,7 @@ func (c client) AttachOrganizationToServer(organizationId, serverId string) erro

body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode != 200 {
return fmt.Errorf("Non-200 response on arrachhing an organization the server\nbody=%s", body)
return fmt.Errorf("Non-200 response on attaching an organization the server\nbody=%s", body)
}

return nil
Expand Down Expand Up @@ -748,6 +751,92 @@ func (c client) DeleteUser(id string, orgId string) error {
return nil
}

func (c client) GetHosts() ([]Host, error) {
url := fmt.Sprintf("/host")
req, err := http.NewRequest("GET", url, nil)

resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("GetHosts: Error on HTTP request: %s", err)
}
defer resp.Body.Close()

body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode != 200 {
return nil, fmt.Errorf("Non-200 response on getting the hosts\nbody=%s", body)
}

var hosts []Host

err = json.Unmarshal(body, &hosts)
if err != nil {
return nil, fmt.Errorf("GetHosts: %s: %+v, body=%s", err, hosts, body)
}

return hosts, nil
}

func (c client) GetHostsByServer(serverId string) ([]Host, error) {
url := fmt.Sprintf("/server/%s/host", serverId)
req, err := http.NewRequest("GET", url, nil)

resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("GetHostsByServer: Error on HTTP request: %s", err)
}
defer resp.Body.Close()

body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode != 200 {
return nil, fmt.Errorf("Non-200 response on getting hosts by the server\nbody=%s", body)
}

var hosts []Host

err = json.Unmarshal(body, &hosts)
if err != nil {
return nil, fmt.Errorf("GetHostsByServer: %s: %+v, body=%s", err, hosts, body)
}

return hosts, nil
}

func (c client) AttachHostToServer(hostId, serverId string) error {
url := fmt.Sprintf("/server/%s/host/%s", serverId, hostId)
req, err := http.NewRequest("PUT", url, nil)

resp, err := c.httpClient.Do(req)
if err != nil {
return fmt.Errorf("AttachHostToServer: Error on HTTP request: %s", err)
}
defer resp.Body.Close()

body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode != 200 {
return fmt.Errorf("Non-200 response on attachhing the host the server\nbody=%s", body)
}

return nil
}

func (c client) DetachHostFromServer(hostId, serverId string) error {
url := fmt.Sprintf("/server/%s/host/%s", serverId, hostId)
req, err := http.NewRequest("DELETE", url, nil)

resp, err := c.httpClient.Do(req)
if err != nil {
return fmt.Errorf("DetachHostFromServer: Error on HTTP request: %s", err)
}
defer resp.Body.Close()

body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode != 200 {
return fmt.Errorf("Non-200 response on detaching the host from the server\nbody=%s", body)
}

return nil
}

func NewClient(baseUrl, apiToken, apiSecret string, insecure bool) Client {
underlyingTransport := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: insecure},
Expand Down
6 changes: 6 additions & 0 deletions internal/pritunl/host.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package pritunl

type Host struct {
ID string `json:"id,omitempty"`
Hostname string `json:"hostname"`
}
62 changes: 62 additions & 0 deletions internal/provider/data_source_host.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package provider

import (
"context"
"errors"
"github.com/disc/terraform-provider-pritunl/internal/pritunl"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceHost() *schema.Resource {
return &schema.Resource{
Description: "Use this data source to get information about the Pritunl hosts.",
ReadContext: dataSourceHostsRead,
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Computed: true,
},
"hostname": {
Description: "Hostname",
Type: schema.TypeString,
Required: true,
},
},
}
}

func dataSourceHostsRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
hostname := d.Get("hostname")
filterFunction := func(host pritunl.Host) bool {
return host.Hostname == hostname
}

host, err := filterHosts(meta, filterFunction)
if err != nil {
return diag.Errorf("could not a find host with a hostname %s. Previous error message: %v", hostname, err)
}

d.SetId(host.ID)
d.Set("hostname", host.Hostname)

return nil
}

func filterHosts(meta interface{}, test func(host pritunl.Host) bool) (pritunl.Host, error) {
apiClient := meta.(pritunl.Client)

hosts, err := apiClient.GetHosts()

if err != nil {
return pritunl.Host{}, err
}

for _, dir := range hosts {
if test(dir) {
return dir, nil
}
}

return pritunl.Host{}, errors.New("could not find a host with specified parameters")
}
36 changes: 36 additions & 0 deletions internal/provider/data_source_host_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package provider

import (
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"regexp"
"testing"
)

func TestDataSourceHost(t *testing.T) {
// pritunl.local sets in Makefile's "test" target
existsHostname := "pritunl.local"
notExistHostname := "not-exist-hostname"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {},
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testdataHostSimpleConfig(existsHostname),
Check: resource.ComposeTestCheckFunc(),
},
{
Config: testdataHostSimpleConfig(notExistHostname),
ExpectError: regexp.MustCompile(fmt.Sprintf("could not a find host with a hostname %s. Previous error message: could not find a host with specified parameters", notExistHostname)),
},
},
})
}

func testdataHostSimpleConfig(name string) string {
return fmt.Sprintf(`
data "pritunl_host" "test" {
hostname = "%[1]s"
}
`, name)
}
3 changes: 3 additions & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ func Provider() *schema.Provider {
"pritunl_server": resourceServer(),
"pritunl_user": resourceUser(),
},
DataSourcesMap: map[string]*schema.Resource{
"pritunl_host": dataSourceHost(),
},
ConfigureContextFunc: providerConfigure,
}
}
Expand Down
Loading

0 comments on commit 7510b81

Please sign in to comment.