Skip to content

Commit

Permalink
[ignore] Moved client files to the client folder and changed the nd_s…
Browse files Browse the repository at this point in the history
…ite import logic
  • Loading branch information
sajagana committed Oct 10, 2024
1 parent 7541283 commit f9ec75d
Show file tree
Hide file tree
Showing 19 changed files with 344 additions and 69 deletions.
1 change: 1 addition & 0 deletions docs/data-sources/site.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ data "nd_site" "example" {
* `inband_epg` (inband_epg) - (String) The In-Band Endpoint Group (EPG) used to connect ND to the site.
* `latitude` (latitude) - (String) The latitude location of the site.
* `longitude` (longitude) - (String) The longitude location of the site.
* `use_proxy` (useProxy) - (Bool) The use proxy of the site, used to route network traffic through a proxy server.
10 changes: 4 additions & 6 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ description: |-

# Nexus Dashboard (ND)

Cisco Nexus Dashboard is a central management console for multiple data center sites and a common platform for hosting Cisco data center operation services, such as Nexus Dashboard Insights and Nexus Dashboard Orchestrator. These services are available for all the data center sites and provide real time analytics, visibility, assurance for network policies and operations, as well as policy orchestration for the data center fabrics, such as Cisco ACI or Cisco NDFC.
Cisco Nexus Dashboard is a central management console for multiple data center sites and a common analytics solution for Cisco data center operations. Nexus Dashboard allows users to manage multiple data center sites and provide real time analytics, visibility, assurance for network policies and operations, as well as policy orchestration for the data center fabrics, such as Cisco ACI or Cisco NDFC or standalone Nexus 9000 switches.

# Cisco ND Provider

The Cisco ND terraform provider is used to interact with resources provided by Cisco Nexus Dashboard. The provider needs to be configured with proper credentials to authenticate with Cisco Nexus Dashboard.

## Authentication

Authentication with user-id and password.
Authentication with username and password.

Example:

Expand All @@ -30,8 +30,6 @@ provider "nd" {
}
```

In this method, it will obtain an authentication token from Cisco Nexus Dashboard and will use that token to authenticate. A limitation with this approach is Nexus Dashboard counts the request to authenticate and threshold it to avoid DOS attack. After too many attempts this authentication method may fail as the threshold will be exceeded. To avoid the above-mentioned problem Cisco Nexus Dashboard supports signature-based authentication.

## Example Usage

```hcl
Expand All @@ -47,7 +45,7 @@ provider "nd" {
username = "admin"
password = "password"
url = "https://my-cisco-nd.com"
insecure = true
insecure = false
}
resource "nd_site" "example" {
Expand Down Expand Up @@ -80,7 +78,7 @@ resource "nd_site" "example" {
- Default: `DefaultAuth`
- Environment variable: `ND_LOGIN_DOMAIN`
- `insecure` (Boolean) Allow insecure HTTPS client.
- Default: `true`
- Default: `false`
- Environment variable: `ND_INSECURE`
- `proxy_creds` (String) Proxy server credentials in the form of `username:password`.
- Environment variable: `ND_PROXY_CREDS`
Expand Down
5 changes: 4 additions & 1 deletion docs/resources/site.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ resource "nd_site" "example" {
login_domain = "local"
latitude = "19.36475238603211"
longitude = "-155.28865502961474"
use_proxy = false
}
```

Expand All @@ -60,14 +61,16 @@ All examples for the Site resource can be found in the [examples](https://github
* `inband_epg` (inband_epg) - (String) The In-Band Endpoint Group (EPG) used to connect ND to the site.
* `latitude` (latitude) - (String) The latitude location of the site.
* `longitude` (longitude) - (String) The longitude location of the site.
* `use_proxy` (useProxy) - (Bool) The use proxy of the site, used to route network traffic through a proxy server.
* Default: false

### Read-Only ###

* `id` (id) - (String) The ID of the site.

## Importing

~> The environment variables `ND_SITE_USERNAME`, `ND_SITE_PASSWORD` and `ND_LOGIN_DOMAIN` must be set in order to import.
~> The details for `username`, `password`, and `login_domain` will be set to `null` when the `nd_site` resource imports an already registered site from the Nexus Dashboard. Modifying the `username`, `password`, and `login_domain` will not update the imported site configuration on the Nexus Dashboard.

An existing Site can be [imported](https://www.terraform.io/docs/import/index.html) into this resource with its name (name), via the following command:

Expand Down
1 change: 1 addition & 0 deletions examples/resources/nd_site/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ resource "nd_site" "example" {
latitude = "19.36475238603211"
longitude = "-155.28865502961474"
login_domain = "local"
use_proxy = true
}
8 changes: 4 additions & 4 deletions internal/provider/auth.go → internal/client/auth.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package provider
package client

import (
"fmt"
Expand Down Expand Up @@ -29,17 +29,17 @@ func (t *Auth) estimateExpireTime() int64 {

func (client *Client) InjectAuthenticationHeader(req *http.Request, path string) (*http.Request, error) {
log.Printf("[DEBUG] Begin Injection")
if client.AuthToken == nil || !client.AuthToken.IsValid() {
if client.authToken == nil || !client.authToken.IsValid() {
err := client.Authenticate()
if err != nil {
return nil, err
}
}

req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", client.AuthToken.Token))
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", client.authToken.Token))
// The header "Cookie" must be set for the Nexus Dashboard 2.3 and later versions.
req.Header.Set("Cookie", fmt.Sprintf("AuthCookie=%s", client.AuthToken.Token))
req.Header.Set("Cookie", fmt.Sprintf("AuthCookie=%s", client.authToken.Token))

return req, nil
}
27 changes: 14 additions & 13 deletions internal/provider/client.go → internal/client/client.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package provider
package client

import (
"bytes"
Expand Down Expand Up @@ -39,10 +39,10 @@ const DefaultBackoffDelayFactor float64 = 3

// Client is the main entry point
type Client struct {
BaseURL *url.URL
baseURL *url.URL
httpClient *http.Client
AuthToken *Auth
Mutex sync.Mutex
authToken *Auth
mutex sync.Mutex
username string
password string
insecure bool
Expand All @@ -68,7 +68,7 @@ func initClient(clientUrl, username, password, proxyUrl, proxyCreds, loginDomain
}

client := &Client{
BaseURL: bUrl,
baseURL: bUrl,
username: username,
httpClient: http.DefaultClient,
password: password,
Expand Down Expand Up @@ -147,7 +147,7 @@ func (c *Client) MakeRestRequest(method string, path string, body *gabs.Containe
validateString.Set("validate", "false")
url.RawQuery = validateString.Encode()
}
fURL := c.BaseURL.ResolveReference(url)
fURL := c.baseURL.ResolveReference(url)

var req *http.Request
if method == "GET" || method == "DELETE" {
Expand Down Expand Up @@ -213,12 +213,12 @@ func (c *Client) Authenticate() error {
return errors.New("Invalid Username or Password")
}

if c.AuthToken == nil {
c.AuthToken = &Auth{}
if c.authToken == nil {
c.authToken = &Auth{}
}

c.AuthToken.Token = token
c.AuthToken.CalculateExpiry(1200) //refreshTime=1200 Sec
c.authToken.Token = token
c.authToken.CalculateExpiry(1200) //refreshTime=1200 Sec

return nil
}
Expand Down Expand Up @@ -312,14 +312,15 @@ func (c *Client) Do(req *http.Request, skipLoggingPayload bool) (*gabs.Container
}
}

func DoRestRequest(ctx context.Context, diags *diag.Diagnostics, client *Client, path, method string, payload *gabs.Container) *gabs.Container {
// func (c *Client) DoRestRequest(ctx context.Context, diags *diag.Diagnostics, client *Client, path, method string, payload *gabs.Container) *gabs.Container {
func (c *Client) DoRestRequest(ctx context.Context, diags *diag.Diagnostics, path, method string, payload *gabs.Container) *gabs.Container {
if !strings.HasPrefix("/", path) {
path = fmt.Sprintf("/%s", path)
}
var restRequest *http.Request
var err error

restRequest, err = client.MakeRestRequest(method, path, payload, true, client.skipLoggingPayload)
restRequest, err = c.MakeRestRequest(method, path, payload, true, c.skipLoggingPayload)
if err != nil {
diags.AddError(
"Creation of rest request failed",
Expand All @@ -328,7 +329,7 @@ func DoRestRequest(ctx context.Context, diags *diag.Diagnostics, client *Client,
return nil
}

cont, restResponse, err := client.Do(restRequest, client.skipLoggingPayload)
cont, restResponse, err := c.Do(restRequest, c.skipLoggingPayload)

// Return nil when the object is not found and ignore 404 not found error
// The resource ID will be set it to nil and the state file content will be deleted when the object is not found
Expand Down
9 changes: 7 additions & 2 deletions internal/provider/data_source_nd_site.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"

"github.com/CiscoDevNet/terraform-provider-nd/internal/client"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-log/tflog"
Expand All @@ -18,7 +19,7 @@ func NewSiteDataSource() datasource.DataSource {

// SiteDataSource defines the data source implementation.
type SiteDataSource struct {
client *Client
client *client.Client
}

func (d *SiteDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
Expand Down Expand Up @@ -74,6 +75,10 @@ func (d *SiteDataSource) Schema(ctx context.Context, req datasource.SchemaReques
Computed: true,
MarkdownDescription: "The longitude location of the site.",
},
"use_proxy": schema.BoolAttribute{
Computed: true,
MarkdownDescription: "The use proxy of the site.",
},
},
}
tflog.Debug(ctx, "End schema of datasource: nd_site")
Expand All @@ -86,7 +91,7 @@ func (d *SiteDataSource) Configure(ctx context.Context, req datasource.Configure
return
}

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

if !ok {
resp.Diagnostics.AddError(
Expand Down
1 change: 1 addition & 0 deletions internal/provider/data_source_nd_site_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func TestAccDataSourceNdSite(t *testing.T) {
resource.TestCheckResourceAttr("nd_site.example_0", "type", "aci"),
resource.TestCheckResourceAttr("nd_site.example_0", "username", "admin"),
resource.TestCheckResourceAttr("nd_site.example_0", "url", "10.195.219.154"),
resource.TestCheckResourceAttr("nd_site.example_0", "use_proxy", "false"),
),
},
{
Expand Down
11 changes: 6 additions & 5 deletions internal/provider/data_source_nd_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"

"github.com/CiscoDevNet/terraform-provider-nd/internal/client"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/diag"
Expand All @@ -21,7 +22,7 @@ func NewVersionDataSource() datasource.DataSource {

// VersionDataSource defines the data source implementation.
type VersionDataSource struct {
client *Client
client *client.Client
}

func (d *VersionDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
Expand Down Expand Up @@ -107,12 +108,12 @@ func (d *VersionDataSource) Configure(ctx context.Context, req datasource.Config
return
}

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

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

return
Expand Down Expand Up @@ -147,8 +148,8 @@ func (d *VersionDataSource) Read(ctx context.Context, req datasource.ReadRequest
tflog.Debug(ctx, fmt.Sprintf("End read of datasource nd_version with id '%s'", data.Id.ValueString()))
}

func getAndSetVersionAttributes(ctx context.Context, diags *diag.Diagnostics, client *Client, data *VersionResourceModel) {
requestData := DoRestRequest(ctx, diags, client, "version.json", "GET", nil)
func getAndSetVersionAttributes(ctx context.Context, diags *diag.Diagnostics, client *client.Client, data *VersionResourceModel) {
requestData := client.DoRestRequest(ctx, diags, "version.json", "GET", nil)
if diags.HasError() {
return
}
Expand Down
7 changes: 4 additions & 3 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"regexp"
"strconv"

"github.com/CiscoDevNet/terraform-provider-nd/internal/client"
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
Expand Down Expand Up @@ -94,7 +95,7 @@ func (p *ndProvider) Schema(ctx context.Context, req provider.SchemaRequest, res
},
},
"insecure": schema.BoolAttribute{
Description: "Allow insecure HTTPS client. This can also be set as the ND_INSECURE environment variable. Defaults to `true`.",
Description: "Allow insecure HTTPS client. This can also be set as the ND_INSECURE environment variable. Defaults to `false`.",
Optional: true,
},
"proxy_url": schema.StringAttribute{
Expand Down Expand Up @@ -137,7 +138,7 @@ func (p *ndProvider) Configure(ctx context.Context, req provider.ConfigureReques

username := getStringAttribute(data.Username, "ND_USERNAME")
password := getStringAttribute(data.Password, "ND_PASSWORD")
isInsecure := getBoolAttribute(resp, data.IsInsecure, "ND_INSECURE", true)
isInsecure := getBoolAttribute(resp, data.IsInsecure, "ND_INSECURE", false)
proxyUrl := getStringAttribute(data.ProxyUrl, "ND_PROXY_URL")
url := getStringAttribute(data.URL, "ND_URL")
loginDomain := getStringAttribute(data.LoginDomain, "ND_LOGIN_DOMAIN")
Expand All @@ -162,7 +163,7 @@ func (p *ndProvider) Configure(ctx context.Context, req provider.ConfigureReques
loginDomain = "DefaultAuth"
}

ndClient := GetClient(url, username, password, proxyUrl, proxyCreds, loginDomain, isInsecure, maxRetries)
ndClient := client.GetClient(url, username, password, proxyUrl, proxyCreds, loginDomain, isInsecure, maxRetries)

resp.DataSourceData = ndClient
resp.ResourceData = ndClient
Expand Down
Loading

0 comments on commit f9ec75d

Please sign in to comment.