Skip to content

Commit

Permalink
wip: attempt to use generated api client
Browse files Browse the repository at this point in the history
  • Loading branch information
skpratt committed Feb 26, 2024
1 parent 0e99850 commit 93426ae
Show file tree
Hide file tree
Showing 18 changed files with 7,231 additions and 119 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ NEW FEATURES:

BUG FIXES:

* The same API client is now reused across all operations ([[#233](https://github.com/hashicorp/terraform-provider-consul/issues/233)]).
* The same API Client is now reused across all operations ([[#233](https://github.com/hashicorp/terraform-provider-consul/issues/233)]).

## 2.10.0 (September 18, 2020)

Expand Down
51 changes: 44 additions & 7 deletions consul/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import (
"strings"

consulapi "github.com/hashicorp/consul/api"

"github.com/hashicorp/terraform-provider-consul/consul/tools"
multicluster "github.com/hashicorp/terraform-provider-consul/consul/tools/openapi"
)

// Config is configuration defined in the provider block
Expand All @@ -29,11 +32,12 @@ type Config struct {
InsecureHttps bool `mapstructure:"insecure_https"`
Namespace string `mapstructure:"namespace"`

client *consulapi.Client
Client *consulapi.Client
V2Client *multicluster.Client
}

// Client returns a new client for accessing consul.
func (c *Config) Client() (*consulapi.Client, error) {
// Client returns a new Client for accessing consul.
func (c *Config) getApiConfig() (*consulapi.Config, error) {
config := consulapi.DefaultConfig()
if c.Datacenter != "" {
config.Datacenter = c.Datacenter
Expand Down Expand Up @@ -74,7 +78,7 @@ func (c *Config) Client() (*consulapi.Client, error) {
}

// This is a temporary workaround to add the Content-Type header when
// needed until the fix is released in the Consul api client.
// needed until the fix is released in the Consul api Client.
config.HttpClient = &http.Client{
Transport: transport{config.Transport},
}
Expand All @@ -83,7 +87,7 @@ func (c *Config) Client() (*consulapi.Client, error) {
tlsClientConfig, err := consulapi.SetupTLSConfig(&config.TLSConfig)

if err != nil {
return nil, fmt.Errorf("failed to create http client: %s", err)
return nil, fmt.Errorf("failed to create http Client config: %s", err)
}

config.Transport.TLSClientConfig = tlsClientConfig
Expand All @@ -104,19 +108,52 @@ func (c *Config) Client() (*consulapi.Client, error) {
if c.Token != "" {
config.Token = c.Token
}
return config, nil
}

func (c *Config) getClient() (*consulapi.Client, error) {

config, err := c.getApiConfig()
if err != nil {
return nil, err
}

client, err := consulapi.NewClient(config)

log.Printf("[INFO] Consul Client configured with address: '%s', scheme: '%s', datacenter: '%s'"+
log.Printf("[INFO] Consul getClient configured with address: '%s', scheme: '%s', datacenter: '%s'"+
", insecure_https: '%t'", config.Address, config.Scheme, config.Datacenter, config.TLSConfig.InsecureSkipVerify)
if err != nil {
return nil, err
}
return client, nil
}

func (c *Config) getV2Client() (*multicluster.Client, error) {
apiConfig, err := c.getApiConfig()
if err != nil {
return nil, err
}
httpClient, err := tools.NewHttpClient(apiConfig.Transport, apiConfig.TLSConfig)
if err != nil {
return nil, err
}

// build server including scheme and address
serverUrl := apiConfig.Address
if apiConfig.Scheme != "" {
serverUrl = apiConfig.Scheme + "://" + serverUrl
}

v2Client := &multicluster.Client{
Server: serverUrl,
Client: httpClient,
RequestEditors: nil,
}
return v2Client, nil
}

// transport adds the Content-Type header to all requests that might need it
// until we update the API client to a version with
// until we update the API Client to a version with
// https://github.com/hashicorp/consul/pull/10204 at which time we will be able
// to remove this hack.
type transport struct {
Expand Down
2 changes: 1 addition & 1 deletion consul/resource_consul_acl_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ func getPolicyByIdOrName(identifier string, client *consulapi.Client, qOpts *con

policy, _, err = client.ACL().PolicyReadByName(identifier, qOpts)
if policy != nil && err == nil {
// we ignore the initial error that might have happened in client.ACL().PolicyRead()
// we ignore the initial error that might have happened in Client.ACL().PolicyRead()
return policy, false, nil
}

Expand Down
122 changes: 97 additions & 25 deletions consul/resource_consul_config_entry_v2_exported_services.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
package consul

import (
"context"
"encoding/json"
"fmt"
"net/http"

"github.com/hashicorp/consul/api"
pbmulticluster "github.com/hashicorp/consul/proto-public/pbmulticluster/v2"
"github.com/hashicorp/consul/proto-public/pbresource"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"google.golang.org/protobuf/encoding/protojson"

multicluster "github.com/hashicorp/terraform-provider-consul/consul/tools/openapi"
)

func resourceConsulV2ExportedServices() *schema.Resource {
Expand Down Expand Up @@ -94,50 +98,118 @@ func resourceConsulV2ExportedServicesCreate(d *schema.ResourceData, meta interfa
}

func resourceConsulV2ExportedServicesUpdate(d *schema.ResourceData, meta interface{}) error {
client, qOpts, _ := getClient(d, meta)
client, _, _ := getMulticlusterV2Client(d, meta)
name := d.Get("name").(string)
kind := d.Get("kind").(string)
gvk := &api.GVK{
Group: "multicluster",
Version: "v2",
Kind: kind,
}
var consumers []map[string]any
partition := d.Get("partition").(string)
namespace := d.Get("namespace").(string)
var consumers []multicluster.HashicorpConsulMulticlusterV2ExportedServicesConsumer
peerConsumers := d.Get("peer_consumers").([]interface{})
for _, p := range peerConsumers {
consumers = append(consumers, map[string]any{"peer": p})
peerString := p.(string)
consumers = append(consumers, multicluster.HashicorpConsulMulticlusterV2ExportedServicesConsumer{
Peer: &peerString,
})
}
partitionConsumers := d.Get("partition_consumers").([]interface{})
for _, ap := range partitionConsumers {
consumers = append(consumers, map[string]any{"partition": ap})
partitionString := ap.(string)
consumers = append(consumers, multicluster.HashicorpConsulMulticlusterV2ExportedServicesConsumer{
Peer: &partitionString,
})
}
samenessConsumers := d.Get("sameness_group_consumers").([]interface{})
for _, ap := range samenessConsumers {
consumers = append(consumers, map[string]any{"sameness_group": ap})
for _, sg := range samenessConsumers {
sgString := sg.(string)
consumers = append(consumers, multicluster.HashicorpConsulMulticlusterV2ExportedServicesConsumer{
SamenessGroup: &sgString,
})
}
data := map[string]any{"consumers": consumers}
services := d.Get("services").([]interface{})
if len(services) > 0 {
data["services"] = services
var servicesData []string
for _, s := range services {
servicesData = append(servicesData, s.(string))
}
wReq := &api.WriteRequest{
Metadata: nil,
Data: data,
Owner: nil,
}
resp, _, err := client.Resource().Apply(gvk, name, qOpts, wReq)
resp, err := doWriteForKind(client, name, kind, namespace, partition, servicesData, consumers)
if err != nil || resp == nil {
return fmt.Errorf("failed to write exported services config '%s': %v", name, err)
}
d.SetId(resp.ID.Type.Kind + resp.ID.Tenancy.Partition + resp.ID.Tenancy.Namespace + resp.ID.Name)

// Probably should parse the response body to get this instead of just relying on OK response
d.SetId(kind + partition + namespace + name)
sw := newStateWriter(d)
sw.set("name", resp.ID.Name)
sw.set("kind", resp.ID.Type.Kind)
sw.set("partition", resp.ID.Tenancy.Partition)
sw.set("namespace", resp.ID.Tenancy.Namespace)
sw.set("name", name)
sw.set("kind", kind)
sw.set("partition", partition)
sw.set("namespace", namespace)
return resourceConsulV2ExportedServicesRead(d, meta)
}

func doWriteForKind(client *multicluster.Client, name string, kind string, namespace string, partition string, services []string, consumers []multicluster.HashicorpConsulMulticlusterV2ExportedServicesConsumer) (*http.Response, error) {
group := "multicluster"
gv := "v2"
gvk := &multicluster.HashicorpConsulResourceType{
Group: &group,
GroupVersion: &gv,
Kind: &kind,
}
id := &multicluster.HashicorpConsulResourceID{
Name: &name,
Tenancy: &multicluster.HashicorpConsulResourceTenancy{
Namespace: &namespace,
Partition: &partition,
},
Type: gvk,
}

var resp *http.Response
var err error
switch kind {
case "ExportedServices":
wParams := &multicluster.WriteExportedServicesParams{
Peer: nil,
Namespace: &namespace,
Ns: nil, // why is this a thing?
Partition: &partition,
}
body := multicluster.WriteExportedServicesJSONRequestBody{
Data: &multicluster.HashicorpConsulMulticlusterV2ExportedServices{
Consumers: &consumers,
Services: &services,
},
Id: id,
}
resp, err = client.WriteExportedServices(context.Background(), name, wParams, body, nil)
case "NamespaceExportedServices":
wParams := &multicluster.WriteNamespaceExportedServicesParams{
Peer: nil,
Namespace: &namespace,
Ns: nil, // why is this a thing?
Partition: &partition,
}
body := multicluster.WriteNamespaceExportedServicesJSONRequestBody{
Data: &multicluster.HashicorpConsulMulticlusterV2NamespaceExportedServices{
Consumers: &consumers,
},
Id: id,
}
resp, err = client.WriteNamespaceExportedServices(context.Background(), name, wParams, body, nil)
case "PartitionExportedServices":
wParams := &multicluster.WritePartitionExportedServicesParams{
Peer: nil,
Partition: &partition,
}
body := multicluster.WritePartitionExportedServicesJSONRequestBody{
Data: &multicluster.HashicorpConsulMulticlusterV2PartitionExportedServices{
Consumers: &consumers,
},
Id: id,
}
resp, err = client.WritePartitionExportedServices(context.Background(), name, wParams, body)
}
return resp, err
}

func resourceConsulV2ExportedServicesRead(d *schema.ResourceData, meta interface{}) error {
client, qOpts, _ := getClient(d, meta)
name := d.Get("name").(string)
Expand Down
31 changes: 25 additions & 6 deletions consul/resource_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/mitchellh/mapstructure"

multicluster "github.com/hashicorp/terraform-provider-consul/consul/tools/openapi"
)

var (
Expand Down Expand Up @@ -113,7 +115,7 @@ func Provider() terraform.ResourceProvider {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("CONSUL_CAPATH", ""),
Description: "A path to a directory of PEM-encoded certificate authority files to use to check the authenticity of client and server connections. Can also be specified with the `CONSUL_CAPATH` environment variable.",
Description: "A path to a directory of PEM-encoded certificate authority files to use to check the authenticity of Client and server connections. Can also be specified with the `CONSUL_CAPATH` environment variable.",
},

"insecure_https": {
Expand Down Expand Up @@ -271,12 +273,21 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
if err := mapstructure.Decode(configRaw, &config); err != nil {
return nil, err
}
log.Printf("[INFO] Initializing Consul client")
client, err := config.Client()
log.Printf("[INFO] Initializing Consul Clients")

// configure V1 client
client, err := config.getClient()
if err != nil {
return nil, err
}
config.Client = client

// Configure the v2 client
v2Client, err := config.getV2Client()
if err != nil {
return nil, err
}
config.client = client
config.V2Client = v2Client

// Set headers if provided
headers := d.Get("header").([]interface{})
Expand Down Expand Up @@ -331,15 +342,23 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {

func getClient(d *schema.ResourceData, meta interface{}) (*consulapi.Client, *consulapi.QueryOptions, *consulapi.WriteOptions) {
config := meta.(*Config)
client := config.client
client := config.Client

qOpts, wOpts := getOptions(d, config)
return client, qOpts, wOpts
}

func getMulticlusterV2Client(d *schema.ResourceData, meta interface{}) (*multicluster.Client, *consulapi.QueryOptions, *consulapi.WriteOptions) {
config := meta.(*Config)
client := config.V2Client

qOpts, wOpts := getOptions(d, config)
return client, qOpts, wOpts
}

func getOptions(d *schema.ResourceData, meta interface{}) (*consulapi.QueryOptions, *consulapi.WriteOptions) {
config := meta.(*Config)
client := config.client
client := config.Client
var dc, token, namespace, partition string

if v, ok := d.GetOk("datacenter"); ok {
Expand Down
6 changes: 3 additions & 3 deletions consul/resource_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func TestResourceProvider(t *testing.T) {
data "consul_key_prefix" "app" {
path_prefix = "test"
}`,
ExpectError: regexp.MustCompile("server gave HTTP response to HTTPS client"),
ExpectError: regexp.MustCompile("server gave HTTP response to HTTPS Client"),
},
"insecure_https": {
Config: `
Expand All @@ -60,7 +60,7 @@ func TestResourceProvider(t *testing.T) {
data "consul_key_prefix" "app" {
path_prefix = "test"
}`,
ExpectError: regexp.MustCompile("server gave HTTP response to HTTPS client"),
ExpectError: regexp.MustCompile("server gave HTTP response to HTTPS Client"),
},
"insecure_https_err": {
Config: `
Expand Down Expand Up @@ -350,7 +350,7 @@ func waitForService(t *testing.T, address string) (terraform.ResourceProvider, *
config.Token = initialManagementToken
client, err := consulapi.NewClient(config)
if err != nil {
t.Fatalf("failed to instantiate client: %v", err)
t.Fatalf("failed to instantiate Client: %v", err)
}

logger := func(format string, args ...any) {}
Expand Down
Loading

0 comments on commit 93426ae

Please sign in to comment.