Handler project (#44)
* Renamed fakeRepo to mockRepo * Changing around TODOs to capture current plans with the code. * Remove the repo interface and use a real DB for tests. * Fixed a few tests. * Adding checks for properly formatted identifiers. * Updating code to account for recent merges. Relaxing some restrictions on what an id can look like. * Added small comment explaining why RegisterGrpcGatewayer interface exists. * Move project service up a call level. Long term I think it would make sense to define these services even higher up the call stack, potentially at the initialization of the controller server, near where the DB is initialized. * Making these fields align with those in the resources under hosts/... * Hard code the service initialization in the handler registration code. * Regenerate project related code proto code. * Removing type field for project. * Adds basic project handling in CLI/SDK (#47) * Adds SDK for creating and reading projects * Reorganizes a bit * Adds CLI for creating and reading projects * Fixes some some generation bugs * Adds redirect support for default org ID * Fix protobuf import references being moved. * Update client test to look for "orgs" and "projects" instead of "org" and "project" * Update expected segments test * Fix setAddr handling when default organization is in use * Set client in target after create or read Co-authored-by: Jim Lambert <jimlambrt@Jims-MBP-3.home> Co-authored-by: Jim <jlambert@hashicorp.com> Co-authored-by: Michael Gaffney <mgaffney@users.noreply.github.com> Co-authored-by: Jeff Mitchell <jeffrey.mitchell@gmail.com>
This commit is contained in:
36 files changed
+4104
-112
No files matched your search
+45
-24
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
@@ -240,17 +241,21 @@ func (c *Config) setAddr(addr string) error {
|
||||
switch len(split) {
|
||||
case 0:
|
||||
case 2:
|
||||
if split[0] != "org" {
|
||||
return fmt.Errorf("expected org segment in address, found %q", split[0])
|
||||
switch split[0] {
|
||||
case "orgs":
|
||||
c.Org = split[1]
|
||||
case "projects":
|
||||
c.Project = split[1]
|
||||
default:
|
||||
return fmt.Errorf("expected orgs or projects segment first in address, found %q", split[0])
|
||||
}
|
||||
c.Org = split[1]
|
||||
case 4:
|
||||
if split[0] != "org" {
|
||||
return fmt.Errorf("expected org segment in address, found %q", split[0])
|
||||
if split[0] != "orgs" {
|
||||
return fmt.Errorf("expected orgs segment in address, found %q", split[0])
|
||||
}
|
||||
c.Org = split[1]
|
||||
if split[2] != "project" {
|
||||
return fmt.Errorf("expected project segment in address, found %q", split[2])
|
||||
if split[2] != "projects" {
|
||||
return fmt.Errorf("expected projects segment in address, found %q", split[2])
|
||||
}
|
||||
c.Project = split[3]
|
||||
default:
|
||||
@@ -543,7 +548,7 @@ func (c *Client) SetBackoff(backoff retryablehttp.Backoff) {
|
||||
// underlying http.Client is used; modifying the client from more than one
|
||||
// goroutine at once may not be safe, so modify the client as needed and then
|
||||
// clone.
|
||||
func (c *Client) Clone() (*Client, error) {
|
||||
func (c *Client) Clone() *Client {
|
||||
c.modifyLock.RLock()
|
||||
defer c.modifyLock.RUnlock()
|
||||
|
||||
@@ -560,6 +565,8 @@ func (c *Client) Clone() (*Client, error) {
|
||||
CheckRetry: config.CheckRetry,
|
||||
Limiter: config.Limiter,
|
||||
SRVLookup: config.SRVLookup,
|
||||
Org: config.Org,
|
||||
Project: config.Project,
|
||||
}
|
||||
if config.TLSConfig != nil {
|
||||
newConfig.TLSConfig = new(TLSConfig)
|
||||
@@ -573,7 +580,7 @@ func (c *Client) Clone() (*Client, error) {
|
||||
newConfig.Headers[k] = vSlice
|
||||
}
|
||||
|
||||
return NewClient(newConfig)
|
||||
return &Client{config: newConfig}
|
||||
}
|
||||
|
||||
func copyHeaders(in http.Header) http.Header {
|
||||
@@ -647,10 +654,6 @@ func (c *Client) NewRequest(ctx context.Context, method, requestPath string, bod
|
||||
}
|
||||
}
|
||||
|
||||
if org == "" {
|
||||
return nil, fmt.Errorf("could not create request, no organization set")
|
||||
}
|
||||
|
||||
u, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -689,9 +692,12 @@ func (c *Client) NewRequest(ctx context.Context, method, requestPath string, bod
|
||||
}
|
||||
}
|
||||
|
||||
orgProjPath := path.Join("org", org)
|
||||
var orgProjPath string
|
||||
if org != "" {
|
||||
orgProjPath = path.Join(orgProjPath, "orgs", org)
|
||||
}
|
||||
if project != "" {
|
||||
orgProjPath = path.Join(orgProjPath, "project", project)
|
||||
orgProjPath = path.Join(orgProjPath, "projects", project)
|
||||
}
|
||||
|
||||
req := &http.Request{
|
||||
@@ -700,12 +706,13 @@ func (c *Client) NewRequest(ctx context.Context, method, requestPath string, bod
|
||||
User: u.User,
|
||||
Scheme: u.Scheme,
|
||||
Host: host,
|
||||
Path: path.Join(u.Path, "v1", orgProjPath, requestPath),
|
||||
Path: path.Join(u.Path, "/v1", orgProjPath, requestPath),
|
||||
},
|
||||
Host: u.Host,
|
||||
}
|
||||
req.Header = headers
|
||||
req.Header.Add("authorization", "bearer: "+token)
|
||||
req.Header.Set("content-type", "application/json")
|
||||
if ctx != nil {
|
||||
req = req.WithContext(ctx)
|
||||
}
|
||||
@@ -752,14 +759,11 @@ func (c *Client) Do(r *retryablehttp.Request) (*Response, error) {
|
||||
}
|
||||
|
||||
if timeout != 0 {
|
||||
// NOTE: this leaks a timer. But when we defer a cancel call here for
|
||||
// the returned function we see errors in tests with contxt canceled.
|
||||
// Although the request is done by the time we exit this function it is
|
||||
// still causing something else to go wrong. Maybe it ends up being
|
||||
// tied to the response somehow and reading the response body ends up
|
||||
// checking it, or something. I don't know, but until we can chase this
|
||||
// down, keep it not-canceled even though vet complains.
|
||||
ctx, _ = context.WithTimeout(ctx, timeout)
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(ctx, timeout)
|
||||
// This dance is just to ignore vet warnings; we don't want to cancel
|
||||
// this as it will make reading the response body impossible
|
||||
_ = cancel
|
||||
}
|
||||
r.Request = r.Request.WithContext(ctx)
|
||||
|
||||
@@ -782,6 +786,23 @@ func (c *Client) Do(r *retryablehttp.Request) (*Response, error) {
|
||||
}
|
||||
|
||||
result, err := client.Do(r)
|
||||
if result != nil && err == nil && result.StatusCode == 307 {
|
||||
loc, err := result.Location()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting new location during redirect: %w", err)
|
||||
}
|
||||
|
||||
// Ensure a protocol downgrade doesn't happen
|
||||
if r.URL.Scheme == "https" && loc.Scheme != "https" {
|
||||
return nil, errors.New("redirect would cause protocol downgrade")
|
||||
}
|
||||
|
||||
// Update the request
|
||||
r.URL = loc
|
||||
|
||||
result, err = client.Do(r)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "tls: oversized") {
|
||||
err = fmt.Errorf(
|
||||
|
||||
Reference in new issue
Block a user