mirror of https://github.com/hashicorp/boundary
Fix Update Project Logic (#54)
* carve out scope into a separate branch for a PR * refactor getOpts to be private * narrowed to just the scope proto * wrap in a transaction * remove user from scopes PR * make scope type immutable * refactored with more referential integrity (thanks mike) * refactor based on pair programming with Mike * better VetForWrite that supports db.Options but that requires GetOpts and Options to be exported. * stop printing out all the db logs * refactor withScope to be private * refactor the VetForWrite a bit based on Todd's PR comment * fix typo Co-authored-by: Michael Gaffney <mgaffney@users.noreply.github.com> * fix ctx propagation and Scope returns * fix ctx propagation and use a const for std retry count * change Std to Crud * fix ctx propagation * make sure update with field masks doesn't update a field not in the mask and force a read after update. * add description * remove comment about future * clean error strings * clean up enum string rep * stdMeta * fix return value to be just nil * fix returns and errors * update test to match new error string * change len of domain to 24 * provide common function for new public ids * use common db.NewPublicId() and provide the correct prefix * move list out of CrudActions and provide a CrudlActions shortcut as well * some comments about the purpose of VetForWrite() * move to random 10 * Adding project API interface. * Creation of Project handler and Tests * Move to using the iam objects. * Setting up testify framework for mocking and assertions. * Fix iam options typo references. * Adding tests for CreateProject and UpdateProject. This also adds some additional argument validation. * Merging in PR 40 * 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 * Adding functionality and tests for update masks. * Additional tests for update. Disable update non existant project test. * Make not providing an update mask be an invalid argument. * Make empty update mask paths and no mutable fields in the path an InvalidArgument error. * Fix get Project test. * Adding back in the Update a non existant project test case. * Adding seperate path structured tests. * Attach an issue id to field mask validation TODO. * Generate Project Update SDK code (#58) * Created the UpdateFunction method. * Regenerate protobuf derived code since pull #50 updated dependencies. * Special case IDs to not be passed for updates. * Updated the tools file since imports reordered it. * Add spaces between each tools import/comment grouping. 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>pull/65/head
parent
d08c26517b
commit
7f0dfa2344
@ -0,0 +1,112 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type updateInfo struct {
|
||||
baseType string
|
||||
targetType string
|
||||
path string
|
||||
}
|
||||
|
||||
var updateFuncs = map[string][]*updateInfo{
|
||||
"scopes": {
|
||||
{
|
||||
"Organization",
|
||||
"Project",
|
||||
"projects/%s",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func writeUpdateFuncs() {
|
||||
for outPkg, funcs := range updateFuncs {
|
||||
outFile := os.Getenv("GEN_BASEPATH") + fmt.Sprintf("/api/%s/update.gen.go", outPkg)
|
||||
outBuf := bytes.NewBuffer([]byte(fmt.Sprintf(
|
||||
`// Code generated by "make api"; DO NOT EDIT.
|
||||
package %s
|
||||
`, outPkg)))
|
||||
for _, updateInfo := range funcs {
|
||||
updateFuncTemplate.Execute(outBuf, struct {
|
||||
BaseType string
|
||||
TargetType string
|
||||
LowerTargetType string
|
||||
Path string
|
||||
}{
|
||||
BaseType: updateInfo.baseType,
|
||||
TargetType: updateInfo.targetType,
|
||||
LowerTargetType: strings.ToLower(updateInfo.targetType),
|
||||
Path: updateInfo.path,
|
||||
})
|
||||
}
|
||||
if err := ioutil.WriteFile(outFile, outBuf.Bytes(), 0644); err != nil {
|
||||
fmt.Printf("error writing file %q: %v\n", outFile, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var updateFuncTemplate = template.Must(template.New("").Parse(
|
||||
`
|
||||
func (s {{ .BaseType }}) Update{{ .TargetType }}(ctx context.Context, {{ .LowerTargetType }} *{{ .TargetType }}) (*{{ .TargetType }}, *api.Error, error) {
|
||||
if s.Client == nil {
|
||||
return nil, nil, fmt.Errorf("nil client in Create{{ .TargetType }} request")
|
||||
}
|
||||
if s.Id == "" {
|
||||
{{ if (eq .BaseType "Organization") }}
|
||||
// Assume the client has been configured with organization already and
|
||||
// move on
|
||||
{{ else if (eq .BaseType "Project") }}
|
||||
// Assume the client has been configured with project already and move
|
||||
// on
|
||||
{{ else }}
|
||||
return nil, nil, fmt.Errorf("missing {{ .BaseType}} ID in Create{{ .TargetType }} request")
|
||||
{{ end }}
|
||||
} else {
|
||||
// If it's explicitly set here, override anything that might be in the
|
||||
// client
|
||||
{{ if (eq .BaseType "Organization") }}
|
||||
ctx = context.WithValue(ctx, "org", s.Id)
|
||||
{{ else if (eq .BaseType "Project") }}
|
||||
ctx = context.WithValue(ctx, "project", s.Id)
|
||||
{{ end }}
|
||||
}
|
||||
|
||||
id := {{ .LowerTargetType }}.Id
|
||||
{{ .LowerTargetType }}.Id = ""
|
||||
|
||||
req, err := s.Client.NewRequest(ctx, "PATCH", fmt.Sprintf("{{ .Path }}", id), {{ .LowerTargetType }})
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating Create{{ .TargetType }} request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := s.Client.Do(req)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error performing client request during Update{{ .TargetType }} call: %w", err)
|
||||
}
|
||||
|
||||
target := new({{ .TargetType }})
|
||||
apiErr, err := resp.Decode(target)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error decoding Update{{ .TargetType }} repsonse: %w", err)
|
||||
}
|
||||
|
||||
{{ if (eq .TargetType "Organization") }}
|
||||
target.Client = s.Client.Clone()
|
||||
target.Client.SetOrgnization(target.Id)
|
||||
{{ else if (eq .TargetType "Project") }}
|
||||
target.Client = s.Client.Clone()
|
||||
target.Client.SetProject(target.Id)
|
||||
{{ else }}
|
||||
target.Client = s.Client
|
||||
{{ end }}
|
||||
|
||||
return target, apiErr, nil
|
||||
}
|
||||
`))
|
||||
@ -0,0 +1,51 @@
|
||||
// Code generated by "make api"; DO NOT EDIT.
|
||||
package scopes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/watchtower/api"
|
||||
)
|
||||
|
||||
func (s Organization) UpdateProject(ctx context.Context, project *Project) (*Project, *api.Error, error) {
|
||||
if s.Client == nil {
|
||||
return nil, nil, fmt.Errorf("nil client in CreateProject request")
|
||||
}
|
||||
if s.Id == "" {
|
||||
|
||||
// Assume the client has been configured with organization already and
|
||||
// move on
|
||||
|
||||
} else {
|
||||
// If it's explicitly set here, override anything that might be in the
|
||||
// client
|
||||
|
||||
ctx = context.WithValue(ctx, "org", s.Id)
|
||||
|
||||
}
|
||||
|
||||
id := project.Id
|
||||
project.Id = ""
|
||||
|
||||
req, err := s.Client.NewRequest(ctx, "PATCH", fmt.Sprintf("projects/%s", id), project)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating CreateProject request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := s.Client.Do(req)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error performing client request during UpdateProject call: %w", err)
|
||||
}
|
||||
|
||||
target := new(Project)
|
||||
apiErr, err := resp.Decode(target)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error decoding UpdateProject repsonse: %w", err)
|
||||
}
|
||||
|
||||
target.Client = s.Client.Clone()
|
||||
target.Client.SetProject(target.Id)
|
||||
|
||||
return target, apiErr, nil
|
||||
}
|
||||
Loading…
Reference in new issue