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:
authored and GitHub committed 2020-05-12 17:35:48 -07:00
1 parent 8d7f24268c
commit c0c6a9b0b8
36 files changed
+4104 -112

No files matched your search

+45 -24
View File
@@ -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(