Merge pull request #2613 from hashicorp/llb-target-address
Assign a Network Address to a Target
This commit is contained in:
104 files changed
+4037
-1040
No files matched your search
@@ -6,6 +6,9 @@ Canonical reference for changes, improvements, and bugfixes for Boundary.
|
||||
|
||||
### New and Improved
|
||||
|
||||
* Direct Address Targets: You can now set an address directly on a target,
|
||||
bypassing the need for host catalogs, host sets and hosts.
|
||||
([PR](https://github.com/hashicorp/boundary/pull/2613))
|
||||
* Custom Response Headers: Adds ability to set api and ui response headers based
|
||||
on status code. Includes default secure CSP and other headers.
|
||||
([PR](https://github.com/hashicorp/boundary/pull/2587))
|
||||
|
||||
@@ -87,6 +87,18 @@ func WithRecursive(recurse bool) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func WithAddress(inAddress string) Option {
|
||||
return func(o *options) {
|
||||
o.postMap["address"] = inAddress
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultAddress() Option {
|
||||
return func(o *options) {
|
||||
o.postMap["address"] = nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithApplicationCredentialSourceIds(inApplicationCredentialSourceIds []string) Option {
|
||||
return func(o *options) {
|
||||
o.postMap["application_credential_source_ids"] = inApplicationCredentialSourceIds
|
||||
|
||||
@@ -37,6 +37,7 @@ type Target struct {
|
||||
InjectedApplicationCredentialSources []*CredentialSource `json:"injected_application_credential_sources,omitempty"`
|
||||
Attributes map[string]interface{} `json:"attributes,omitempty"`
|
||||
AuthorizedActions []string `json:"authorized_actions,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
|
||||
response *api.Response
|
||||
}
|
||||
|
||||
@@ -37,8 +37,9 @@ The first step in the process is to add it to the API/SDK protobufs.
|
||||
* Define a `custom_options.v1.mask_mapping` tag for the field
|
||||
which maps the API `this` field to the storage `that` field
|
||||
(yes, it's the opposite of how it's defined for a storage protobuf)
|
||||
* Define a `custom_options.v1.generate_sdk_option` tag for the SDK
|
||||
* Define a data classification/filter tag for the field via `@gotags`
|
||||
* Define a `custom_options.v1.generate_sdk_option` tag to change the SDK and add
|
||||
API options (DefaultX, WithX functions).
|
||||
* Define a data classification/filter tag for the field via `@gotags`
|
||||
which specifies how sensitive/secret/public data
|
||||
will be handled for the API's audit events.
|
||||
See the [classification rubric](./classification-rubric.md)
|
||||
|
||||
@@ -160,7 +160,10 @@ func (b *Server) CreateDevDatabase(ctx context.Context, opt ...Option) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := b.CreateInitialTarget(ctx); err != nil {
|
||||
if _, err := b.CreateInitialTargetWithAddress(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := b.CreateInitialTargetWithHostSources(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -415,114 +415,132 @@ func (b *Server) CreateInitialHostResources(ctx context.Context) (*static.HostCa
|
||||
return hc, hs, h, nil
|
||||
}
|
||||
|
||||
func (b *Server) CreateInitialTarget(ctx context.Context) (target.Target, error) {
|
||||
func (b *Server) CreateInitialTargetWithAddress(ctx context.Context) (target.Target, error) {
|
||||
rw := db.New(b.Database)
|
||||
|
||||
kmsCache, err := kms.New(ctx, rw, rw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating kms cache: %w", err)
|
||||
return nil, fmt.Errorf("failed to create kms cache: %w", err)
|
||||
}
|
||||
if err := kmsCache.AddExternalWrappers(
|
||||
b.Context,
|
||||
kms.WithRootWrapper(b.RootKms),
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("error adding config keys to kms: %w", err)
|
||||
if err := kmsCache.AddExternalWrappers(ctx, kms.WithRootWrapper(b.RootKms)); err != nil {
|
||||
return nil, fmt.Errorf("failed to add config keys to kms: %w", err)
|
||||
}
|
||||
|
||||
targetRepo, err := target.NewRepository(ctx, rw, rw, kmsCache)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating target repository: %w", err)
|
||||
return nil, fmt.Errorf("failed to create target repository: %w", err)
|
||||
}
|
||||
|
||||
// Host Catalog
|
||||
if b.DevTargetId == "" {
|
||||
// When this function is not called as part of boundary dev (eg: as part of
|
||||
// boundary database init or tests), generate random target ids.
|
||||
if len(b.DevTargetId) == 0 {
|
||||
b.DevTargetId, err = db.NewPublicId(tcp.TargetPrefix)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating initial target id: %w", err)
|
||||
return nil, fmt.Errorf("failed to generate initial target id: %w", err)
|
||||
}
|
||||
}
|
||||
if b.DevTargetDefaultPort == 0 {
|
||||
b.DevTargetDefaultPort = 22
|
||||
}
|
||||
if len(b.DevTargetAddress) == 0 {
|
||||
b.DevTargetAddress = "127.0.0.1"
|
||||
}
|
||||
opts := []target.Option{
|
||||
target.WithName("Generated target"),
|
||||
target.WithDescription("Provides an initial target in Boundary"),
|
||||
target.WithName("Generated target with a direct address"),
|
||||
target.WithDescription("Provides an initial target using an address in Boundary"),
|
||||
target.WithDefaultPort(uint32(b.DevTargetDefaultPort)),
|
||||
target.WithSessionMaxSeconds(uint32(b.DevTargetSessionMaxSeconds)),
|
||||
target.WithSessionConnectionLimit(int32(b.DevTargetSessionConnectionLimit)),
|
||||
target.WithPublicId(b.DevTargetId),
|
||||
target.WithAddress(b.DevTargetAddress),
|
||||
}
|
||||
t, err := target.New(ctx, tcp.Subtype, b.DevProjectId, opts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating in memory target: %w", err)
|
||||
return nil, fmt.Errorf("failed to create target object: %w", err)
|
||||
}
|
||||
tt, _, _, err := targetRepo.CreateTarget(ctx, t, opts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error saving target to the db: %w", err)
|
||||
return nil, fmt.Errorf("failed to save target to the db: %w", err)
|
||||
}
|
||||
tt, _, _, err = targetRepo.AddTargetHostSources(ctx, tt.GetPublicId(), tt.GetVersion(), []string{b.DevHostSetId})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error saving target to the db: %w", err)
|
||||
}
|
||||
b.InfoKeys = append(b.InfoKeys, "generated target id")
|
||||
b.Info["generated target id"] = b.DevTargetId
|
||||
b.InfoKeys = append(b.InfoKeys, "generated target with address id")
|
||||
b.Info["generated target with address id"] = b.DevTargetId
|
||||
|
||||
// If we have an unprivileged dev user, add user to the role that grants
|
||||
// list/read:self/cancel:self on sessions, read:self/delete:self/list on
|
||||
// tokens, and an authorize-session role
|
||||
if b.DevUnprivilegedUserId != "" {
|
||||
iamRepo, err := iam.NewRepository(rw, rw, kmsCache, iam.WithRandomReader(b.SecureRandomReader))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create repo for unprivileged user target connection role: %w", err)
|
||||
return nil, fmt.Errorf("failed to create iam repository: %w", err)
|
||||
}
|
||||
err = unprivilegedDevUserRoleSetup(ctx, iamRepo, b.DevUnprivilegedUserId, b.DevProjectId, b.DevTargetId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to set up unprivileged dev user: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
roles, err := iamRepo.ListRoles(ctx, []string{b.DevProjectId})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to list existing roles in project: %w", err)
|
||||
}
|
||||
if len(roles) != 2 {
|
||||
return nil, fmt.Errorf("unexpected number of roles in default project, expected 2, got %d", len(roles))
|
||||
}
|
||||
var idx int = -1
|
||||
for i, r := range roles {
|
||||
// Hacky, I know, but saves a DB trip to look up other
|
||||
// characteristics like "if any principals are currently attached".
|
||||
// No matter what we pick here it's a bit heuristical.
|
||||
if r.Name == "Default Grants" {
|
||||
idx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if idx == -1 {
|
||||
return nil, fmt.Errorf("couldn't find default grants role in default project")
|
||||
}
|
||||
if _, err := iamRepo.AddPrincipalRoles(ctx,
|
||||
roles[idx].PublicId,
|
||||
roles[idx].Version,
|
||||
[]string{b.DevUnprivilegedUserId}); err != nil {
|
||||
return nil, fmt.Errorf("error adding unpriv user ID to project default role: %w", err)
|
||||
}
|
||||
return tt, nil
|
||||
}
|
||||
|
||||
pr, err := iam.NewRole(b.DevProjectId,
|
||||
iam.WithName("Unprivileged User Session Authorization"),
|
||||
iam.WithDescription(`Provides grants within the dev project scope to allow the initial unprivileged user to authorize sessions against the dev target`),
|
||||
)
|
||||
func (b *Server) CreateInitialTargetWithHostSources(ctx context.Context) (target.Target, error) {
|
||||
rw := db.New(b.Database)
|
||||
|
||||
kmsCache, err := kms.New(ctx, rw, rw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create kms cache: %w", err)
|
||||
}
|
||||
if err := kmsCache.AddExternalWrappers(
|
||||
b.Context,
|
||||
kms.WithRootWrapper(b.RootKms),
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("failed to add config keys to kms: %w", err)
|
||||
}
|
||||
|
||||
targetRepo, err := target.NewRepository(ctx, rw, rw, kmsCache)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create target repository: %w", err)
|
||||
}
|
||||
|
||||
// When this function is not called as part of boundary dev (eg: as part of
|
||||
// boundary database init or tests), generate random target ids.
|
||||
if len(b.DevSecondaryTargetId) == 0 {
|
||||
b.DevSecondaryTargetId, err = db.NewPublicId(tcp.TargetPrefix)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating in memory role for generated grants: %w", err)
|
||||
return nil, fmt.Errorf("failed to generate initial secondary target id: %w", err)
|
||||
}
|
||||
sessionRole, err := iamRepo.CreateRole(ctx, pr)
|
||||
}
|
||||
if b.DevTargetDefaultPort == 0 {
|
||||
b.DevTargetDefaultPort = 22
|
||||
}
|
||||
|
||||
opts := []target.Option{
|
||||
target.WithName("Generated target using host sources"),
|
||||
target.WithDescription("Provides a target using host sources in Boundary"),
|
||||
target.WithDefaultPort(uint32(b.DevTargetDefaultPort)),
|
||||
target.WithSessionMaxSeconds(uint32(b.DevTargetSessionMaxSeconds)),
|
||||
target.WithSessionConnectionLimit(int32(b.DevTargetSessionConnectionLimit)),
|
||||
target.WithPublicId(b.DevSecondaryTargetId),
|
||||
}
|
||||
t, err := target.New(ctx, tcp.Subtype, b.DevProjectId, opts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create target object: %w", err)
|
||||
}
|
||||
tt, _, _, err := targetRepo.CreateTarget(ctx, t, opts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to save target to the db: %w", err)
|
||||
}
|
||||
tt, _, _, err = targetRepo.AddTargetHostSources(ctx, tt.GetPublicId(), tt.GetVersion(), []string{b.DevHostSetId})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add host source %q to target: %w", b.DevHostSetId, err)
|
||||
}
|
||||
b.InfoKeys = append(b.InfoKeys, "generated target with host source id")
|
||||
b.Info["generated target with host source id"] = b.DevSecondaryTargetId
|
||||
|
||||
if b.DevUnprivilegedUserId != "" {
|
||||
iamRepo, err := iam.NewRepository(rw, rw, kmsCache, iam.WithRandomReader(b.SecureRandomReader))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating role for unprivileged user generated grants: %w", err)
|
||||
return nil, fmt.Errorf("failed to create iam repository: %w", err)
|
||||
}
|
||||
if _, err := iamRepo.AddRoleGrants(ctx,
|
||||
sessionRole.PublicId,
|
||||
sessionRole.Version,
|
||||
[]string{fmt.Sprintf("id=%s;actions=authorize-session", b.DevTargetId)},
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("error creating grant for unprivileged user generated grants: %w", err)
|
||||
}
|
||||
if _, err := iamRepo.AddPrincipalRoles(ctx, sessionRole.PublicId, sessionRole.Version+1, []string{b.DevUnprivilegedUserId}, nil); err != nil {
|
||||
return nil, fmt.Errorf("error adding principal to role for unprivileged user generated grants: %w", err)
|
||||
err = unprivilegedDevUserRoleSetup(ctx, iamRepo, b.DevUnprivilegedUserId, b.DevProjectId, b.DevSecondaryTargetId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to set up unprivileged dev user: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,3 +594,79 @@ func (b *Server) RegisterHostPlugin(ctx context.Context, name string, plg plgpb.
|
||||
|
||||
return plugin, nil
|
||||
}
|
||||
|
||||
// unprivilegedDevUserRoleSetup adds dev user to the role that grants
|
||||
// list/read:self/cancel:self on sessions and read:self/delete:self/list on
|
||||
// tokens. It also creates a role with an `authorize-session` grant for the
|
||||
// provided targetId.
|
||||
func unprivilegedDevUserRoleSetup(ctx context.Context, repo *iam.Repository, userId, projectId, targetId string) error {
|
||||
roles, err := repo.ListRoles(ctx, []string{projectId})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list existing roles for project id %q: %w", projectId, err)
|
||||
}
|
||||
|
||||
// Look for default grants role to set unprivileged user as a principal.
|
||||
defaultRoleIdx := -1
|
||||
for i, r := range roles {
|
||||
// Hacky, I know, but saves a DB trip to look up other
|
||||
// characteristics like "if any principals are currently attached".
|
||||
// No matter what we pick here it's a bit heuristical.
|
||||
if r.Name == "Default Grants" {
|
||||
defaultRoleIdx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if defaultRoleIdx == -1 {
|
||||
return fmt.Errorf("couldn't find default grants role for project id %q", projectId)
|
||||
}
|
||||
defaultRole := roles[defaultRoleIdx]
|
||||
|
||||
// This function may be called more than once for the same boundary
|
||||
// deployment (eg: if we're creating more than one target), so we need to
|
||||
// check if the unprivileged user is not already a principal for the default
|
||||
// role in this project, as attempting to add an existing principal is an
|
||||
// error.
|
||||
principals, err := repo.ListPrincipalRoles(ctx, defaultRole.GetPublicId())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list principals for default project role: %w", err)
|
||||
}
|
||||
found := false
|
||||
for _, p := range principals {
|
||||
if p.PrincipalId == userId {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
_, err = repo.AddPrincipalRoles(ctx, defaultRole.GetPublicId(), defaultRole.GetVersion(), []string{userId})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add %q as principal for role id %q", userId, defaultRole.GetPublicId())
|
||||
}
|
||||
defaultRole.Version++ // The above call increments the role version in the database, so we must also track that with our state.
|
||||
}
|
||||
|
||||
// Create a new role for the "authorize-session" grant and add the
|
||||
// unprivileged user as a principal.
|
||||
asRole, err := iam.NewRole(projectId,
|
||||
iam.WithName(fmt.Sprintf("Session authorization for %s", targetId)),
|
||||
iam.WithDescription(fmt.Sprintf("Provides grants within the dev project scope to allow the initial unprivileged user to authorize sessions against %s", targetId)),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create role object: %w", err)
|
||||
}
|
||||
|
||||
asRole, err = repo.CreateRole(ctx, asRole)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create role for unprivileged user: %w", err)
|
||||
}
|
||||
if _, err := repo.AddPrincipalRoles(ctx, asRole.GetPublicId(), asRole.GetVersion(), []string{userId}, nil); err != nil {
|
||||
return fmt.Errorf("failed to add unprivileged user as principal to new role: %w", err)
|
||||
}
|
||||
asRole.Version++
|
||||
|
||||
_, err = repo.AddRoleGrants(ctx, asRole.GetPublicId(), asRole.GetVersion(), []string{fmt.Sprintf("id=%s;actions=authorize-session", targetId)})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add authorize-session grant for unprivileged user: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -106,8 +106,10 @@ type Server struct {
|
||||
DevHostCatalogId string
|
||||
DevHostSetId string
|
||||
DevHostId string
|
||||
DevTargetId string
|
||||
DevHostAddress string
|
||||
DevTargetId string // Target using address.
|
||||
DevSecondaryTargetId string // Target using host sources.
|
||||
DevHostAddress string // Host address for target using host sources.
|
||||
DevTargetAddress string // Network address for target with address.
|
||||
DevTargetDefaultPort int
|
||||
DevTargetSessionMaxSeconds int
|
||||
DevTargetSessionConnectionLimit int
|
||||
|
||||
@@ -63,7 +63,16 @@ func (s *sshFlags) buildArgs(c *Command, port, ip, _ string, creds credentials)
|
||||
case "tcp":
|
||||
// SSH detects a host key change when the localhost proxy port changes
|
||||
// This uses the host ID instead of 'localhost:port'.
|
||||
args = append(args, "-o", fmt.Sprintf("HostKeyAlias=%s", c.sessionAuthzData.GetHostId()))
|
||||
if len(c.sessionAuthzData.GetHostId()) > 0 {
|
||||
args = append(args, "-o", fmt.Sprintf("HostKeyAlias=%s", c.sessionAuthzData.GetHostId()))
|
||||
} else {
|
||||
// In cases where the Target has no host sources and has an
|
||||
// address directly attached to it, we have no Host Id. Use
|
||||
// Target Id instead. Only one address can ever be present on a
|
||||
// target, and no other host sources may be present at the same
|
||||
// time, so this is a reasonable alternative.
|
||||
args = append(args, "-o", fmt.Sprintf("HostKeyAlias=%s", c.sessionAuthzData.GetTargetId()))
|
||||
}
|
||||
case "ssh":
|
||||
args = append(args, "-o", "NoHostAuthenticationForLocalhost=yes")
|
||||
}
|
||||
|
||||
@@ -426,26 +426,42 @@ func (c *InitCommand) Run(args []string) (retCode int) {
|
||||
}
|
||||
|
||||
c.DevTargetSessionConnectionLimit = -1
|
||||
t, err := c.CreateInitialTarget(c.Context)
|
||||
ta, err := c.CreateInitialTargetWithAddress(c.Context)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("Error creating initial target: %w", err).Error())
|
||||
return base.CommandCliError
|
||||
}
|
||||
taInfo := &TargetInfo{
|
||||
TargetId: ta.GetPublicId(),
|
||||
DefaultPort: ta.GetDefaultPort(),
|
||||
SessionMaxSeconds: ta.GetSessionMaxSeconds(),
|
||||
SessionConnectionLimit: ta.GetSessionConnectionLimit(),
|
||||
Type: string(ta.GetType()),
|
||||
ScopeId: ta.GetProjectId(),
|
||||
Name: ta.GetName(),
|
||||
}
|
||||
|
||||
targetInfo := &TargetInfo{
|
||||
TargetId: c.DevTargetId,
|
||||
DefaultPort: t.GetDefaultPort(),
|
||||
SessionMaxSeconds: t.GetSessionMaxSeconds(),
|
||||
SessionConnectionLimit: t.GetSessionConnectionLimit(),
|
||||
Type: "tcp",
|
||||
ScopeId: c.DevProjectId,
|
||||
Name: t.GetName(),
|
||||
ths, err := c.CreateInitialTargetWithHostSources(c.Context)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("Error creating initial secondary target: %w", err).Error())
|
||||
return base.CommandCliError
|
||||
}
|
||||
thsInfo := &TargetInfo{
|
||||
TargetId: ths.GetPublicId(),
|
||||
DefaultPort: ths.GetDefaultPort(),
|
||||
SessionMaxSeconds: ths.GetSessionMaxSeconds(),
|
||||
SessionConnectionLimit: ths.GetSessionConnectionLimit(),
|
||||
Type: string(ths.GetType()),
|
||||
ScopeId: ths.GetProjectId(),
|
||||
Name: ths.GetName(),
|
||||
}
|
||||
switch base.Format(c.UI) {
|
||||
case "table":
|
||||
c.UI.Output(generateInitialTargetTableOutput(targetInfo))
|
||||
c.UI.Output(generateInitialTargetTableOutput(taInfo))
|
||||
c.UI.Output(generateInitialTargetTableOutput(thsInfo))
|
||||
case "json":
|
||||
jsonMap["target"] = targetInfo
|
||||
jsonMap["target"] = taInfo
|
||||
jsonMap["target_secondary"] = thsInfo
|
||||
}
|
||||
|
||||
return base.CommandSuccess
|
||||
|
||||
@@ -66,6 +66,7 @@ type Command struct {
|
||||
flagUnprivilegedLoginName string
|
||||
flagUnprivilegedPassword string
|
||||
flagIdSuffix string
|
||||
flagSecondaryIdSuffix string
|
||||
flagHostAddress string
|
||||
flagTargetDefaultPort int
|
||||
flagTargetSessionMaxSeconds int
|
||||
@@ -141,7 +142,15 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
Target: &c.flagIdSuffix,
|
||||
Default: "1234567890",
|
||||
EnvVar: "BOUNDARY_DEV_ID_SUFFIX",
|
||||
Usage: `If set, auto-created resources will use this value for their identifier (along with their resource-specific prefix). Must be 10 alphanumeric characters. As an example, if this is set to "1234567890", the generated password auth method ID will be "ampw_1234567890", the generated TCP target ID will be "ttcp_1234567890", and so on.`,
|
||||
Usage: `If set, auto-created resources will use this value for their identifier (along with their resource-specific prefix). Must be 10 alphanumeric characters. As an example, if this is set to "1234567890", the generated password auth method ID will be "ampw_1234567890", the generated TCP target ID will be "ttcp_1234567890", and so on. Must be different from -secondary-id-suffix (BOUNDARY_DEV_SECONDARY_ID_SUFFIX).`,
|
||||
})
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "secondary-id-suffix",
|
||||
Target: &c.flagSecondaryIdSuffix,
|
||||
Default: "0987654321",
|
||||
EnvVar: "BOUNDARY_DEV_SECONDARY_ID_SUFFIX",
|
||||
Usage: `If set, secondary auto-created resources will use this value for their identifier (along with their resource-specific prefix). Must be 10 alphanumeric characters. Currently only used for the target resource. Must be different from -id-suffix (BOUNDARY_DEV_ID_SUFFIX).`,
|
||||
})
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
@@ -450,6 +459,23 @@ func (c *Command) Run(args []string) int {
|
||||
c.DevHostId = fmt.Sprintf("%s_%s", static.HostPrefix, c.flagIdSuffix)
|
||||
c.DevTargetId = fmt.Sprintf("%s_%s", tcp.TargetPrefix, c.flagIdSuffix)
|
||||
}
|
||||
if c.flagSecondaryIdSuffix != "" {
|
||||
if len(c.flagSecondaryIdSuffix) != 10 {
|
||||
c.UI.Error("Invalid secondary ID suffix, must be exactly 10 characters")
|
||||
return base.CommandUserError
|
||||
}
|
||||
if !handlers.ValidId(handlers.Id("abc_"+c.flagSecondaryIdSuffix), "abc") {
|
||||
c.UI.Error("Invalid secondary ID suffix, must be in the set A-Za-z0-9")
|
||||
return base.CommandUserError
|
||||
}
|
||||
c.DevSecondaryTargetId = fmt.Sprintf("%s_%s", tcp.TargetPrefix, c.flagSecondaryIdSuffix)
|
||||
}
|
||||
|
||||
if c.flagIdSuffix != "" && c.flagSecondaryIdSuffix != "" &&
|
||||
strings.EqualFold(c.flagIdSuffix, c.flagSecondaryIdSuffix) {
|
||||
c.UI.Error("Primary and secondary ID suffixes are equal, must be distinct")
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
host, port, err := net.SplitHostPort(c.flagHostAddress)
|
||||
if err != nil {
|
||||
|
||||
@@ -99,7 +99,7 @@ func TestServer_ReloadListener(t *testing.T) {
|
||||
CreateDevDatabase: true,
|
||||
ControllerKey: controllerKey,
|
||||
UseDevAuthMethod: true,
|
||||
UseDevTarget: true,
|
||||
UseDevTargets: true,
|
||||
})
|
||||
// Unset auto-created KMSes that are overwritten by config on startup
|
||||
cmd.RootKms = nil
|
||||
|
||||
@@ -14,15 +14,18 @@ import (
|
||||
// We try to pull these from TestController, but targets et al are
|
||||
// computed off of a suffix instead of having constants. Just define
|
||||
// for now here, this can be tweaked later if need be.
|
||||
const defaultTestTargetId = "ttcp_1234567890"
|
||||
const (
|
||||
defaultTestTargetId = "ttcp_1234567890"
|
||||
defaultSecondaryTestTargetId = "ttcp_0987654321"
|
||||
|
||||
const rootKmsConfig = `
|
||||
rootKmsConfig = `
|
||||
kms "aead" {
|
||||
purpose = "root"
|
||||
aead_type = "aes-gcm"
|
||||
key = "%s"
|
||||
key_id = "global_root"
|
||||
}`
|
||||
)
|
||||
|
||||
type testServerCommandOpts struct {
|
||||
// Whether or not to create the dev database
|
||||
@@ -34,8 +37,8 @@ type testServerCommandOpts struct {
|
||||
// Use the well-known dev mode auth method id (1234567890)
|
||||
UseDevAuthMethod bool
|
||||
|
||||
// Use the well-known dev mode target method id (1234567890)
|
||||
UseDevTarget bool
|
||||
// Use the well-known dev mode target method ids (1234567890 and 0987654321)
|
||||
UseDevTargets bool
|
||||
|
||||
// Whether or not to enable metric collection. If enable metrics will use
|
||||
// prometheus' default registerer.
|
||||
@@ -71,8 +74,9 @@ func testServerCommand(t *testing.T, opts testServerCommandOpts) *Command {
|
||||
cmd.Server.DevPassword = controller.DefaultTestPassword
|
||||
}
|
||||
|
||||
if opts.UseDevTarget {
|
||||
if opts.UseDevTargets {
|
||||
cmd.Server.DevTargetId = defaultTestTargetId
|
||||
cmd.Server.DevSecondaryTargetId = defaultSecondaryTestTargetId
|
||||
}
|
||||
|
||||
err = cmd.CreateDevDatabase(cmd.Context, base.WithDatabaseTemplate("boundary_template"), base.WithSkipOidcAuthMethodCreation())
|
||||
|
||||
@@ -78,9 +78,10 @@ func TestServer_ShutdownWorker(t *testing.T) {
|
||||
tcl := targets.NewClient(client)
|
||||
tgtL, err := tcl.List(ctx, scope.Global.String(), targets.WithRecursive(true))
|
||||
require.NoError(err)
|
||||
require.Len(tgtL.Items, 1)
|
||||
require.Len(tgtL.Items, 2)
|
||||
tgt := tgtL.Items[0]
|
||||
require.NotNil(tgt)
|
||||
require.NotNil(tgtL.GetItems()[1])
|
||||
|
||||
// Create test server, update default port on target
|
||||
ts := helper.NewTestTcpServer(t)
|
||||
|
||||
@@ -482,6 +482,11 @@ func (c *Command) printListTable(items []*targets.Target) string {
|
||||
fmt.Sprintf(" Description: %s", item.Description),
|
||||
)
|
||||
}
|
||||
if item.Address != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Address: %s", item.Address),
|
||||
)
|
||||
}
|
||||
if len(item.AuthorizedActions) > 0 {
|
||||
output = append(output,
|
||||
" Authorized Actions:",
|
||||
@@ -516,6 +521,9 @@ func printItemTable(item *targets.Target, resp *api.Response) string {
|
||||
if item.Description != "" {
|
||||
nonAttributeMap["Description"] = item.Description
|
||||
}
|
||||
if item.Address != "" {
|
||||
nonAttributeMap["Address"] = item.Address
|
||||
}
|
||||
if item.WorkerFilter != "" {
|
||||
nonAttributeMap["Worker Filter"] = item.WorkerFilter
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ func init() {
|
||||
|
||||
func extraSshActionsFlagsMapFuncImpl() map[string][]string {
|
||||
return map[string][]string{
|
||||
"create": {"default-port", "session-max-seconds", "session-connection-limit", "egress-worker-filter", "ingress-worker-filter"},
|
||||
"update": {"default-port", "session-max-seconds", "session-connection-limit", "worker-filter", "egress-worker-filter", "ingress-worker-filter"},
|
||||
"create": {"address", "default-port", "session-max-seconds", "session-connection-limit", "egress-worker-filter", "ingress-worker-filter"},
|
||||
"update": {"address", "default-port", "session-max-seconds", "session-connection-limit", "worker-filter", "egress-worker-filter", "ingress-worker-filter"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ type extraSshCmdVars struct {
|
||||
flagWorkerFilter string
|
||||
flagEgressWorkerFilter string
|
||||
flagIngressWorkerFilter string
|
||||
flagAddress string
|
||||
}
|
||||
|
||||
func (c *SshCommand) extraSshHelpFunc(helpMap map[string]func() string) string {
|
||||
@@ -66,6 +67,12 @@ func extraSshFlagsFuncImpl(c *SshCommand, set *base.FlagSets, f *base.FlagSet) {
|
||||
|
||||
for _, name := range flagsSshMap[c.Func] {
|
||||
switch name {
|
||||
case "address":
|
||||
fs.StringVar(&base.StringVar{
|
||||
Name: "address",
|
||||
Target: &c.flagAddress,
|
||||
Usage: "Optionally, a valid network address to connect to for this target. Can not be used alongside host sources.",
|
||||
})
|
||||
case "default-port":
|
||||
fs.StringVar(&base.StringVar{
|
||||
Name: "default-port",
|
||||
@@ -188,6 +195,14 @@ func extraSshFlagsHandlingFuncImpl(c *SshCommand, _ *base.FlagSets, opts *[]targ
|
||||
*opts = append(*opts, targets.WithIngressWorkerFilter(c.flagIngressWorkerFilter))
|
||||
}
|
||||
|
||||
switch c.flagAddress {
|
||||
case "":
|
||||
case "null":
|
||||
*opts = append(*opts, targets.DefaultAddress())
|
||||
default:
|
||||
*opts = append(*opts, targets.WithAddress(c.flagAddress))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ func init() {
|
||||
|
||||
func extraTcpActionsFlagsMapFuncImpl() map[string][]string {
|
||||
return map[string][]string{
|
||||
"create": {"default-port", "session-max-seconds", "session-connection-limit", "egress-worker-filter", "ingress-worker-filter"},
|
||||
"update": {"default-port", "session-max-seconds", "session-connection-limit", "worker-filter", "egress-worker-filter", "ingress-worker-filter"},
|
||||
"create": {"address", "default-port", "session-max-seconds", "session-connection-limit", "egress-worker-filter", "ingress-worker-filter"},
|
||||
"update": {"address", "default-port", "session-max-seconds", "session-connection-limit", "worker-filter", "egress-worker-filter", "ingress-worker-filter"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ type extraTcpCmdVars struct {
|
||||
flagWorkerFilter string
|
||||
flagEgressWorkerFilter string
|
||||
flagIngressWorkerFilter string
|
||||
flagAddress string
|
||||
}
|
||||
|
||||
func (c *TcpCommand) extraTcpHelpFunc(helpMap map[string]func() string) string {
|
||||
@@ -65,6 +66,12 @@ func extraTcpFlagsFuncImpl(c *TcpCommand, set *base.FlagSets, f *base.FlagSet) {
|
||||
|
||||
for _, name := range flagsTcpMap[c.Func] {
|
||||
switch name {
|
||||
case "address":
|
||||
fs.StringVar(&base.StringVar{
|
||||
Name: "address",
|
||||
Target: &c.flagAddress,
|
||||
Usage: "Optionally, a valid network address to connect to for this target. Can not be used alongside host sources.",
|
||||
})
|
||||
case "default-port":
|
||||
fs.StringVar(&base.StringVar{
|
||||
Name: "default-port",
|
||||
@@ -187,5 +194,13 @@ func extraTcpFlagsHandlingFuncImpl(c *TcpCommand, _ *base.FlagSets, opts *[]targ
|
||||
*opts = append(*opts, targets.WithIngressWorkerFilter(c.flagIngressWorkerFilter))
|
||||
}
|
||||
|
||||
switch c.flagAddress {
|
||||
case "":
|
||||
case "null":
|
||||
*opts = append(*opts, targets.DefaultAddress())
|
||||
default:
|
||||
*opts = append(*opts, targets.WithAddress(c.flagAddress))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -150,6 +150,22 @@ func InvalidArgumentErrorf(msg string, fields map[string]string) *ApiError {
|
||||
return apiErr
|
||||
}
|
||||
|
||||
// ConflictErrorf generates an ApiErr when a pre-conditional check is violated.
|
||||
// Note, this deliberately doesn't translate to the similarly named '412
|
||||
// Precondition Failed' HTTP response status. The ApiErr returned is a 400 bad
|
||||
// request because this is how the grpc-gateway mapping is implemented for
|
||||
// failed precondition protobuf errors.
|
||||
func ConflictErrorf(msg string) *ApiError {
|
||||
const op = "handlers.ConflictErrorf"
|
||||
ctx := context.TODO()
|
||||
err := ApiErrorWithCodeAndMessage(codes.FailedPrecondition, msg)
|
||||
var apiErr *ApiError
|
||||
if !errors.As(err, &apiErr) {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("Unable to build conflict api error."))
|
||||
}
|
||||
return apiErr
|
||||
}
|
||||
|
||||
var statusRegEx = regexp.MustCompile("Status: ([0-9]+), Kind: \"(.*)\", Error: \"(.*)\"")
|
||||
|
||||
// Converts a known errors into an error that can presented to an end user over the API.
|
||||
@@ -184,6 +200,8 @@ func backendErrorToApiError(inErr error) *ApiError {
|
||||
return InvalidArgumentErrorf("Error in provided request", map[string]string{"update_mask": "Invalid update mask provided."})
|
||||
case errors.IsUniqueError(inErr):
|
||||
return InvalidArgumentErrorf(genericUniquenessMsg, nil)
|
||||
case errors.IsConflictError(inErr):
|
||||
return ConflictErrorf(inErr.Error())
|
||||
}
|
||||
|
||||
var statusCode int32 = http.StatusInternalServerError
|
||||
|
||||
@@ -721,6 +721,7 @@ func TestCancel(t *testing.T) {
|
||||
requestContext := context.WithValue(context.Background(), requests.ContextRequestInformationKey, &requests.RequestContext{})
|
||||
ctx := auth.NewVerifierContext(requestContext, iamRepoFn, tokenRepoFn, serversRepoFn, kms, &requestInfo)
|
||||
got, gErr := s.CancelSession(ctx, tc.req)
|
||||
|
||||
if tc.err != nil {
|
||||
require.Error(gErr)
|
||||
// It's hard to mix and match api/error package errors right now
|
||||
@@ -764,6 +765,8 @@ func TestCancel(t *testing.T) {
|
||||
tc.res.GetItem().ExpirationTime = got.GetItem().GetExpirationTime()
|
||||
}
|
||||
|
||||
assert.Equal(got.GetItem().HostId, tc.res.GetItem().HostId)
|
||||
assert.Equal(got.GetItem().HostSetId, tc.res.GetItem().HostSetId)
|
||||
assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "CancelSession(%q) got response\n%q, wanted\n%q", tc.req, got, tc.res)
|
||||
|
||||
if tc.req != nil {
|
||||
|
||||
@@ -781,6 +781,10 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
|
||||
endpoints = append(endpoints, eps...)
|
||||
}
|
||||
|
||||
if len(endpoints) == 0 && t.GetAddress() == "" {
|
||||
return nil, handlers.NotFoundErrorf("No host sources or address found for given target.")
|
||||
}
|
||||
|
||||
var chosenEndpoint *host.Endpoint
|
||||
if requestedId != "" {
|
||||
for _, ep := range endpoints {
|
||||
@@ -798,25 +802,32 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
|
||||
}
|
||||
}
|
||||
|
||||
if chosenEndpoint == nil {
|
||||
if len(endpoints) == 0 {
|
||||
// No hosts were found, error
|
||||
return nil, handlers.NotFoundErrorf("No endpoint found from available target host sources.")
|
||||
}
|
||||
var h, p, hostId, hostSetId string
|
||||
if chosenEndpoint == nil && len(endpoints) > 0 {
|
||||
chosenEndpoint = endpoints[rand.Intn(len(endpoints))]
|
||||
}
|
||||
|
||||
h, p, err := net.SplitHostPort(chosenEndpoint.Address)
|
||||
switch {
|
||||
case err != nil && strings.Contains(err.Error(), missingPortErrStr):
|
||||
if t.GetDefaultPort() == 0 {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("neither the selected host %q nor the target provides a port to use", chosenEndpoint.HostId))
|
||||
if chosenEndpoint != nil {
|
||||
hostId = chosenEndpoint.HostId
|
||||
hostSetId = chosenEndpoint.SetId
|
||||
h, p, err = net.SplitHostPort(chosenEndpoint.Address)
|
||||
switch {
|
||||
case err != nil && strings.Contains(err.Error(), missingPortErrStr):
|
||||
if t.GetDefaultPort() == 0 {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("neither the selected host %q nor the target provides a port to use", chosenEndpoint.HostId))
|
||||
}
|
||||
h = chosenEndpoint.Address
|
||||
p = strconv.FormatUint(uint64(t.GetDefaultPort()), 10)
|
||||
case err != nil:
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error when parsing the chosen endpoints host address"))
|
||||
}
|
||||
h = chosenEndpoint.Address
|
||||
p = strconv.FormatUint(uint64(t.GetDefaultPort()), 10)
|
||||
case err != nil:
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error when parsing the chosen endpoints host address"))
|
||||
}
|
||||
|
||||
if t.GetAddress() != "" && hostId == "" && hostSetId == "" {
|
||||
h = t.GetAddress()
|
||||
p = strconv.FormatUint(uint64(t.GetDefaultPort()), 10)
|
||||
}
|
||||
|
||||
// Generate the endpoint URL
|
||||
endpointUrl := &url.URL{
|
||||
Scheme: t.GetType().String(),
|
||||
@@ -857,9 +868,9 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
|
||||
expTime.Seconds += int64(t.GetSessionMaxSeconds())
|
||||
sessionComposition := session.ComposedOf{
|
||||
UserId: authResults.UserId,
|
||||
HostId: chosenEndpoint.HostId,
|
||||
HostId: hostId,
|
||||
TargetId: t.GetPublicId(),
|
||||
HostSetId: chosenEndpoint.SetId,
|
||||
HostSetId: hostSetId,
|
||||
AuthTokenId: authResults.AuthTokenId,
|
||||
ProjectId: authResults.Scope.Id,
|
||||
Endpoint: endpointUrl.String(),
|
||||
@@ -871,7 +882,6 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
|
||||
DynamicCredentials: dynCreds,
|
||||
StaticCredentials: staticCreds,
|
||||
}
|
||||
|
||||
sess, err := session.New(sessionComposition)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -977,7 +987,7 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
|
||||
Type: t.GetType().String(),
|
||||
Certificate: sess.Certificate,
|
||||
PrivateKey: sess.CertificatePrivateKey,
|
||||
HostId: chosenEndpoint.HostId,
|
||||
HostId: hostId,
|
||||
Endpoint: endpointUrl.String(),
|
||||
WorkerInfo: wl.WorkerList(selectedWorkers).WorkerInfos(),
|
||||
ConnectionLimit: t.GetSessionConnectionLimit(),
|
||||
@@ -996,8 +1006,8 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
|
||||
Type: t.GetType().String(),
|
||||
AuthorizationToken: encodedMarshaledSad,
|
||||
UserId: authResults.UserId,
|
||||
HostId: chosenEndpoint.HostId,
|
||||
HostSetId: chosenEndpoint.SetId,
|
||||
HostId: hostId,
|
||||
HostSetId: hostSetId,
|
||||
Endpoint: endpointUrl.String(),
|
||||
Credentials: creds,
|
||||
}
|
||||
@@ -1040,6 +1050,9 @@ func (s Service) createInRepo(ctx context.Context, item *pb.Target) (target.Targ
|
||||
if item.GetIngressWorkerFilter() != nil {
|
||||
opts = append(opts, target.WithIngressWorkerFilter(item.GetIngressWorkerFilter().GetValue()))
|
||||
}
|
||||
if item.GetAddress() != nil {
|
||||
opts = append(opts, target.WithAddress(item.GetAddress().GetValue()))
|
||||
}
|
||||
|
||||
attr, err := subtypeRegistry.newAttribute(target.SubtypeFromType(item.GetType()), item.GetAttrs())
|
||||
if err != nil {
|
||||
@@ -1067,6 +1080,7 @@ func (s Service) createInRepo(ctx context.Context, item *pb.Target) (target.Targ
|
||||
|
||||
func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []string, item *pb.Target) (target.Target, []target.HostSource, []target.CredentialSource, error) {
|
||||
const op = "targets.(Service).updateInRepo"
|
||||
var dbMask []string
|
||||
var opts []target.Option
|
||||
if desc := item.GetDescription(); desc != nil {
|
||||
opts = append(opts, target.WithDescription(desc.GetValue()))
|
||||
@@ -1090,6 +1104,10 @@ func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []st
|
||||
if ingressFilter := item.GetIngressWorkerFilter(); ingressFilter != nil {
|
||||
opts = append(opts, target.WithIngressWorkerFilter(item.GetIngressWorkerFilter().GetValue()))
|
||||
}
|
||||
if item.GetAddress() != nil {
|
||||
dbMask = append(dbMask, "Address")
|
||||
opts = append(opts, target.WithAddress(item.GetAddress().GetValue()))
|
||||
}
|
||||
subtype := target.SubtypeFromId(id)
|
||||
|
||||
attr, err := subtypeRegistry.newAttribute(subtype, item.GetAttrs())
|
||||
@@ -1113,8 +1131,7 @@ func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []st
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to update target"))
|
||||
}
|
||||
|
||||
dbMask := maskManager.Translate(mask)
|
||||
dbMask = append(dbMask, maskManager.Translate(mask)...)
|
||||
if len(dbMask) == 0 {
|
||||
return nil, nil, nil, handlers.InvalidArgumentErrorf("No valid fields included in the update mask.", map[string]string{"update_mask": "No valid paths provided in the update mask."})
|
||||
}
|
||||
@@ -1122,7 +1139,7 @@ func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []st
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
out, hs, cl, rowsUpdated, err := repo.UpdateTarget(ctx, u, version, dbMask)
|
||||
out, hs, cl, rowsUpdated, err := repo.UpdateTarget(ctx, u, version, dbMask, opts...)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to update target"))
|
||||
}
|
||||
@@ -1167,8 +1184,14 @@ func (s Service) addHostSourcesInRepo(ctx context.Context, targetId string, host
|
||||
}
|
||||
out, hs, cl, err := repo.AddTargetHostSources(ctx, targetId, version, strutil.RemoveDuplicates(hostSourceIds, false))
|
||||
if err != nil {
|
||||
var internalErr *errors.Err
|
||||
if stderrors.As(err, &internalErr) && internalErr.Code == errors.Conflict {
|
||||
// The conflict error is surfaced directly as it's correctly
|
||||
// converted all the way down to the HTTP status.
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
|
||||
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to add host sources to target: %v.", err)
|
||||
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Failed to add target host sources")
|
||||
}
|
||||
if out == nil {
|
||||
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to lookup target after adding host sources to it.")
|
||||
@@ -1184,8 +1207,14 @@ func (s Service) setHostSourcesInRepo(ctx context.Context, targetId string, host
|
||||
}
|
||||
_, _, _, err = repo.SetTargetHostSources(ctx, targetId, version, strutil.RemoveDuplicates(hostSourceIds, false))
|
||||
if err != nil {
|
||||
var internalErr *errors.Err
|
||||
if stderrors.As(err, &internalErr) && internalErr.Code == errors.Conflict {
|
||||
// The conflict error is surfaced directly as it's correctly
|
||||
// converted all the way down to the HTTP status.
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
|
||||
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set host sources in target: %v.", err)
|
||||
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Failed to set target host sources")
|
||||
}
|
||||
|
||||
out, hs, cl, err := repo.LookupTarget(ctx, targetId)
|
||||
@@ -1424,6 +1453,9 @@ func toProto(ctx context.Context, in target.Target, hostSources []target.HostSou
|
||||
})
|
||||
}
|
||||
}
|
||||
if outputFields.Has(globals.AddressField) {
|
||||
out.Address = wrapperspb.String(in.GetAddress())
|
||||
}
|
||||
|
||||
var brokeredSources, injectedAppSources []*pb.CredentialSource
|
||||
var brokeredSourceIds, injectedAppSourceIds []string
|
||||
@@ -1525,7 +1557,20 @@ func validateCreateRequest(req *pbs.CreateTargetRequest) error {
|
||||
badFields[globals.IngressWorkerFilterField] = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
if address := req.GetItem().GetAddress(); address != nil {
|
||||
if len(address.GetValue()) < static.MinHostAddressLength ||
|
||||
len(address.GetValue()) > static.MaxHostAddressLength {
|
||||
badFields[globals.AddressField] = fmt.Sprintf("Address length must be between %d and %d characters.", static.MinHostAddressLength, static.MaxHostAddressLength)
|
||||
}
|
||||
_, _, err := net.SplitHostPort(address.GetValue())
|
||||
switch {
|
||||
case err == nil:
|
||||
badFields[globals.AddressField] = "Address does not support a port."
|
||||
case strings.Contains(err.Error(), missingPortErrStr):
|
||||
default:
|
||||
badFields[globals.AddressField] = fmt.Sprintf("Error parsing address: %v.", err)
|
||||
}
|
||||
}
|
||||
subtype := target.SubtypeFromType(req.GetItem().GetType())
|
||||
_, err := subtypeRegistry.get(subtype)
|
||||
if err != nil {
|
||||
@@ -1588,6 +1633,20 @@ func validateUpdateRequest(req *pbs.UpdateTargetRequest) error {
|
||||
badFields[globals.IngressWorkerFilterField] = err.Error()
|
||||
}
|
||||
}
|
||||
if address := req.GetItem().GetAddress(); address != nil {
|
||||
if len(address.GetValue()) < static.MinHostAddressLength ||
|
||||
len(address.GetValue()) > static.MaxHostAddressLength {
|
||||
badFields[globals.AddressField] = fmt.Sprintf("Address length must be between %d and %d characters.", static.MinHostAddressLength, static.MaxHostAddressLength)
|
||||
}
|
||||
_, _, err := net.SplitHostPort(address.GetValue())
|
||||
switch {
|
||||
case err == nil:
|
||||
badFields[globals.AddressField] = "Address does not support a port."
|
||||
case strings.Contains(err.Error(), missingPortErrStr):
|
||||
default:
|
||||
badFields[globals.AddressField] = fmt.Sprintf("Error parsing address: %v.", err)
|
||||
}
|
||||
}
|
||||
subtype := target.SubtypeFromId(req.GetId())
|
||||
_, err := subtypeRegistry.get(subtype)
|
||||
if err != nil {
|
||||
|
||||
@@ -139,6 +139,8 @@ func TestGet(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
tar := tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "test", target.WithHostSources([]string{hs[0].GetPublicId(), hs[1].GetPublicId()}))
|
||||
|
||||
tarAddr := tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "test address", target.WithAddress("8.8.8.8"))
|
||||
|
||||
pTar := &pb.Target{
|
||||
Id: tar.GetPublicId(),
|
||||
ScopeId: proj.GetPublicId(),
|
||||
@@ -152,11 +154,27 @@ func TestGet(t *testing.T) {
|
||||
SessionMaxSeconds: wrapperspb.UInt32(28800),
|
||||
SessionConnectionLimit: wrapperspb.Int32(-1),
|
||||
AuthorizedActions: testAuthorizedActions,
|
||||
Address: &wrapperspb.StringValue{},
|
||||
}
|
||||
for _, ihs := range hs {
|
||||
pTar.HostSources = append(pTar.HostSources, &pb.HostSource{Id: ihs.GetPublicId(), HostCatalogId: ihs.GetCatalogId()})
|
||||
}
|
||||
|
||||
pTarAddr := &pb.Target{
|
||||
Id: tarAddr.GetPublicId(),
|
||||
ScopeId: proj.GetPublicId(),
|
||||
Name: wrapperspb.String("test address"),
|
||||
CreatedTime: tarAddr.GetCreateTime().GetTimestamp(),
|
||||
UpdatedTime: tarAddr.GetUpdateTime().GetTimestamp(),
|
||||
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String(), ParentScopeId: o.GetPublicId()},
|
||||
Type: tcp.Subtype.String(),
|
||||
Attrs: &pb.Target_TcpTargetAttributes{},
|
||||
SessionMaxSeconds: wrapperspb.UInt32(28800),
|
||||
SessionConnectionLimit: wrapperspb.Int32(-1),
|
||||
AuthorizedActions: testAuthorizedActions,
|
||||
Address: &wrapperspb.StringValue{Value: "8.8.8.8"},
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
req *pbs.GetTargetRequest
|
||||
@@ -168,6 +186,11 @@ func TestGet(t *testing.T) {
|
||||
req: &pbs.GetTargetRequest{Id: tar.GetPublicId()},
|
||||
res: &pbs.GetTargetResponse{Item: pTar},
|
||||
},
|
||||
{
|
||||
name: "Get an Existing Target w/ address",
|
||||
req: &pbs.GetTargetRequest{Id: tarAddr.GetPublicId()},
|
||||
res: &pbs.GetTargetResponse{Item: pTarAddr},
|
||||
},
|
||||
{
|
||||
name: "Get a non existing Target",
|
||||
req: &pbs.GetTargetRequest{Id: tcp.TargetPrefix + "_DoesntExis"},
|
||||
@@ -272,6 +295,7 @@ func TestList(t *testing.T) {
|
||||
SessionMaxSeconds: wrapperspb.UInt32(28800),
|
||||
SessionConnectionLimit: wrapperspb.Int32(-1),
|
||||
AuthorizedActions: testAuthorizedActions,
|
||||
Address: &wrapperspb.StringValue{},
|
||||
})
|
||||
totalTars = append(totalTars, wantTars[i])
|
||||
tar = tcp.TestTarget(ctx, t, conn, otherProj.GetPublicId(), name, target.WithHostSources([]string{otherHss[0].GetPublicId(), otherHss[1].GetPublicId()}))
|
||||
@@ -288,6 +312,7 @@ func TestList(t *testing.T) {
|
||||
SessionMaxSeconds: wrapperspb.UInt32(28800),
|
||||
SessionConnectionLimit: wrapperspb.Int32(-1),
|
||||
AuthorizedActions: testAuthorizedActions,
|
||||
Address: &wrapperspb.StringValue{},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -575,6 +600,7 @@ func TestCreate(t *testing.T) {
|
||||
SessionConnectionLimit: wrapperspb.Int32(-1),
|
||||
AuthorizedActions: testAuthorizedActions,
|
||||
EgressWorkerFilter: wrapperspb.String(`type == "bar"`),
|
||||
Address: &wrapperspb.StringValue{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -668,6 +694,30 @@ func TestCreate(t *testing.T) {
|
||||
res: nil,
|
||||
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
||||
},
|
||||
{
|
||||
name: "Invalid address length",
|
||||
req: &pbs.CreateTargetRequest{Item: &pb.Target{
|
||||
Address: wrapperspb.String("ab"),
|
||||
}},
|
||||
res: nil,
|
||||
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
||||
},
|
||||
{
|
||||
name: "Invalid address w/ port",
|
||||
req: &pbs.CreateTargetRequest{Item: &pb.Target{
|
||||
Address: wrapperspb.String("8.8.8.8:80"),
|
||||
}},
|
||||
res: nil,
|
||||
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
||||
},
|
||||
{
|
||||
name: "Invalid address not parsable",
|
||||
req: &pbs.CreateTargetRequest{Item: &pb.Target{
|
||||
Address: wrapperspb.String("aaa.8bc.8.8:80:abc"),
|
||||
}},
|
||||
res: nil,
|
||||
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
@@ -824,6 +874,7 @@ func TestUpdate(t *testing.T) {
|
||||
SessionMaxSeconds: wrapperspb.UInt32(3600),
|
||||
SessionConnectionLimit: wrapperspb.Int32(5),
|
||||
AuthorizedActions: testAuthorizedActions,
|
||||
Address: &wrapperspb.StringValue{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -858,6 +909,7 @@ func TestUpdate(t *testing.T) {
|
||||
SessionMaxSeconds: wrapperspb.UInt32(tar.GetSessionMaxSeconds()),
|
||||
SessionConnectionLimit: wrapperspb.Int32(tar.GetSessionConnectionLimit()),
|
||||
AuthorizedActions: testAuthorizedActions,
|
||||
Address: &wrapperspb.StringValue{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -955,6 +1007,7 @@ func TestUpdate(t *testing.T) {
|
||||
SessionMaxSeconds: wrapperspb.UInt32(tar.GetSessionMaxSeconds()),
|
||||
SessionConnectionLimit: wrapperspb.Int32(tar.GetSessionConnectionLimit()),
|
||||
AuthorizedActions: testAuthorizedActions,
|
||||
Address: &wrapperspb.StringValue{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -988,6 +1041,7 @@ func TestUpdate(t *testing.T) {
|
||||
SessionMaxSeconds: wrapperspb.UInt32(tar.GetSessionMaxSeconds()),
|
||||
SessionConnectionLimit: wrapperspb.Int32(tar.GetSessionConnectionLimit()),
|
||||
AuthorizedActions: testAuthorizedActions,
|
||||
Address: &wrapperspb.StringValue{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1021,6 +1075,7 @@ func TestUpdate(t *testing.T) {
|
||||
SessionMaxSeconds: wrapperspb.UInt32(tar.GetSessionMaxSeconds()),
|
||||
SessionConnectionLimit: wrapperspb.Int32(tar.GetSessionConnectionLimit()),
|
||||
AuthorizedActions: testAuthorizedActions,
|
||||
Address: &wrapperspb.StringValue{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1109,6 +1164,45 @@ func TestUpdate(t *testing.T) {
|
||||
res: nil,
|
||||
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
||||
},
|
||||
{
|
||||
name: "Invalid address length",
|
||||
req: &pbs.UpdateTargetRequest{
|
||||
UpdateMask: &field_mask.FieldMask{
|
||||
Paths: []string{"address"},
|
||||
},
|
||||
Item: &pb.Target{
|
||||
Address: wrapperspb.String("ab"),
|
||||
},
|
||||
},
|
||||
res: nil,
|
||||
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
||||
},
|
||||
{
|
||||
name: "Invalid address w/ port",
|
||||
req: &pbs.UpdateTargetRequest{
|
||||
UpdateMask: &field_mask.FieldMask{
|
||||
Paths: []string{"address"},
|
||||
},
|
||||
Item: &pb.Target{
|
||||
Address: wrapperspb.String("8.8.8.8:80"),
|
||||
},
|
||||
},
|
||||
res: nil,
|
||||
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
||||
},
|
||||
{
|
||||
name: "Invalid address not parsable",
|
||||
req: &pbs.UpdateTargetRequest{
|
||||
UpdateMask: &field_mask.FieldMask{
|
||||
Paths: []string{"address"},
|
||||
},
|
||||
Item: &pb.Target{
|
||||
Address: wrapperspb.String("aaa.8bc.8.8:80:abc"),
|
||||
},
|
||||
},
|
||||
res: nil,
|
||||
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
||||
@@ -5,8 +5,9 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/targets"
|
||||
"github.com/hashicorp/boundary/internal/target"
|
||||
"github.com/hashicorp/boundary/internal/target/store"
|
||||
"github.com/hashicorp/boundary/internal/target/tcp"
|
||||
"github.com/hashicorp/boundary/internal/target/tcp/store"
|
||||
tcpStore "github.com/hashicorp/boundary/internal/target/tcp/store"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets"
|
||||
)
|
||||
|
||||
@@ -78,7 +79,7 @@ func init() {
|
||||
var err error
|
||||
|
||||
if maskManager, err = handlers.NewMaskManager(
|
||||
handlers.MaskDestination{&store.Target{}},
|
||||
handlers.MaskDestination{&tcpStore.Target{}, &store.TargetAddress{}},
|
||||
handlers.MaskSource{&pb.Target{}, &pb.TcpTargetAttributes{}},
|
||||
); err != nil {
|
||||
panic(err)
|
||||
|
||||
@@ -709,7 +709,7 @@ func TestControllerConfig(t testing.TB, ctx context.Context, tc *TestController,
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !opts.DisableTargetCreation {
|
||||
if _, err := tc.b.CreateInitialTarget(ctx); err != nil {
|
||||
if _, err := tc.b.CreateInitialTargetWithHostSources(ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ begin;
|
||||
alter column credential_group_key drop default;
|
||||
|
||||
-- replaces function from 15/01_wh_rename_key_columns.up.sql
|
||||
-- replaced function in 70/03_wh_sessions.up.sql
|
||||
drop trigger wh_insert_session on session;
|
||||
drop function wh_insert_session;
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ begin;
|
||||
|
||||
|
||||
-- replaces function from 15/02_wh_rename_key_columns.up.sql
|
||||
-- replaced function in 70/03_wh_sessions.up.sql
|
||||
-- adds the network address key to the host dimension table.
|
||||
drop function wh_upsert_host;
|
||||
create function wh_upsert_host(p_host_id wt_public_id, p_host_set_id wt_public_id, p_target_id wt_public_id) returns wh_dim_key
|
||||
|
||||
@@ -82,6 +82,7 @@ begin;
|
||||
-- warehouse
|
||||
|
||||
-- Replaces whx_host_dimension_source defined in 26/02_wh_network_address_dimensions.up.sql.
|
||||
-- Replaced view in 70/03_wh_sessions.up.sql
|
||||
drop view whx_host_dimension_source;
|
||||
create view whx_host_dimension_source as
|
||||
select -- id is the first column in the target view
|
||||
|
||||
@@ -35,6 +35,7 @@ begin;
|
||||
$$ language plpgsql;
|
||||
|
||||
-- Replaces trigger from 01/50_session.up.sql
|
||||
-- Replaced trigger in 70/02_sessions.up.sql
|
||||
create or replace function insert_session() returns trigger
|
||||
as $$
|
||||
begin
|
||||
|
||||
+1
@@ -32,6 +32,7 @@ begin;
|
||||
on update cascade;
|
||||
|
||||
-- Replaces trigger from 44/04_session.up.sql
|
||||
-- Replaced in 70/02_sessions.up.sql
|
||||
-- Adding a foreign key reference to the kms key means we have
|
||||
-- to set the key_id to null when the scope_id is set to null,
|
||||
-- otherwise we can't delete scopes with sessions, since deleting
|
||||
|
||||
+1
@@ -86,6 +86,7 @@ select public_id,
|
||||
from target_tcp;
|
||||
|
||||
-- Replaces view from 56/06_add_session_private_key_column.up.sql
|
||||
-- Replaced in 70/02_sessions.up.sql
|
||||
drop view session_list;
|
||||
create view session_list as
|
||||
select
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
begin;
|
||||
|
||||
create table target_address (
|
||||
target_id wt_public_id primary key,
|
||||
address text not null
|
||||
-- the following constraints are used to validate the length requirements of a dns name
|
||||
-- note the address column can also contain other network types such as ipv4
|
||||
constraint address_must_be_more_than_2_characters
|
||||
check(length(trim(address)) > 2)
|
||||
constraint address_must_be_less_than_256_characters
|
||||
check(length(trim(address)) < 256),
|
||||
constraint target_fkey foreign key (target_id)
|
||||
references target (public_id)
|
||||
on delete cascade
|
||||
on update cascade
|
||||
);
|
||||
comment on table target_address is
|
||||
'target_address entries represent a network address assigned to a target.';
|
||||
|
||||
create trigger immutable_columns before update on target_address
|
||||
for each row execute function immutable_columns('target_id');
|
||||
|
||||
insert into oplog_ticket (name, version)
|
||||
values
|
||||
('target_address', 1);
|
||||
|
||||
commit;
|
||||
@@ -0,0 +1,218 @@
|
||||
begin;
|
||||
|
||||
-- Replaces trigger from 56/02_add_data_key_foreign_key_references.up.sql
|
||||
drop trigger cancel_session_with_null_fk on session;
|
||||
create or replace function cancel_session_with_null_fk() returns trigger
|
||||
as $$
|
||||
begin
|
||||
-- Note that we need each of these to run in case
|
||||
-- more than one of them is null.
|
||||
if new.auth_token_id is null then
|
||||
perform cancel_session(new.public_id);
|
||||
end if;
|
||||
if new.project_id is null then
|
||||
-- Setting the key_id to null will allow the scope
|
||||
-- to cascade delete its keys.
|
||||
new.key_id = null;
|
||||
perform cancel_session(new.public_id);
|
||||
end if;
|
||||
if new.target_id is null then
|
||||
perform cancel_session(new.public_id);
|
||||
end if;
|
||||
if new.user_id is null then
|
||||
perform cancel_session(new.public_id);
|
||||
end if;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
|
||||
create trigger cancel_session_with_null_fk before update of auth_token_id, project_id, target_id, user_id on session
|
||||
for each row execute procedure cancel_session_with_null_fk();
|
||||
|
||||
create table session_target_address (
|
||||
session_id wt_public_id primary key,
|
||||
target_id wt_public_id,
|
||||
-- the following foreign key constraint is set to null on a delete
|
||||
-- because we want to be able to invoke a trigger to call cancel_session
|
||||
-- when the references column is deleted
|
||||
-- rather than canceling a session for any reason that may cause a row to be deleted.
|
||||
constraint target_address_fkey foreign key (target_id)
|
||||
references target_address (target_id)
|
||||
on delete set null
|
||||
on update cascade,
|
||||
constraint session_fkey foreign key (session_id)
|
||||
references session (public_id)
|
||||
on delete cascade
|
||||
on update cascade,
|
||||
constraint session_target_address_session_id_target_id_uq
|
||||
unique(session_id, target_id)
|
||||
);
|
||||
comment on table session_target_address is
|
||||
'session_target_address entries represent a session that is using a network address that is assigned directly to a Target.';
|
||||
|
||||
create trigger immutable_columns before update on session_target_address
|
||||
for each row execute procedure immutable_columns('session_id');
|
||||
|
||||
create function cancel_session_with_null_target_address_fk() returns trigger
|
||||
as $$
|
||||
begin
|
||||
if new.target_id is null then
|
||||
perform cancel_session(new.session_id);
|
||||
delete from session_target_address where session_id = new.session_id;
|
||||
end if;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
|
||||
create trigger cancel_session_with_null_target_address_fk after update of target_id on session_target_address
|
||||
for each row execute procedure cancel_session_with_null_target_address_fk();
|
||||
|
||||
create function insert_session_target_address() returns trigger
|
||||
as $$
|
||||
begin
|
||||
if new.target_id is null then
|
||||
raise exception 'target_id is null';
|
||||
end if;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
|
||||
create trigger insert_session_target_address before insert on session_target_address
|
||||
for each row execute procedure insert_session_target_address();
|
||||
|
||||
create table session_host_set_host (
|
||||
session_id wt_public_id primary key,
|
||||
host_set_id wt_public_id,
|
||||
host_id wt_public_id,
|
||||
-- the following foreign key constraints for host_set_id & host_id is set to null on a delete
|
||||
-- because we want to be able to invoke a trigger to call cancel_session
|
||||
-- when the references column is deleted
|
||||
-- rather than canceling a session for any reason that may cause a row to be deleted.
|
||||
constraint host_set_fkey foreign key (host_set_id)
|
||||
references host_set (public_id)
|
||||
on delete set null
|
||||
on update cascade,
|
||||
constraint host_fkey foreign key (host_id)
|
||||
references host (public_id)
|
||||
on delete set null
|
||||
on update cascade,
|
||||
constraint session_fkey foreign key (session_id)
|
||||
references session (public_id)
|
||||
on delete cascade
|
||||
on update cascade,
|
||||
constraint session_host_set_host_session_id_host_set_id_host_id_uq
|
||||
unique(session_id, host_set_id, host_id)
|
||||
);
|
||||
comment on table session_host_set_host is
|
||||
'session_host_set entries represent a session that is using a Host Set.';
|
||||
|
||||
create trigger immutable_columns before update on session_host_set_host
|
||||
for each row execute procedure immutable_columns('session_id');
|
||||
|
||||
create function cancel_session_with_null_host_source_fk() returns trigger
|
||||
as $$
|
||||
begin
|
||||
if new.host_set_id is null or new.host_id is null then
|
||||
perform cancel_session(new.session_id);
|
||||
delete from session_host_set_host where session_id = new.session_id;
|
||||
end if;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
|
||||
create trigger cancel_session_with_null_host_source_fk after update of host_set_id, host_id on session_host_set_host
|
||||
for each row execute procedure cancel_session_with_null_host_source_fk();
|
||||
|
||||
create function insert_session_host_set_host() returns trigger
|
||||
as $$
|
||||
begin
|
||||
if new.host_set_id is null then
|
||||
raise exception 'host_set_id is null';
|
||||
end if;
|
||||
if new.host_id is null then
|
||||
raise exception 'host_id is null';
|
||||
end if;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
|
||||
create trigger insert_session_host_set_host before insert on session_host_set_host
|
||||
for each row execute procedure insert_session_host_set_host();
|
||||
|
||||
drop view session_list;
|
||||
alter table session
|
||||
drop constraint session_host_id_fkey,
|
||||
drop constraint session_host_set_id_fkey,
|
||||
drop column host_id,
|
||||
drop column host_set_id
|
||||
;
|
||||
|
||||
-- Replaces trigger from 44/04_sessions.up.sql
|
||||
drop trigger insert_session on session;
|
||||
create or replace function insert_session() returns trigger
|
||||
as $$
|
||||
begin
|
||||
case
|
||||
when new.user_id is null then
|
||||
raise exception 'user_id is null';
|
||||
when new.target_id is null then
|
||||
raise exception 'target_id is null';
|
||||
when new.auth_token_id is null then
|
||||
raise exception 'auth_token_id is null';
|
||||
when new.project_id is null then
|
||||
raise exception 'project_id is null';
|
||||
when new.endpoint is null then
|
||||
raise exception 'endpoint is null';
|
||||
else
|
||||
end case;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
|
||||
create trigger insert_session before insert on session
|
||||
for each row execute procedure insert_session();
|
||||
|
||||
-- Replaces view from 59/01_target_ingress_egress_worker_filters.up.sql
|
||||
create view session_list as
|
||||
select
|
||||
s.public_id,
|
||||
s.user_id,
|
||||
shsh.host_id,
|
||||
s.target_id,
|
||||
shsh.host_set_id,
|
||||
s.auth_token_id,
|
||||
s.project_id,
|
||||
s.certificate,
|
||||
s.certificate_private_key,
|
||||
s.expiration_time,
|
||||
s.connection_limit,
|
||||
s.tofu_token,
|
||||
s.key_id,
|
||||
s.termination_reason,
|
||||
s.version,
|
||||
s.create_time,
|
||||
s.update_time,
|
||||
s.endpoint,
|
||||
s.worker_filter,
|
||||
s.egress_worker_filter,
|
||||
s.ingress_worker_filter,
|
||||
ss.state,
|
||||
ss.previous_end_time,
|
||||
ss.start_time,
|
||||
ss.end_time,
|
||||
sc.public_id as connection_id,
|
||||
sc.client_tcp_address,
|
||||
sc.client_tcp_port,
|
||||
sc.endpoint_tcp_address,
|
||||
sc.endpoint_tcp_port,
|
||||
sc.bytes_up,
|
||||
sc.bytes_down,
|
||||
sc.closed_reason
|
||||
from session s
|
||||
join session_state ss on
|
||||
s.public_id = ss.session_id
|
||||
left join session_connection sc on
|
||||
s.public_id = sc.session_id
|
||||
left join session_host_set_host shsh on s.public_id = shsh.session_id;
|
||||
|
||||
commit;
|
||||
@@ -0,0 +1,424 @@
|
||||
begin;
|
||||
|
||||
-- replaced view in 44/03_targets.up.sql
|
||||
drop view whx_host_dimension_source;
|
||||
create view whx_host_dimension_source as
|
||||
with
|
||||
host_sources (
|
||||
host_id, host_type, host_name, host_description,
|
||||
host_set_id, host_set_type, host_set_name, host_set_description,
|
||||
host_catalog_id, host_catalog_type, host_catalog_name, host_catalog_description,
|
||||
target_id, target_type, target_name, target_description,
|
||||
target_default_port_number, target_session_max_seconds, target_session_connection_limit,
|
||||
project_id, project_name, project_description,
|
||||
organization_id, organization_name, organization_description
|
||||
) as (
|
||||
select
|
||||
h.public_id as host_id,
|
||||
case when sh.public_id is not null then 'static host'
|
||||
when ph.public_id is not null then 'plugin host'
|
||||
else 'Unknown' end as host_type,
|
||||
case when sh.public_id is not null then coalesce(sh.name, 'None')
|
||||
when ph.public_id is not null then coalesce(ph.name, 'None')
|
||||
else 'Unknown' end as host_name,
|
||||
case when sh.public_id is not null then coalesce(sh.description, 'None')
|
||||
when ph.public_id is not null then coalesce(ph.description, 'None')
|
||||
else 'Unknown' end as host_description,
|
||||
hs.public_id as host_set_id,
|
||||
case when shs.public_id is not null then 'static host set'
|
||||
when phs.public_id is not null then 'plugin host set'
|
||||
else 'Unknown' end as host_set_type,
|
||||
case
|
||||
when shs.public_id is not null then coalesce(shs.name, 'None')
|
||||
when phs.public_id is not null then coalesce(phs.name, 'None')
|
||||
else 'None'
|
||||
end as host_set_name,
|
||||
case
|
||||
when shs.public_id is not null then coalesce(shs.description, 'None')
|
||||
when phs.public_id is not null then coalesce(phs.description, 'None')
|
||||
else 'None'
|
||||
end as host_set_description,
|
||||
hc.public_id as host_catalog_id,
|
||||
case when shc.public_id is not null then 'static host catalog'
|
||||
when phc.public_id is not null then 'plugin host catalog'
|
||||
else 'Unknown' end as host_catalog_type,
|
||||
case
|
||||
when shc.public_id is not null then coalesce(shc.name, 'None')
|
||||
when phc.public_id is not null then coalesce(phc.name, 'None')
|
||||
else 'None'
|
||||
end as host_catalog_name,
|
||||
case
|
||||
when shc.public_id is not null then coalesce(shc.description, 'None')
|
||||
when phc.public_id is not null then coalesce(phc.description, 'None')
|
||||
else 'None'
|
||||
end as host_catalog_description,
|
||||
t.public_id as target_id,
|
||||
'tcp target' as target_type,
|
||||
coalesce(t.name, 'None') as target_name,
|
||||
coalesce(t.description, 'None') as target_description,
|
||||
coalesce(t.default_port, 0) as target_default_port_number,
|
||||
t.session_max_seconds as target_session_max_seconds,
|
||||
t.session_connection_limit as target_session_connection_limit,
|
||||
p.public_id as project_id,
|
||||
coalesce(p.name, 'None') as project_name,
|
||||
coalesce(p.description, 'None') as project_description,
|
||||
o.public_id as organization_id,
|
||||
coalesce(o.name, 'None') as organization_name,
|
||||
coalesce(o.description, 'None') as organization_description
|
||||
from host as h
|
||||
join host_catalog as hc on h.catalog_id = hc.public_id
|
||||
join host_set as hs on h.catalog_id = hs.catalog_id
|
||||
join target_host_set as ts on hs.public_id = ts.host_set_id
|
||||
join target_tcp as t on ts.target_id = t.public_id
|
||||
join iam_scope as p on t.project_id = p.public_id and p.type = 'project'
|
||||
join iam_scope as o on p.parent_id = o.public_id and o.type = 'org'
|
||||
|
||||
left join static_host as sh on sh.public_id = h.public_id
|
||||
left join host_plugin_host as ph on ph.public_id = h.public_id
|
||||
left join static_host_catalog as shc on shc.public_id = hc.public_id
|
||||
left join host_plugin_catalog as phc on phc.public_id = hc.public_id
|
||||
left join static_host_set as shs on shs.public_id = hs.public_id
|
||||
left join host_plugin_set as phs on phs.public_id = hs.public_id
|
||||
),
|
||||
host_target_address (
|
||||
host_id, host_type, host_name, host_description,
|
||||
host_set_id, host_set_type, host_set_name, host_set_description,
|
||||
host_catalog_id, host_catalog_type, host_catalog_name, host_catalog_description,
|
||||
target_id, target_type, target_name, target_description,
|
||||
target_default_port_number, target_session_max_seconds, target_session_connection_limit,
|
||||
project_id, project_name, project_description,
|
||||
organization_id, organization_name, organization_description
|
||||
) as (
|
||||
select
|
||||
'Not Applicable' as host_id,
|
||||
'direct address' as host_type,
|
||||
'Not Applicable' as host_name,
|
||||
'Not Applicable' as host_description,
|
||||
'Not Applicable' as host_set_id,
|
||||
'Not Applicable' as host_set_type,
|
||||
'Not Applicable' as host_set_name,
|
||||
'Not Applicable' as host_set_description,
|
||||
'Not Applicable' as host_catalog_id,
|
||||
'Not Applicable' as host_catalog_type,
|
||||
'Not Applicable' as host_catalog_name,
|
||||
'Not Applicable' as host_catalog_description,
|
||||
t.public_id as target_id,
|
||||
'tcp target' as target_type,
|
||||
coalesce(t.name, 'None') as target_name,
|
||||
coalesce(t.description, 'None') as target_description,
|
||||
coalesce(t.default_port, 0) as target_default_port_number,
|
||||
t.session_max_seconds as target_session_max_seconds,
|
||||
t.session_connection_limit as target_session_connection_limit,
|
||||
p.public_id as project_id,
|
||||
coalesce(p.name, 'None') as project_name,
|
||||
coalesce(p.description, 'None') as project_description,
|
||||
o.public_id as organization_id,
|
||||
coalesce(o.name, 'None') as organization_name,
|
||||
coalesce(o.description, 'None') as organization_description
|
||||
from target_tcp as t
|
||||
right join target_address as ta on t.public_id = ta.target_id
|
||||
left join iam_scope as p on p.public_id = t.project_id
|
||||
left join iam_scope as o on o.public_id = p.parent_id
|
||||
)
|
||||
select * from host_sources
|
||||
union
|
||||
select * from host_target_address;
|
||||
|
||||
-- replaced function in 26/03_wh_network_address_dimensions.up.sql
|
||||
create or replace function wh_upsert_host() returns trigger
|
||||
as $$
|
||||
declare
|
||||
p_target_id wt_public_id;
|
||||
p_host_key wh_dim_key;
|
||||
src whx_host_dimension_target%rowtype;
|
||||
target whx_host_dimension_target%rowtype;
|
||||
addr_group_key wh_dim_key;
|
||||
begin
|
||||
select target_id into p_target_id
|
||||
from session
|
||||
where session.public_id = new.session_id;
|
||||
|
||||
if p_target_id is null then
|
||||
raise exception 'target_id is null';
|
||||
end if;
|
||||
|
||||
select * into target
|
||||
from whx_host_dimension_target as t
|
||||
where t.host_id = new.host_id
|
||||
and t.host_set_id = new.host_set_id
|
||||
and t.target_id = p_target_id;
|
||||
|
||||
select wh_upsert_network_address_dimension(new.host_id) into addr_group_key;
|
||||
|
||||
select target.key, addr_group_key, t.* into src
|
||||
from whx_host_dimension_source as t
|
||||
where t.host_id = new.host_id
|
||||
and t.host_set_id = new.host_set_id
|
||||
and t.target_id = p_target_id;
|
||||
|
||||
if src is distinct from target then
|
||||
|
||||
-- expire the current row
|
||||
update wh_host_dimension
|
||||
set current_row_indicator = 'Expired',
|
||||
row_expiration_time = current_timestamp
|
||||
where host_id = new.host_id
|
||||
and host_set_id = new.host_set_id
|
||||
and target_id = p_target_id
|
||||
and current_row_indicator = 'Current';
|
||||
|
||||
-- insert a new row
|
||||
insert into wh_host_dimension (
|
||||
host_id, host_type, host_name, host_description,
|
||||
network_address_group_key,
|
||||
host_set_id, host_set_type, host_set_name, host_set_description,
|
||||
host_catalog_id, host_catalog_type, host_catalog_name, host_catalog_description,
|
||||
target_id, target_type, target_name, target_description,
|
||||
target_default_port_number, target_session_max_seconds, target_session_connection_limit,
|
||||
project_id, project_name, project_description,
|
||||
organization_id, organization_name, organization_description,
|
||||
current_row_indicator, row_effective_time, row_expiration_time
|
||||
)
|
||||
select host_id, host_type, host_name, host_description,
|
||||
addr_group_key,
|
||||
host_set_id, host_set_type, host_set_name, host_set_description,
|
||||
host_catalog_id, host_catalog_type, host_catalog_name, host_catalog_description,
|
||||
target_id, target_type, target_name, target_description,
|
||||
target_default_port_number, target_session_max_seconds, target_session_connection_limit,
|
||||
project_id, project_name, project_description,
|
||||
organization_id, organization_name, organization_description,
|
||||
'Current', current_timestamp, 'infinity'::timestamptz
|
||||
from whx_host_dimension_source
|
||||
where host_id = new.host_id
|
||||
and host_set_id = new.host_set_id
|
||||
and target_id = p_target_id;
|
||||
|
||||
end if;
|
||||
|
||||
select key into p_host_key
|
||||
from wh_host_dimension as t
|
||||
where t.current_row_indicator = 'Current'
|
||||
and t.host_id = new.host_id
|
||||
and t.host_set_id = new.host_set_id
|
||||
and t.target_id = p_target_id;
|
||||
|
||||
update wh_session_accumulating_fact
|
||||
set host_key = p_host_key
|
||||
where session_id = new.session_id;
|
||||
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
|
||||
create trigger wh_update_session_connection_accumulating_fact after insert on session_host_set_host
|
||||
for each row execute procedure wh_upsert_host();
|
||||
|
||||
-- replaced function in 16/04_wh_credential_dimension.up.sql
|
||||
create or replace function wh_insert_session() returns trigger
|
||||
as $$
|
||||
declare
|
||||
new_row wh_session_accumulating_fact%rowtype;
|
||||
begin
|
||||
with
|
||||
pending_timestamp (date_dim_key, time_dim_key, ts) as (
|
||||
select wh_date_key(start_time), wh_time_key(start_time), start_time
|
||||
from session_state
|
||||
where session_id = new.public_id
|
||||
and state = 'pending'
|
||||
)
|
||||
insert into wh_session_accumulating_fact (
|
||||
session_id,
|
||||
auth_token_id,
|
||||
host_key,
|
||||
user_key,
|
||||
credential_group_key,
|
||||
session_pending_date_key,
|
||||
session_pending_time_key,
|
||||
session_pending_time
|
||||
)
|
||||
select new.public_id,
|
||||
new.auth_token_id,
|
||||
'no host source', -- will be updated by wh_upsert_host
|
||||
wh_upsert_user(new.user_id, new.auth_token_id),
|
||||
'no credentials', -- will be updated by wh_upsert_credential_group
|
||||
pending_timestamp.date_dim_key,
|
||||
pending_timestamp.time_dim_key,
|
||||
pending_timestamp.ts
|
||||
from pending_timestamp
|
||||
returning * into strict new_row;
|
||||
return null;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
|
||||
insert into wh_host_dimension (
|
||||
key,
|
||||
host_id, host_type, host_name, host_description,
|
||||
host_set_id, host_set_type, host_set_name, host_set_description,
|
||||
host_catalog_id, host_catalog_type, host_catalog_name, host_catalog_description,
|
||||
target_id, target_type, target_name, target_description, target_default_port_number, target_session_max_seconds, target_session_connection_limit,
|
||||
project_id, project_name, project_description, organization_id, organization_name, organization_description,
|
||||
current_row_indicator, row_effective_time, row_expiration_time, network_address_group_key
|
||||
)
|
||||
values
|
||||
(
|
||||
'no host source',
|
||||
'None', 'None', 'None', 'None',
|
||||
'None', 'None', 'None', 'None',
|
||||
'None', 'None', 'None', 'None',
|
||||
'None', 'None', 'None', 'None', -1, -1, -1,
|
||||
'00000000000', 'None', 'None', '00000000000', 'None', 'None',
|
||||
'Current', now(), 'infinity'::timestamptz, 'Unknown'
|
||||
);
|
||||
|
||||
create function wh_upsert_direct_network_address_dimension(p_address text, p_target_id text) returns wh_dim_key
|
||||
as $$
|
||||
declare
|
||||
p_address_type text := 'Not Applicable';
|
||||
p_ip_address_family text := 'Not Applicable';
|
||||
p_private_ip_address_indicator text := 'Not Applicable';
|
||||
p_dns_name text := 'Not Applicable';
|
||||
p_ip4_address text := 'Not Applicable';
|
||||
p_ip6_address text := 'Not Applicable';
|
||||
nag_key wh_dim_key;
|
||||
begin
|
||||
if wh_try_cast_inet(p_address) is null then
|
||||
p_address_type := 'DNS Name';
|
||||
p_dns_name := p_address;
|
||||
else
|
||||
p_address_type := 'IP Address';
|
||||
p_private_ip_address_indicator := wh_private_address_indicator(wh_try_cast_inet(p_address));
|
||||
end if;
|
||||
|
||||
if family(wh_try_cast_inet(p_address)) = 4 then
|
||||
p_ip_address_family := 'IPv4';
|
||||
p_ip4_address := host(wh_try_cast_inet(p_address));
|
||||
elsif family(wh_try_cast_inet(p_address)) = 6 then
|
||||
p_ip_address_family := 'IPv6';
|
||||
p_ip6_address := host(wh_try_cast_inet(p_address));
|
||||
end if;
|
||||
|
||||
insert into wh_network_address_dimension
|
||||
(address, address_type, ip_address_family, private_ip_address_indicator, dns_name, ip4_address, ip6_address)
|
||||
values
|
||||
(p_address, p_address_type, p_ip_address_family, p_private_ip_address_indicator, p_dns_name, p_ip4_address, p_ip6_address) on conflict do nothing;
|
||||
|
||||
select distinct g.network_address_group_key into nag_key
|
||||
from wh_network_address_group_membership g
|
||||
left join wh_host_dimension h on g.network_address_group_key = h.network_address_group_key
|
||||
where g.network_address = p_address
|
||||
and h.current_row_indicator = 'Current'
|
||||
and h.target_id = p_target_id
|
||||
and h.host_id = 'Not Applicable'
|
||||
and h.host_set_id = 'Not Applicable';
|
||||
|
||||
if nag_key is null then
|
||||
select network_address_group_key into nag_key
|
||||
from wh_host_dimension h
|
||||
where h.current_row_indicator = 'Current'
|
||||
and h.host_id = 'Not Applicable'
|
||||
and h.host_set_id = 'Not Applicable'
|
||||
and h.target_id = p_target_id;
|
||||
end if;
|
||||
|
||||
if nag_key is null then
|
||||
insert into wh_network_address_group default values returning key into nag_key;
|
||||
end if;
|
||||
|
||||
insert into wh_network_address_group_membership
|
||||
(network_address_group_key, network_address)
|
||||
values
|
||||
(nag_key, p_address) on conflict do nothing;
|
||||
|
||||
return nag_key;
|
||||
end
|
||||
$$ language plpgsql;
|
||||
|
||||
create function wh_upsert_host_direct_network_address() returns trigger
|
||||
as $$
|
||||
declare
|
||||
p_address text;
|
||||
src whx_host_dimension_target%rowtype;
|
||||
target whx_host_dimension_target%rowtype;
|
||||
addr_group_key wh_dim_key;
|
||||
p_host_key wh_dim_key;
|
||||
begin
|
||||
select address into p_address
|
||||
from target_address
|
||||
where target_address.target_id = new.target_id;
|
||||
|
||||
if p_address is null then
|
||||
raise exception 'target address is null';
|
||||
end if;
|
||||
|
||||
select * into target
|
||||
from whx_host_dimension_target as t
|
||||
where t.host_id = 'Not Applicable'
|
||||
and t.host_set_id = 'Not Applicable'
|
||||
and t.target_id = new.target_id;
|
||||
|
||||
select wh_upsert_direct_network_address_dimension(p_address, new.target_id) into addr_group_key;
|
||||
|
||||
select target.key, addr_group_key, t.* into src
|
||||
from whx_host_dimension_source as t
|
||||
where t.host_id = 'Not Applicable'
|
||||
and t.host_set_id = 'Not Applicable'
|
||||
and t.target_id = new.target_id;
|
||||
|
||||
if src is distinct from target then
|
||||
|
||||
-- expire the current row
|
||||
update wh_host_dimension
|
||||
set current_row_indicator = 'Expired',
|
||||
row_expiration_time = current_timestamp
|
||||
where host_id = 'Not Applicable'
|
||||
and host_set_id = 'Not Applicable'
|
||||
and target_id = new.target_id
|
||||
and current_row_indicator = 'Current';
|
||||
|
||||
-- insert a new row
|
||||
insert into wh_host_dimension (
|
||||
host_id, host_type, host_name, host_description,
|
||||
network_address_group_key,
|
||||
host_set_id, host_set_type, host_set_name, host_set_description,
|
||||
host_catalog_id, host_catalog_type, host_catalog_name, host_catalog_description,
|
||||
target_id, target_type, target_name, target_description,
|
||||
target_default_port_number, target_session_max_seconds, target_session_connection_limit,
|
||||
project_id, project_name, project_description,
|
||||
organization_id, organization_name, organization_description,
|
||||
current_row_indicator, row_effective_time, row_expiration_time
|
||||
)
|
||||
select host_id, host_type, host_name, host_description,
|
||||
addr_group_key,
|
||||
host_set_id, host_set_type, host_set_name, host_set_description,
|
||||
host_catalog_id, host_catalog_type, host_catalog_name, host_catalog_description,
|
||||
target_id, target_type, target_name, target_description,
|
||||
target_default_port_number, target_session_max_seconds, target_session_connection_limit,
|
||||
project_id, project_name, project_description,
|
||||
organization_id, organization_name, organization_description,
|
||||
'Current', current_timestamp, 'infinity'::timestamptz
|
||||
from whx_host_dimension_source
|
||||
where host_id = 'Not Applicable'
|
||||
and host_set_id = 'Not Applicable'
|
||||
and target_id = new.target_id;
|
||||
|
||||
end if;
|
||||
|
||||
select key into p_host_key
|
||||
from wh_host_dimension as t
|
||||
where t.current_row_indicator = 'Current'
|
||||
and t.host_id = 'Not Applicable'
|
||||
and t.host_set_id = 'Not Applicable'
|
||||
and t.target_id = new.target_id;
|
||||
|
||||
update wh_session_accumulating_fact
|
||||
set host_key = p_host_key
|
||||
where session_id = new.session_id;
|
||||
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
|
||||
create trigger wh_update_session_connection_accumulating_fact after insert on session_target_address
|
||||
for each row execute procedure wh_upsert_host_direct_network_address();
|
||||
|
||||
commit;
|
||||
@@ -1,188 +0,0 @@
|
||||
package oss_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/db/common"
|
||||
"github.com/hashicorp/boundary/internal/db/schema"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/target"
|
||||
"github.com/hashicorp/boundary/internal/target/targettest"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
"github.com/hashicorp/boundary/testing/dbtest"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
insertTargetQuery = `INSERT INTO "target_tcp" ("public_id","project_id","name","session_max_seconds","session_connection_limit","worker_filter") VALUES ($1,$2,$3,28800,-1,$4)`
|
||||
)
|
||||
|
||||
func TestMigrations_AddEgressAndIngressFilters(t *testing.T) {
|
||||
const (
|
||||
priorMigration = 58001
|
||||
currentMigration = 59001
|
||||
)
|
||||
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
dialect := dbtest.Postgres
|
||||
|
||||
c, u, _, err := dbtest.StartUsingTemplate(dialect, dbtest.WithTemplate(dbtest.Template1))
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, c())
|
||||
})
|
||||
d, err := common.SqlOpen(dialect, u)
|
||||
require.NoError(t, err)
|
||||
|
||||
// migration to the prior migration (before the one we want to test)
|
||||
m, err := schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions(
|
||||
schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": priorMigration}),
|
||||
))
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = m.ApplyMigrations(ctx)
|
||||
require.NoError(t, err)
|
||||
state, err := m.CurrentState(ctx)
|
||||
require.NoError(t, err)
|
||||
want := &schema.State{
|
||||
Initialized: true,
|
||||
Editions: []schema.EditionState{
|
||||
{
|
||||
Name: "oss",
|
||||
BinarySchemaVersion: priorMigration,
|
||||
DatabaseSchemaVersion: priorMigration,
|
||||
DatabaseSchemaState: schema.Equal,
|
||||
},
|
||||
},
|
||||
}
|
||||
require.Equal(t, want, state)
|
||||
|
||||
// Get a connection
|
||||
dbType, err := db.StringToDbType(dialect)
|
||||
require.NoError(t, err)
|
||||
conn, err := db.Open(ctx, dbType, u)
|
||||
require.NoError(t, err)
|
||||
|
||||
wrapper := db.TestWrapper(t)
|
||||
rw := db.New(conn)
|
||||
kmsCache := kms.TestKms(t, conn, wrapper)
|
||||
err = kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader))
|
||||
require.NoError(t, err)
|
||||
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
_, proj := iam.TestScopes(t, iamRepo)
|
||||
|
||||
// Create a target with a worker filter
|
||||
oldTargetId1, err := db.NewPublicId("ttcp")
|
||||
oldWorkerFilter := "foo==bar"
|
||||
require.NoError(t, err)
|
||||
execResult, err := d.ExecContext(ctx, insertTargetQuery, oldTargetId1, proj.PublicId, "old-target-1", oldWorkerFilter)
|
||||
require.NoError(t, err)
|
||||
rowsAffected, err := execResult.RowsAffected()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(1), rowsAffected)
|
||||
|
||||
// Create another target with a worker filter to use in testing
|
||||
oldTargetId2, err := db.NewPublicId("ttcp")
|
||||
require.NoError(t, err)
|
||||
execResult, err = d.ExecContext(ctx, insertTargetQuery, oldTargetId2, proj.PublicId, "old-target-2", oldWorkerFilter)
|
||||
require.NoError(t, err)
|
||||
rowsAffected, err = execResult.RowsAffected()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(1), rowsAffected)
|
||||
|
||||
// now we're ready for the migration we want to test.
|
||||
m, err = schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions(
|
||||
schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": currentMigration}),
|
||||
))
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = m.ApplyMigrations(ctx)
|
||||
require.NoError(t, err)
|
||||
state, err = m.CurrentState(ctx)
|
||||
require.NoError(t, err)
|
||||
want = &schema.State{
|
||||
Initialized: true,
|
||||
Editions: []schema.EditionState{
|
||||
{
|
||||
Name: "oss",
|
||||
BinarySchemaVersion: currentMigration,
|
||||
DatabaseSchemaVersion: currentMigration,
|
||||
DatabaseSchemaState: schema.Equal,
|
||||
},
|
||||
},
|
||||
}
|
||||
require.Equal(t, want, state)
|
||||
|
||||
testRepo, err := target.NewRepository(ctx, rw, rw, kmsCache)
|
||||
|
||||
// Ensure old target 1 still have the same worker filter
|
||||
result, _, _, err := testRepo.LookupTarget(ctx, oldTargetId1)
|
||||
require.Equal(t, oldWorkerFilter, result.GetWorkerFilter())
|
||||
|
||||
// Update the old worker filter
|
||||
newWorkerFilter := "bar==foo"
|
||||
result.SetWorkerFilter(newWorkerFilter)
|
||||
result, _, _, _, err = testRepo.UpdateTarget(ctx, result, result.GetVersion(), []string{"WorkerFilter"})
|
||||
require.Equal(t, newWorkerFilter, result.GetWorkerFilter())
|
||||
|
||||
// Update to set an egress filter- expect worker filter to be cleared out
|
||||
result.SetEgressWorkerFilter(newWorkerFilter)
|
||||
result, _, _, _, err = testRepo.UpdateTarget(ctx, result, result.GetVersion(), []string{"EgressWorkerFilter"})
|
||||
require.Equal(t, newWorkerFilter, result.GetEgressWorkerFilter())
|
||||
require.Empty(t, result.GetWorkerFilter())
|
||||
|
||||
// Attempt to set worker filter again - expect failure
|
||||
result.SetWorkerFilter(newWorkerFilter)
|
||||
result, _, _, _, err = testRepo.UpdateTarget(ctx, result, result.GetVersion(), []string{"WorkerFilter"})
|
||||
require.Error(t, err)
|
||||
|
||||
// Ensure old target 2 still has the same worker filter
|
||||
result, _, _, err = testRepo.LookupTarget(ctx, oldTargetId2)
|
||||
require.Equal(t, oldWorkerFilter, result.GetWorkerFilter())
|
||||
|
||||
// Clear out its worker filter
|
||||
result.SetWorkerFilter("")
|
||||
result, _, _, _, err = testRepo.UpdateTarget(ctx, result, result.GetVersion(), []string{"WorkerFilter"})
|
||||
require.Equal(t, "", result.GetWorkerFilter())
|
||||
|
||||
// Update to set an ingress filter- expect worker filter to be cleared out
|
||||
result.SetIngressWorkerFilter(newWorkerFilter)
|
||||
result, _, _, _, err = testRepo.UpdateTarget(ctx, result, result.GetVersion(), []string{"IngressWorkerFilter"})
|
||||
require.Equal(t, newWorkerFilter, result.GetIngressWorkerFilter())
|
||||
require.Empty(t, result.GetWorkerFilter())
|
||||
|
||||
// Attempt to create a new target with a worker filter- expect failure
|
||||
tar, err := targettest.New(proj.PublicId, target.WithName("new-worker"), target.WithWorkerFilter(oldWorkerFilter))
|
||||
require.NoError(t, err)
|
||||
id, err := db.NewPublicId("ttcp")
|
||||
require.NoError(t, err)
|
||||
tar.SetPublicId(ctx, id)
|
||||
err = rw.Create(context.Background(), tar)
|
||||
require.Error(t, err)
|
||||
|
||||
// Create a new target with egress and ingress filters
|
||||
tar2, err := targettest.New(proj.PublicId, target.WithName("new-worker-filters"), target.WithEgressWorkerFilter(oldWorkerFilter),
|
||||
target.WithIngressWorkerFilter(oldWorkerFilter))
|
||||
require.NoError(t, err)
|
||||
id, err = db.NewPublicId("ttcp")
|
||||
require.NoError(t, err)
|
||||
tar2.SetPublicId(ctx, id)
|
||||
err = rw.Create(context.Background(), tar2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Attempt to create a new target with all 3 filters- expect failure
|
||||
tar3, err := targettest.New(proj.PublicId, target.WithName("new-worker-filters"), target.WithEgressWorkerFilter(oldWorkerFilter),
|
||||
target.WithIngressWorkerFilter(oldWorkerFilter), target.WithEgressWorkerFilter(oldWorkerFilter))
|
||||
require.NoError(t, err)
|
||||
id, err = db.NewPublicId("ttcp")
|
||||
require.NoError(t, err)
|
||||
tar3.SetPublicId(ctx, id)
|
||||
err = rw.Create(context.Background(), tar3)
|
||||
require.Error(t, err)
|
||||
}
|
||||
@@ -10,7 +10,8 @@ begin;
|
||||
(parent_id, type, public_id, name)
|
||||
values
|
||||
('o_____colors', 'project', 'p____bcolors', 'Blue Color Mill'),
|
||||
('o_____colors', 'project', 'p____rcolors', 'Red Color Mill');
|
||||
('o_____colors', 'project', 'p____rcolors', 'Red Color Mill'),
|
||||
('o_____colors', 'project', 'p____gcolors', 'Green Color Mill');
|
||||
|
||||
-- Add global users
|
||||
insert into iam_user
|
||||
@@ -27,7 +28,8 @@ begin;
|
||||
('o_____colors', 'u______clare', 'Clare'),
|
||||
('o_____colors', 'u______cindy', 'Cindy'),
|
||||
('o_____colors', 'u______carly', 'Carly'),
|
||||
('o_____colors', 'u______ciara', 'Ciara');
|
||||
('o_____colors', 'u______ciara', 'Ciara'),
|
||||
('o_____colors', 'u_______cora', 'Cora');
|
||||
|
||||
-- Add keys
|
||||
insert into kms_root_key
|
||||
@@ -56,7 +58,8 @@ begin;
|
||||
('global', 'g___gg-group', 'Global Group'),
|
||||
('o_____colors', 'g___oc-group', 'Colors R Us Group'),
|
||||
('p____bcolors', 'g___cb-group', 'Blue Color Group'),
|
||||
('p____rcolors', 'g___cr-group', 'Red Color Group');
|
||||
('p____rcolors', 'g___cr-group', 'Red Color Group'),
|
||||
('p____gcolors', 'g___cg-group', 'Green Color Group');
|
||||
|
||||
insert into iam_group_member_user
|
||||
(group_id, member_id)
|
||||
@@ -64,15 +67,18 @@ begin;
|
||||
('g___gg-group', 'u_______gary'),
|
||||
('g___oc-group', 'u______clare'),
|
||||
('g___cb-group', 'u______cindy'),
|
||||
('g___cr-group', 'u______carly');
|
||||
('g___cr-group', 'u______carly'),
|
||||
('g___cg-group', 'u_______cora');
|
||||
|
||||
insert into iam_role
|
||||
(scope_id, grant_scope_id, public_id, name)
|
||||
values
|
||||
('p____bcolors', 'p____bcolors', 'r_pp_bc__mix', 'Color Mixer'),
|
||||
('p____rcolors', 'p____rcolors', 'r_pp_rc__mix', 'Color Mixer'),
|
||||
('p____gcolors', 'p____gcolors', 'r_pp_gc__mix', 'Color Mixer'),
|
||||
('o_____colors', 'p____bcolors', 'r_op_bc__art', 'Blue Color Artist'),
|
||||
('o_____colors', 'p____rcolors', 'r_op_rc__art', 'Red Color Artist'),
|
||||
('o_____colors', 'p____gcolors', 'r_op_gc__art', 'Green Color Artist'),
|
||||
('o_____colors', 'o_____colors', 'r_oo_____art', 'Color Artist'),
|
||||
('global', 'o_____colors', 'r_go____name', 'Color Namer'),
|
||||
('global', 'p____bcolors', 'r_gp____spec', 'Blue Color Inspector'),
|
||||
@@ -89,15 +95,18 @@ begin;
|
||||
('r_oo_____art', 'type=color;action=create', 'create color'),
|
||||
('r_op_bc__art', 'type=color;action=create', 'create color'),
|
||||
('r_op_rc__art', 'type=color;action=create', 'create color'),
|
||||
('r_op_gc__art', 'type=color;action=create', 'create color'),
|
||||
('r_pp_bc__mix', 'type=color;action=mix', 'mix color'),
|
||||
('r_pp_rc__mix', 'type=color;action=mix', 'mix color');
|
||||
('r_pp_rc__mix', 'type=color;action=mix', 'mix color'),
|
||||
('r_pp_gc__mix', 'type=color;action=mix', 'mix color');
|
||||
|
||||
insert into iam_group_role
|
||||
(role_id, principal_id)
|
||||
values
|
||||
('r_op_rc__art', 'g___oc-group'), -- color
|
||||
('r_pp_bc__mix', 'g___cb-group'), -- color
|
||||
('r_pp_rc__mix', 'g___cr-group'); -- color
|
||||
('r_pp_rc__mix', 'g___cr-group'), -- color
|
||||
('r_pp_gc__mix', 'g___cg-group'); -- color
|
||||
|
||||
insert into iam_user_role
|
||||
(role_id, principal_id)
|
||||
@@ -125,18 +134,21 @@ begin;
|
||||
('apm___colors', 'apa____clare', 'clare'),
|
||||
('apm___colors', 'apa____cindy', 'cindy'),
|
||||
('apm___colors', 'apa____carly', 'carly'),
|
||||
('apm___colors', 'apa_____cora', 'cora'),
|
||||
('apm___colors', 'apa____ciara', 'ciara');
|
||||
|
||||
update auth_account set iam_user_id = 'u______clare' where public_id = 'apa____clare';
|
||||
update auth_account set iam_user_id = 'u______cindy' where public_id = 'apa____cindy';
|
||||
update auth_account set iam_user_id = 'u______carly' where public_id = 'apa____carly';
|
||||
update auth_account set iam_user_id = 'u_______cora' where public_id = 'apa_____cora';
|
||||
update auth_account set iam_user_id = 'u______ciara' where public_id = 'apa____ciara';
|
||||
|
||||
insert into static_host_catalog
|
||||
(project_id, public_id, name)
|
||||
values
|
||||
('p____bcolors', 'c___cb-sthcl', 'Blue Color Static Catalog'),
|
||||
('p____rcolors', 'c___cr-sthcl', 'Red Color Static Catalog');
|
||||
('p____rcolors', 'c___cr-sthcl', 'Red Color Static Catalog'),
|
||||
('p____gcolors', 'c___cg-sthcl', 'Green Color Static Catalog');
|
||||
|
||||
insert into auth_token
|
||||
(key_id, auth_account_id, public_id, token)
|
||||
@@ -144,7 +156,8 @@ begin;
|
||||
('kdkv_______colors', 'apa____clare', 'tok____clare', 'tok____clare'::bytea),
|
||||
('kdkv_______colors', 'apa____cindy', 'tok____cindy', 'tok____cindy'::bytea),
|
||||
('kdkv_______colors', 'apa____ciara', 'tok____ciara', 'tok____ciara'::bytea),
|
||||
('kdkv_______colors', 'apa____carly', 'tok____carly', 'tok____carly'::bytea);
|
||||
('kdkv_______colors', 'apa____carly', 'tok____carly', 'tok____carly'::bytea),
|
||||
('kdkv_______colors', 'apa_____cora', 'tok_____cora', 'tok_____cora'::bytea);
|
||||
|
||||
insert into static_host
|
||||
(catalog_id, public_id, address)
|
||||
@@ -167,7 +180,17 @@ begin;
|
||||
('c___cr-sthcl', 'h_____cr__06', '6.red.color'),
|
||||
('c___cr-sthcl', 'h_____cr__07', '7.red.color'),
|
||||
('c___cr-sthcl', 'h_____cr__08', '8.red.color'),
|
||||
('c___cr-sthcl', 'h_____cr__09', '9.red.color');
|
||||
('c___cr-sthcl', 'h_____cr__09', '9.red.color'),
|
||||
|
||||
('c___cg-sthcl', 'h_____cg__01', '1.green.color'),
|
||||
('c___cg-sthcl', 'h_____cg__02', '2.green.color'),
|
||||
('c___cg-sthcl', 'h_____cg__03', '3.green.color'),
|
||||
('c___cg-sthcl', 'h_____cg__04', '4.green.color'),
|
||||
('c___cg-sthcl', 'h_____cg__05', '5.green.color'),
|
||||
('c___cg-sthcl', 'h_____cg__06', '6.green.color'),
|
||||
('c___cg-sthcl', 'h_____cg__07', '7.green.color'),
|
||||
('c___cg-sthcl', 'h_____cg__08', '8.green.color'),
|
||||
('c___cg-sthcl', 'h_____cg__09', '9.green.color');
|
||||
|
||||
insert into host_dns_name
|
||||
(host_id, name)
|
||||
@@ -190,7 +213,17 @@ begin;
|
||||
('h_____cr__06', '6.red.color'),
|
||||
('h_____cr__07', '7.red.color'),
|
||||
('h_____cr__08', '8.red.color'),
|
||||
('h_____cr__09', '9.red.color');
|
||||
('h_____cr__09', '9.red.color'),
|
||||
|
||||
('h_____cg__01', '1.green.color'),
|
||||
('h_____cg__02', '2.green.color'),
|
||||
('h_____cg__03', '3.green.color'),
|
||||
('h_____cg__04', '4.green.color'),
|
||||
('h_____cg__05', '5.green.color'),
|
||||
('h_____cg__06', '6.green.color'),
|
||||
('h_____cg__07', '7.green.color'),
|
||||
('h_____cg__08', '8.green.color'),
|
||||
('h_____cg__09', '9.green.color');
|
||||
|
||||
insert into host_ip_address
|
||||
(host_id, address)
|
||||
@@ -213,7 +246,17 @@ begin;
|
||||
('h_____cr__06', '2001:4860:4860::6666'),
|
||||
('h_____cr__07', '77.77.77.77'),
|
||||
('h_____cr__08', '2001:4860:4860::8888'),
|
||||
('h_____cr__09', '99.99.99.99');
|
||||
('h_____cr__09', '99.99.99.99'),
|
||||
|
||||
('h_____cg__01', '111.111.111.111'),
|
||||
('h_____cg__02', '3001:5860:5860::3333'),
|
||||
('h_____cg__03', '112.112.112.112'),
|
||||
('h_____cg__04', '3001:5860:5860::5555'),
|
||||
('h_____cg__05', '113.113.113.113'),
|
||||
('h_____cg__06', '3001:5860:5860::7777'),
|
||||
('h_____cg__07', '114.114.114.114'),
|
||||
('h_____cg__08', '3001:5860:5860::9999'),
|
||||
('h_____cg__09', '115.115.115.115');
|
||||
|
||||
insert into static_host_set
|
||||
(catalog_id, public_id, name)
|
||||
@@ -221,7 +264,9 @@ begin;
|
||||
('c___cb-sthcl', 's___1cb-sths', 'Blue Color Static Set 1'),
|
||||
('c___cb-sthcl', 's___2cb-sths', 'Blue Color Static Set 2'),
|
||||
('c___cr-sthcl', 's___1cr-sths', 'Red Color Static Set 1'),
|
||||
('c___cr-sthcl', 's___2cr-sths', 'Red Color Static Set 2');
|
||||
('c___cr-sthcl', 's___2cr-sths', 'Red Color Static Set 2'),
|
||||
('c___cg-sthcl', 's___1cg-sths', 'Green Color Static Set 1'),
|
||||
('c___cg-sthcl', 's___2cg-sths', 'Green Color Static Set 2');
|
||||
|
||||
insert
|
||||
into static_host_set_member
|
||||
@@ -235,7 +280,8 @@ begin;
|
||||
(project_id, public_id, name)
|
||||
values
|
||||
('p____bcolors', 't_________cb', 'Blue Color Target'),
|
||||
('p____rcolors', 't_________cr', 'Red Color Target');
|
||||
('p____rcolors', 't_________cr', 'Red Color Target'),
|
||||
('p____gcolors', 't_________cg', 'Green Color Target');
|
||||
|
||||
insert into target_host_set
|
||||
(project_id, target_id, host_set_id)
|
||||
@@ -245,6 +291,11 @@ begin;
|
||||
('p____rcolors', 't_________cr', 's___1cr-sths'),
|
||||
('p____rcolors', 't_________cr', 's___2cr-sths');
|
||||
|
||||
insert into target_address
|
||||
(target_id, address)
|
||||
values
|
||||
('t_________cg', '8.8.8.8');
|
||||
|
||||
insert into credential_vault_store
|
||||
(project_id, public_id, name, description, vault_address, namespace)
|
||||
values
|
||||
@@ -263,12 +314,26 @@ begin;
|
||||
('p____bcolors', 't_________cb', 'vl______cvl', 'brokered');
|
||||
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p____bcolors', 't_________cb', 's___1cb-sths', 'h_____cb__01', 'u______clare', 'tok____clare', 'abc'::bytea, 'ep1', 's1_____clare'),
|
||||
('p____bcolors', 't_________cb', 's___1cb-sths', 'h_____cb__01', 'u______cindy', 'tok____cindy', 'abc'::bytea, 'ep1', 's1_____cindy'),
|
||||
('p____bcolors', 't_________cb', 's___1cb-sths', 'h_____cb__01', 'u______cindy', 'tok____cindy', 'abc'::bytea, 'ep1', 's1_____ciara'),
|
||||
('p____bcolors', 't_________cb', 's___1cb-sths', 'h_____cb__01', 'u______carly', 'tok____carly', 'abc'::bytea, 'ep1', 's1_____carly');
|
||||
('p____bcolors', 't_________cb', 'u______clare', 'tok____clare', 'abc'::bytea, 'ep1', 's1_____clare'),
|
||||
('p____bcolors', 't_________cb', 'u______cindy', 'tok____cindy', 'abc'::bytea, 'ep1', 's1_____cindy'),
|
||||
('p____bcolors', 't_________cb', 'u______cindy', 'tok____cindy', 'abc'::bytea, 'ep1', 's1_____ciara'),
|
||||
('p____bcolors', 't_________cb', 'u______carly', 'tok____carly', 'abc'::bytea, 'ep1', 's1_____carly'),
|
||||
('p____gcolors', 't_________cg', 'u_______cora', 'tok_____cora', 'abc'::bytea, 'ep1', 's1______cora');
|
||||
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1_____clare', 's___1cb-sths', 'h_____cb__01'),
|
||||
('s1_____cindy', 's___1cb-sths', 'h_____cb__01'),
|
||||
('s1_____ciara', 's___1cb-sths', 'h_____cb__01'),
|
||||
('s1_____carly', 's___1cb-sths', 'h_____cb__01');
|
||||
|
||||
insert into session_target_address
|
||||
(session_id, target_id)
|
||||
values
|
||||
('s1______cora', 't_________cg');
|
||||
|
||||
insert into session_connection
|
||||
(session_id, public_id)
|
||||
|
||||
@@ -122,8 +122,13 @@ begin;
|
||||
('r_pp___tacos', 'u________bob');
|
||||
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p______tacos', 't__________t', 's____1t-sths', 'h______t__01', 'u________jim', 'tok______jim', 'abc'::bytea, 'ep1', 's1_______jim');
|
||||
('p______tacos', 't__________t', 'u________jim', 'tok______jim', 'abc'::bytea, 'ep1', 's1_______jim');
|
||||
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1_______jim', 's____1t-sths', 'h______t__01');
|
||||
|
||||
commit;
|
||||
@@ -0,0 +1,28 @@
|
||||
begin;
|
||||
select plan(12);
|
||||
|
||||
-- Ensure session state table is populated
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____clare' and state='pending';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____cindy' and state='terminated';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____ciara' and state='canceling';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____carly' and state='active';
|
||||
|
||||
-- Check that we have a session for both auth token
|
||||
select is(count(*), 1::bigint) from session where auth_token_id = 'tok____clare';
|
||||
select is(count(*), 1::bigint) from session where auth_token_id = 'tok____carly';
|
||||
|
||||
-- Delete auth tokens, expect no errors
|
||||
delete from auth_token where public_id = 'tok____clare' or public_id = 'tok____carly';
|
||||
select is(count(*), 0::bigint) from auth_token where public_id = 'tok____clare';
|
||||
select is(count(*), 0::bigint) from auth_token where public_id = 'tok____carly';
|
||||
|
||||
-- Ensure we no longer have sessions associated with auth tokens
|
||||
select is(count(*), 0::bigint) from session where auth_token_id = 'tok____clare';
|
||||
select is(count(*), 0::bigint) from session where auth_token_id = 'tok____carly';
|
||||
|
||||
-- Ensure sessions that were pending or active are now in canceling state
|
||||
select is(count(*), 1::bigint) from session_state where state = 'canceling' and session_id = 's1_____clare';
|
||||
select is(count(*), 1::bigint) from session_state where state = 'canceling' and session_id = 's1_____carly';
|
||||
|
||||
select * from finish();
|
||||
rollback;
|
||||
@@ -0,0 +1,25 @@
|
||||
begin;
|
||||
select plan(9);
|
||||
|
||||
-- Ensure session state table is populated
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____clare' and state='pending';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____cindy' and state='terminated';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____ciara' and state='canceling';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____carly' and state='active';
|
||||
|
||||
-- Check that we have 4 sessions using this host
|
||||
select is(count(*), 4::bigint) from session_host_set_host where host_id = 'h_____cb__01';
|
||||
|
||||
-- Delete host, expect no errors
|
||||
delete from host where public_id = 'h_____cb__01';
|
||||
select is(count(*), 0::bigint) from host where public_id = 'h_____cb__01';
|
||||
|
||||
-- Ensure we no longer have sessions associated with this host
|
||||
select is(count(*), 0::bigint) from session_host_set_host where host_id = 'h_____cb__01';
|
||||
|
||||
-- Ensure sessions that were pending or active are now in canceling state
|
||||
select is(count(*), 1::bigint) from session_state where state = 'canceling' and session_id = 's1_____clare';
|
||||
select is(count(*), 1::bigint) from session_state where state = 'canceling' and session_id = 's1_____carly';
|
||||
|
||||
select * from finish();
|
||||
rollback;
|
||||
@@ -0,0 +1,25 @@
|
||||
begin;
|
||||
select plan(9);
|
||||
|
||||
-- Ensure session state table is populated
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____clare' and state='pending';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____cindy' and state='terminated';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____ciara' and state='canceling';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____carly' and state='active';
|
||||
|
||||
-- Check that we have 4 sessions using this host set
|
||||
select is(count(*), 4::bigint) from session_host_set_host where host_set_id = 's___1cb-sths';
|
||||
|
||||
-- Delete host set, expect no errors
|
||||
delete from host_set where public_id = 's___1cb-sths';
|
||||
select is(count(*), 0::bigint) from host_set where public_id = 's___1cb-sths';
|
||||
|
||||
-- Ensure we no longer have sessions associated with this host set
|
||||
select is(count(*), 0::bigint) from session_host_set_host where host_set_id = 's___1cb-sths';
|
||||
|
||||
-- Ensure sessions that were pending or active are now in canceling state
|
||||
select is(count(*), 1::bigint) from session_state where state = 'canceling' and session_id = 's1_____clare';
|
||||
select is(count(*), 1::bigint) from session_state where state = 'canceling' and session_id = 's1_____carly';
|
||||
|
||||
select * from finish();
|
||||
rollback;
|
||||
@@ -0,0 +1,25 @@
|
||||
begin;
|
||||
select plan(9);
|
||||
|
||||
-- Ensure session state table is populated
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____clare' and state='pending';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____cindy' and state='terminated';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____ciara' and state='canceling';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____carly' and state='active';
|
||||
|
||||
-- Check that we have 4 sessions using this project
|
||||
select is(count(*), 4::bigint) from session where project_id = 'p____bcolors';
|
||||
|
||||
-- Delete project, expect no errors
|
||||
delete from iam_scope_project where scope_id = 'p____bcolors';
|
||||
select is(count(*), 0::bigint) from iam_scope_project where scope_id = 'p____bcolors';
|
||||
|
||||
-- Ensure we no longer have sessions associated with this project
|
||||
select is(count(*), 0::bigint) from session where project_id = 'p____bcolors';
|
||||
|
||||
-- Ensure sessions that were pending or active are now in canceling state
|
||||
select is(count(*), 1::bigint) from session_state where state = 'canceling' and session_id = 's1_____clare';
|
||||
select is(count(*), 1::bigint) from session_state where state = 'canceling' and session_id = 's1_____carly';
|
||||
|
||||
select * from finish();
|
||||
rollback;
|
||||
@@ -0,0 +1,25 @@
|
||||
begin;
|
||||
select plan(9);
|
||||
|
||||
-- Ensure session state table is populated
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1______cora' and state='pending';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____clare' and state='pending';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____cindy' and state='terminated';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____ciara' and state='canceling';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____carly' and state='active';
|
||||
|
||||
-- Check that we have a session using this target address
|
||||
select is(count(*), 1::bigint) from session_target_address where target_id = 't_________cg';
|
||||
|
||||
-- Delete target address, expect no errors
|
||||
delete from target_address where target_id = 't_________cg';
|
||||
select is(count(*), 0::bigint) from target_address where target_id = 't_________cg';
|
||||
|
||||
-- Ensure we no longer have sessions associated with this target address
|
||||
select is(count(*), 0::bigint) from session_target_address where target_id = 't_________cg';
|
||||
|
||||
-- Ensure sessions that were pending or active are now in canceling state
|
||||
select is(count(*), 1::bigint) from session_state where state = 'canceling' and session_id = 's1______cora';
|
||||
|
||||
select * from finish();
|
||||
rollback;
|
||||
@@ -0,0 +1,28 @@
|
||||
begin;
|
||||
select plan(12);
|
||||
|
||||
-- Ensure session state table is populated
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____clare' and state='pending';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____cindy' and state='terminated';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____ciara' and state='canceling';
|
||||
select is(count(*), 1::bigint) from session_state where session_id = 's1_____carly' and state='active';
|
||||
|
||||
-- Check that we have a session for both users
|
||||
select is(count(*), 1::bigint) from session where user_id = 'u______clare';
|
||||
select is(count(*), 1::bigint) from session where user_id = 'u______carly';
|
||||
|
||||
-- Delete users, expect no errors
|
||||
delete from iam_user where public_id = 'u______clare' or public_id = 'u______carly';
|
||||
select is(count(*), 0::bigint) from iam_user where public_id = 'u______clare';
|
||||
select is(count(*), 0::bigint) from iam_user where public_id = 'u______carly';
|
||||
|
||||
-- Ensure we no longer have sessions associated with the users
|
||||
select is(count(*), 0::bigint) from session where user_id = 'u______clare';
|
||||
select is(count(*), 0::bigint) from session where user_id = 'u______carly';
|
||||
|
||||
-- Ensure sessions that were pending or active are now in canceling state
|
||||
select is(count(*), 1::bigint) from session_state where state = 'canceling' and session_id = 's1_____clare';
|
||||
select is(count(*), 1::bigint) from session_state where state = 'canceling' and session_id = 's1_____carly';
|
||||
|
||||
select * from finish();
|
||||
rollback;
|
||||
@@ -10,9 +10,13 @@ begin;
|
||||
|
||||
-- insert first session, should result in a new credentials dimension
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p____bwidget', 't_________wb', 's___1wb-sths', 'h_____wb__01', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's1____walter');
|
||||
('p____bwidget', 't_________wb', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
insert into session_credential_dynamic
|
||||
( session_id, library_id, credential_id, credential_purpose)
|
||||
values
|
||||
@@ -25,9 +29,13 @@ begin;
|
||||
-- * same host
|
||||
-- should not result in a new credential dimension
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p____bwidget', 't_________wb', 's___1wb-sths', 'h_____wb__01', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's2____walter');
|
||||
('p____bwidget', 't_________wb', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's2____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s2____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
insert into session_credential_dynamic
|
||||
( session_id, library_id, credential_id, credential_purpose)
|
||||
values
|
||||
@@ -39,9 +47,13 @@ begin;
|
||||
|
||||
-- start another session, should result in a new credential dimension
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p____bwidget', 't_________wb', 's___1wb-sths', 'h_____wb__01', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's3____walter');
|
||||
('p____bwidget', 't_________wb', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's3____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s3____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
insert into session_credential_dynamic
|
||||
( session_id, library_id, credential_id, credential_purpose)
|
||||
values
|
||||
@@ -50,9 +62,13 @@ begin;
|
||||
|
||||
-- start another session, should result in a one new credential dimensions
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p____bwidget', 't_________wb', 's___1wb-sths', 'h_____wb__01', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's4____walter');
|
||||
('p____bwidget', 't_________wb', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's4____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s4____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
insert into session_credential_dynamic
|
||||
( session_id, library_id, credential_id, credential_purpose)
|
||||
values
|
||||
@@ -65,9 +81,13 @@ begin;
|
||||
|
||||
-- start another session, should result in a one new credential dimensions since one changed
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p____bwidget', 't_________wb', 's___1wb-sths', 'h_____wb__01', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's5____walter');
|
||||
('p____bwidget', 't_________wb', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's5____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s5____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
insert into session_credential_dynamic
|
||||
( session_id, library_id, credential_id, credential_purpose)
|
||||
values
|
||||
@@ -80,9 +100,13 @@ begin;
|
||||
-- then test creating a session
|
||||
delete from credential_vault_library;
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p____bwidget', 't_________wb', 's___1wb-sths', 'h_____wb__01', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's6____walter');
|
||||
('p____bwidget', 't_________wb', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's6____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s6____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
select is(count(*), 4::bigint) from wh_credential_dimension where organization_id = 'o_____widget';
|
||||
select is(credential_group_key, 'no credentials') from wh_session_accumulating_fact where session_id = 's6____walter';
|
||||
insert into session_connection
|
||||
@@ -93,9 +117,13 @@ begin;
|
||||
|
||||
-- insert into a session for a target that never had any credentials associated with it.
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p____bwidget', 't_________ws', 's___1ws-sths', 'h_____ws__01', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's7____walter');
|
||||
('p____bwidget', 't_________ws', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's7____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s7____walter', 's___1ws-sths', 'h_____ws__01');
|
||||
select is(count(*), 4::bigint) from wh_credential_dimension where organization_id = 'o_____widget';
|
||||
select is(credential_group_key, 'no credentials') from wh_session_accumulating_fact where session_id = 's7____walter';
|
||||
insert into session_connection
|
||||
|
||||
@@ -10,9 +10,13 @@ begin;
|
||||
|
||||
-- insert first session, should result in a new user dimension
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p____bwidget', 't_________wb', 's___1wb-sths', 'h_____wb__01', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's1____walter');
|
||||
('p____bwidget', 't_________wb', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
insert into session_credential_dynamic
|
||||
( session_id, library_id, credential_id, credential_purpose)
|
||||
values
|
||||
|
||||
@@ -14,9 +14,13 @@ begin;
|
||||
|
||||
-- insert session and session_credential_dynamic, should result in a three new credential dimensions
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p____bwidget', 't_________wb', 's___1wb-sths', 'h_____wb__01', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's1____walter');
|
||||
('p____bwidget', 't_________wb', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
insert into session_credential_dynamic
|
||||
( session_id, library_id, credential_id, credential_purpose)
|
||||
values
|
||||
@@ -29,9 +33,13 @@ begin;
|
||||
update credential_vault_library set vault_path = '/secrets/tcp/user' where public_id = 'vl______wvl2';
|
||||
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p____bwidget', 't_________wb', 's___1wb-sths', 'h_____wb__01', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's2____walter');
|
||||
('p____bwidget', 't_________wb', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's2____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s2____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
insert into session_credential_dynamic
|
||||
( session_id, library_id, credential_id, credential_purpose)
|
||||
values
|
||||
|
||||
@@ -4,9 +4,13 @@ begin;
|
||||
|
||||
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets', 'credentials');
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p____bwidget', 't_________wb', 's___1wb-sths', 'h_____wb__01', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's1____walter');
|
||||
('p____bwidget', 't_________wb', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
insert into session_credential_dynamic
|
||||
( session_id, library_id, credential_id, credential_purpose)
|
||||
values
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
begin;
|
||||
select plan(8);
|
||||
|
||||
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets');
|
||||
|
||||
-- ensure no existing dimensions
|
||||
select is(count(*), 0::bigint) from wh_host_dimension where organization_id = 'o_____widget';
|
||||
|
||||
-- create network address dimension using static host
|
||||
insert into session
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_host_dimension where organization_id = 'o_____widget';
|
||||
select is(count(*), 1::bigint) from wh_network_address_dimension
|
||||
where address = '1.big.widget'
|
||||
and address_type = 'DNS Name'
|
||||
and ip_address_family = 'Not Applicable'
|
||||
and private_ip_address_indicator = 'Not Applicable'
|
||||
and dns_name = '1.big.widget'
|
||||
and ip4_address = 'Not Applicable'
|
||||
and ip6_address = 'Not Applicable';
|
||||
select is(count(*), 1::bigint)
|
||||
from wh_network_address_group_membership g
|
||||
left join wh_host_dimension h on g.network_address_group_key = h.network_address_group_key
|
||||
where g.network_address = '1.big.widget'
|
||||
and h.target_id = 't_________wb'
|
||||
and h.host_id = 'h_____wb__01'
|
||||
and h.host_set_id = 's___1wb-sths'
|
||||
and h.current_row_indicator = 'Current';
|
||||
|
||||
-- delete target host source associations to enforce mutually exclusive relationship to a target address
|
||||
delete from target_host_set where target_id = 't_________wb';
|
||||
|
||||
-- update target to use the same address, but as a direct network address association
|
||||
insert into target_address
|
||||
(target_id, address)
|
||||
values
|
||||
('t_________wb', '1.big.widget');
|
||||
select is(count(*), 0::bigint) from target_host_set where target_id = 't_________wb';
|
||||
|
||||
insert into session
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's2____walter');
|
||||
insert into session_target_address
|
||||
(session_id, target_id)
|
||||
values
|
||||
('s2____walter', 't_________wb');
|
||||
|
||||
-- this should have expired the old host_dimension that had values inserted in the columns related to hosts, host sets, & host catalogs.
|
||||
-- this should have created a new host_dimension for a static address with 'Not Applicable' values set for columns related to hosts, host sets, & host catalogs.
|
||||
-- this should have used the existing network_address_dimension created from the session using a host source
|
||||
select is(count(*), 2::bigint) from wh_host_dimension where organization_id = 'o_____widget';
|
||||
select is(count(*), 1::bigint) from wh_network_address_dimension
|
||||
where address = '1.big.widget'
|
||||
and address_type = 'DNS Name'
|
||||
and ip_address_family = 'Not Applicable'
|
||||
and private_ip_address_indicator = 'Not Applicable'
|
||||
and dns_name = '1.big.widget'
|
||||
and ip4_address = 'Not Applicable'
|
||||
and ip6_address = 'Not Applicable';
|
||||
select is(count(*), 1::bigint)
|
||||
from wh_network_address_group_membership g
|
||||
left join wh_host_dimension h on g.network_address_group_key = h.network_address_group_key
|
||||
where g.network_address = '1.big.widget'
|
||||
and h.target_id = 't_________wb'
|
||||
and h.host_id = 'Not Applicable'
|
||||
and h.host_set_id = 'Not Applicable'
|
||||
and h.current_row_indicator = 'Current';
|
||||
|
||||
select * from finish();
|
||||
rollback;
|
||||
@@ -10,10 +10,13 @@ begin;
|
||||
|
||||
-- insert first session, should result in a new host dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-plghs' , 'h_____wb__02-plgh' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-plghs', 'h_____wb__02-plgh');
|
||||
select is(count(*), 1::bigint) from wh_host_dimension where organization_id = 'o_____widget';
|
||||
|
||||
-- another session with:
|
||||
@@ -22,10 +25,14 @@ begin;
|
||||
-- * same host
|
||||
-- should not result in a new host dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-plghs' , 'h_____wb__02-plgh' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's2____walter');
|
||||
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's2____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s2____walter', 's___1wb-plghs', 'h_____wb__02-plgh');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_host_dimension where organization_id = 'o_____widget';
|
||||
|
||||
-- another session with:
|
||||
@@ -34,9 +41,13 @@ begin;
|
||||
-- * same host
|
||||
-- should not result in a new host dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-plghs' , 'h_____wb__02-plgh' , 'u_____warren' , 'tok___warren' , 'abc'::bytea , 'ep1' , 's3____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____warren' , 'tok___warren' , 'abc'::bytea , 'ep1' , 's3____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s3____walter', 's___1wb-plghs', 'h_____wb__02-plgh');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_host_dimension where organization_id = 'o_____widget';
|
||||
|
||||
@@ -52,9 +63,13 @@ begin;
|
||||
|
||||
-- should result in a new host dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-plghs' , 'h_____wb__02-plgh' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's4____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's4____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s4____walter', 's___1wb-plghs', 'h_____wb__02-plgh');
|
||||
|
||||
select is(count(*), 2::bigint) from wh_host_dimension where organization_id = 'o_____widget';
|
||||
|
||||
@@ -70,9 +85,13 @@ begin;
|
||||
|
||||
-- should result in a new host dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-plghs' , 'h_____wb__02-plgh' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's5____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's5____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s5____walter', 's___1wb-plghs', 'h_____wb__02-plgh');
|
||||
|
||||
select is(count(*), 3::bigint) from wh_host_dimension where organization_id = 'o_____widget';
|
||||
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
begin;
|
||||
select plan(12);
|
||||
|
||||
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets');
|
||||
|
||||
-- ensure no existing dimensions
|
||||
select is(count(*), 0::bigint) from wh_host_dimension where organization_id = 'o_____widget';
|
||||
|
||||
-- setup target to use a ipv4 static address
|
||||
insert into target_address
|
||||
(target_id, address)
|
||||
values
|
||||
('t_________wb', '8.6.4.2');
|
||||
|
||||
-- insert first session, should result in a new host dimension
|
||||
insert into session
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
insert into session_target_address
|
||||
(session_id, target_id)
|
||||
values
|
||||
('s1____walter', 't_________wb');
|
||||
select is(count(*), 1::bigint) from wh_host_dimension where organization_id = 'o_____widget';
|
||||
|
||||
-- expected wh_network_address_dimension row is created for ipv4
|
||||
select is(count(*), 1::bigint) from wh_network_address_dimension
|
||||
where address = '8.6.4.2'
|
||||
and address_type = 'IP Address'
|
||||
and ip_address_family = 'IPv4'
|
||||
and private_ip_address_indicator = 'Public IP address'
|
||||
and dns_name = 'Not Applicable'
|
||||
and ip4_address = '8.6.4.2'
|
||||
and ip6_address = 'Not Applicable';
|
||||
|
||||
-- expected wh_network_address_group_membership has one row: '8.6.4.2'
|
||||
select is(count(*), 1::bigint)
|
||||
from wh_network_address_group_membership gm,
|
||||
wh_host_dimension h
|
||||
where h.network_address_group_key = gm.network_address_group_key
|
||||
and h.host_id = 'Not Applicable'
|
||||
and h.host_set_id = 'Not Applicable'
|
||||
and h.host_catalog_id = 'Not Applicable'
|
||||
and h.target_id = 't_________wb';
|
||||
|
||||
-- update target address association to ipv6
|
||||
update target_address set address = 'fe60::6667:5556:4445:3334' where target_id = 't_________wb';
|
||||
insert into session
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's2____walter');
|
||||
insert into session_target_address
|
||||
(session_id, target_id)
|
||||
values
|
||||
('s2____walter', 't_________wb');
|
||||
|
||||
-- should not result in a new host dimension
|
||||
select is(count(*), 1::bigint) from wh_host_dimension where organization_id = 'o_____widget';
|
||||
|
||||
-- expected wh_network_address_dimension row is created for ipv6
|
||||
select is(count(*), 1::bigint) from wh_network_address_dimension
|
||||
where address = 'fe60::6667:5556:4445:3334'
|
||||
and address_type = 'IP Address'
|
||||
and ip_address_family = 'IPv6'
|
||||
and private_ip_address_indicator = 'Public IP address'
|
||||
and dns_name = 'Not Applicable'
|
||||
and ip4_address = 'Not Applicable'
|
||||
and ip6_address = 'fe60::6667:5556:4445:3334';
|
||||
|
||||
-- expected wh_network_address_group_membership has two rows: '8.6.4.2' & 'fe60::6667:5556:4445:3334'
|
||||
select is(count(*), 2::bigint)
|
||||
from wh_network_address_group_membership gm,
|
||||
wh_host_dimension h
|
||||
where h.network_address_group_key = gm.network_address_group_key
|
||||
and h.host_id = 'Not Applicable'
|
||||
and h.host_set_id = 'Not Applicable'
|
||||
and h.host_catalog_id = 'Not Applicable'
|
||||
and h.target_id = 't_________wb';
|
||||
|
||||
-- update static address association to dns name
|
||||
update target_address set address = '0.blue.green' where target_id = 't_________wb';
|
||||
insert into session
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's3____walter');
|
||||
insert into session_target_address
|
||||
(session_id, target_id)
|
||||
values
|
||||
('s3____walter', 't_________wb');
|
||||
|
||||
-- should not result in a new host dimension
|
||||
select is(count(*), 1::bigint) from wh_host_dimension where organization_id = 'o_____widget';
|
||||
|
||||
-- expected wh_network_address_dimension row is created for dns
|
||||
select is(count(*), 1::bigint) from wh_network_address_dimension
|
||||
where address = '0.blue.green'
|
||||
and address_type = 'DNS Name'
|
||||
and ip_address_family = 'Not Applicable'
|
||||
and private_ip_address_indicator = 'Not Applicable'
|
||||
and dns_name = '0.blue.green'
|
||||
and ip4_address = 'Not Applicable'
|
||||
and ip6_address = 'Not Applicable';
|
||||
|
||||
-- expected wh_network_address_group_membership has three rows: '8.6.4.2' & 'fe60::6667:5556:4445:3334' & '0.blue.green'
|
||||
select is(count(*), 3::bigint)
|
||||
from wh_network_address_group_membership gm,
|
||||
wh_host_dimension h
|
||||
where h.network_address_group_key = gm.network_address_group_key
|
||||
and h.host_id = 'Not Applicable'
|
||||
and h.host_set_id = 'Not Applicable'
|
||||
and h.host_catalog_id = 'Not Applicable'
|
||||
and h.target_id = 't_________wb';
|
||||
|
||||
-- create second session with the same resources
|
||||
insert into session
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's4____walter');
|
||||
insert into session_target_address
|
||||
(session_id, target_id)
|
||||
values
|
||||
('s4____walter', 't_________wb');
|
||||
|
||||
-- should not result in a new host dimension
|
||||
select is(count(*), 1::bigint) from wh_host_dimension where organization_id = 'o_____widget';
|
||||
|
||||
-- expected wh_network_address_group_membership does not change.
|
||||
select is(count(*), 3::bigint)
|
||||
from wh_network_address_group_membership gm,
|
||||
wh_host_dimension h
|
||||
where h.network_address_group_key = gm.network_address_group_key
|
||||
and h.host_id = 'Not Applicable'
|
||||
and h.host_set_id = 'Not Applicable'
|
||||
and h.host_catalog_id = 'Not Applicable'
|
||||
and h.target_id = 't_________wb';
|
||||
|
||||
select * from finish();
|
||||
rollback;
|
||||
@@ -10,9 +10,13 @@ begin;
|
||||
|
||||
-- insert first session, should result in a new host dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-plghs' , 'h_____wb__01-plgh' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-plghs', 'h_____wb__01-plgh');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_host_dimension where organization_id = 'o_____widget';
|
||||
|
||||
|
||||
@@ -9,9 +9,13 @@ begin;
|
||||
|
||||
-- insert first session, should result in a new wh_session_accumulating_fact
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_session_accumulating_fact where session_id = 's1____walter';
|
||||
|
||||
|
||||
@@ -8,10 +8,13 @@ begin;
|
||||
select is(count(*), 0::bigint) from wh_session_connection_accumulating_fact where connection_id = 'sc1____walter';
|
||||
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
insert into session_connection
|
||||
(session_id, public_id)
|
||||
values
|
||||
|
||||
@@ -10,10 +10,13 @@ begin;
|
||||
|
||||
--- insert single credential
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p____bwidget', 't_________wb', 's___1wb-sths', 'h_____wb__01', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's1____walter');
|
||||
|
||||
('p____bwidget', 't_________wb', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
insert into session_credential_dynamic
|
||||
( session_id, library_id, credential_id, credential_purpose)
|
||||
values
|
||||
|
||||
@@ -10,9 +10,13 @@ begin;
|
||||
|
||||
--- multiple single credentials
|
||||
insert into session
|
||||
( project_id, target_id, host_set_id, host_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
( project_id, target_id, user_id, auth_token_id, certificate, endpoint, public_id)
|
||||
values
|
||||
('p____bwidget', 't_________wb', 's___1wb-sths', 'h_____wb__01', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's1____walter');
|
||||
('p____bwidget', 't_________wb', 'u_____walter', 'tok___walter', 'abc'::bytea, 'ep1', 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
insert into session_credential_dynamic
|
||||
( session_id, library_id, credential_id, credential_purpose)
|
||||
values
|
||||
|
||||
@@ -10,9 +10,13 @@ begin;
|
||||
|
||||
-- insert first session, should result in a new user dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'oidc__walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'oidc__walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_user_dimension where user_id = 'u_____walter';
|
||||
select is(user_id, 'u_____walter') from wh_user_dimension where user_id = 'u_____walter';
|
||||
@@ -41,9 +45,13 @@ begin;
|
||||
|
||||
-- insert session without full name or email
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____warren' , 'oidc__warren' , 'abc'::bytea , 'ep1' , 's1____warren');
|
||||
('p____bwidget' , 't_________wb' , 'u_____warren' , 'oidc__warren' , 'abc'::bytea , 'ep1' , 's1____warren');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____warren', 's___1wb-sths', 'h_____wb__01');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_user_dimension where user_id = 'u_____warren';
|
||||
select is(user_name, 'Warren') from wh_user_dimension where user_id = 'u_____warren';
|
||||
|
||||
@@ -11,9 +11,13 @@ begin;
|
||||
|
||||
-- insert first session, should result in a new user dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_user_dimension where user_id = 'u_____walter';
|
||||
select is(user_id, 'u_____walter') from wh_user_dimension where user_id = 'u_____walter';
|
||||
@@ -52,9 +56,13 @@ begin;
|
||||
-- * same host
|
||||
-- should result in a new user dimension due to auth change.
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's2____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's2____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s2____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
|
||||
select is(count(*), 2::bigint) from wh_user_dimension where user_organization_id = 'o_____widget';
|
||||
|
||||
|
||||
@@ -10,9 +10,13 @@ begin;
|
||||
|
||||
-- insert first session, should result in a new user dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_user_dimension where user_id = 'u_____walter';
|
||||
select is(user_id, 'u_____walter') from wh_user_dimension where user_id = 'u_____walter';
|
||||
|
||||
@@ -10,9 +10,13 @@ begin;
|
||||
|
||||
-- insert first session, should result in a new user dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_user_dimension where user_organization_id = 'o_____widget';
|
||||
|
||||
@@ -22,9 +26,13 @@ begin;
|
||||
-- * same host
|
||||
-- should not result in a new user dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's2____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's2____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s2____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_user_dimension where user_organization_id = 'o_____widget';
|
||||
|
||||
@@ -34,9 +42,13 @@ begin;
|
||||
-- * different host
|
||||
-- should not result in a new user dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__02' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's3____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's3____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s3____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_user_dimension where user_organization_id = 'o_____widget';
|
||||
|
||||
|
||||
+12
-4
@@ -11,9 +11,13 @@ begin;
|
||||
|
||||
-- insert first session, should result in a new user dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_user_dimension where user_organization_id = 'o_____widget';
|
||||
|
||||
@@ -23,9 +27,13 @@ begin;
|
||||
-- * same host
|
||||
-- should result in a new user dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok1__walter' , 'abc'::bytea , 'ep1' , 's4____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok1__walter' , 'abc'::bytea , 'ep1' , 's4____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s4____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
|
||||
select is(count(*), 2::bigint) from wh_user_dimension where user_organization_id = 'o_____widget';
|
||||
select is(count(*), 1::bigint) from wh_user_dimension where user_id = 'u_____walter' and auth_account_id = 'apa1__walter';
|
||||
|
||||
@@ -10,9 +10,13 @@ begin;
|
||||
|
||||
-- insert first session, should result in a new user dimension
|
||||
insert into session
|
||||
( project_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
( project_id , target_id , user_id , auth_token_id , certificate , endpoint , public_id)
|
||||
values
|
||||
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
('p____bwidget' , 't_________wb' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
('s1____walter', 's___1wb-sths', 'h_____wb__01');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_user_dimension where user_organization_id = 'o_____widget';
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ const (
|
||||
// client and server error codes
|
||||
Unauthorized Code = 401 // Unauthorized represents the operation is unauthorized
|
||||
Forbidden Code = 403 // Forbidden represents the operation is forbidden
|
||||
Conflict Code = 409 // Conflict represents the operation failed due to failed pre-condition or was aborted.
|
||||
Internal Code = 500 // InternalError represents the system encountered an unexpected condition.
|
||||
|
||||
// DB errors are reserved Codes from 1000-1999
|
||||
|
||||
@@ -152,6 +152,10 @@ var errorCodeInfo = map[Code]Info{
|
||||
Message: "unauthorized",
|
||||
Kind: Other,
|
||||
},
|
||||
Conflict: {
|
||||
Message: "conflict",
|
||||
Kind: Integrity,
|
||||
},
|
||||
CheckConstraint: {
|
||||
Message: "constraint check failed",
|
||||
Kind: Integrity,
|
||||
|
||||
@@ -94,3 +94,13 @@ func IsNotFoundError(err error) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// IsConflictError returns a boolean indicating whether the error is known to
|
||||
// report a pre-conditional check violation or an aborted transaction.
|
||||
func IsConflictError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return Match(T(Conflict), err)
|
||||
}
|
||||
@@ -3062,7 +3062,7 @@
|
||||
},
|
||||
"/v1/targets/{id}:add-host-sources": {
|
||||
"post": {
|
||||
"summary": "Adds existing Host Sources to a Target.",
|
||||
"summary": "Adds existing Host Sources to a Target. Cannot be used on targets that have their address field set.",
|
||||
"operationId": "TargetService_AddTargetHostSources",
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -3329,7 +3329,7 @@
|
||||
},
|
||||
"/v1/targets/{id}:set-host-sources": {
|
||||
"post": {
|
||||
"summary": "Sources the Host Sources on the Target.",
|
||||
"summary": "Sources the Host Sources on the Target. Cannot be used on targets that have their address field set.",
|
||||
"operationId": "TargetService_SetTargetHostSources",
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -5710,6 +5710,10 @@
|
||||
},
|
||||
"description": "Output only. The available actions on this resource for this user.",
|
||||
"readOnly": true
|
||||
},
|
||||
"address": {
|
||||
"type": "string",
|
||||
"description": "Optional string value that represents a network resource and is used when establishing a session."
|
||||
}
|
||||
},
|
||||
"title": "Target contains all fields related to a Target resource"
|
||||
|
||||
@@ -1619,7 +1619,7 @@ var file_controller_api_services_v1_target_service_proto_rawDesc = []byte{
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65,
|
||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
|
||||
0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x32, 0x99, 0x14,
|
||||
0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x32, 0x95, 0x15,
|
||||
0x0a, 0x0d, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||
0xa2, 0x01, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x2c, 0x2e,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73,
|
||||
@@ -1686,7 +1686,7 @@ var file_controller_api_services_v1_target_service_proto_rawDesc = []byte{
|
||||
0x6f, 0x6e, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x22, 0x22, 0x2f, 0x76, 0x31, 0x2f, 0x74,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x75, 0x74, 0x68,
|
||||
0x6f, 0x72, 0x69, 0x7a, 0x65, 0x2d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x01, 0x2a,
|
||||
0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0xe9, 0x01, 0x0a, 0x14, 0x41, 0x64, 0x64, 0x54, 0x61,
|
||||
0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0xa7, 0x02, 0x0a, 0x14, 0x41, 0x64, 0x64, 0x54, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12,
|
||||
0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64,
|
||||
@@ -1695,99 +1695,107 @@ var file_controller_api_services_v1_target_service_proto_rawDesc = []byte{
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48,
|
||||
0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x5e, 0x92, 0x41, 0x29, 0x12, 0x27, 0x41, 0x64, 0x64, 0x73, 0x20, 0x65, 0x78,
|
||||
0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e,
|
||||
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x22, 0x21, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67,
|
||||
0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x64, 0x64, 0x2d, 0x68, 0x6f, 0x73,
|
||||
0x74, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74,
|
||||
0x65, 0x6d, 0x12, 0xe9, 0x01, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x37, 0x2e, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67,
|
||||
0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53,
|
||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5e,
|
||||
0x92, 0x41, 0x29, 0x12, 0x27, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65,
|
||||
0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x6f, 0x6e,
|
||||
0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x82, 0xd3, 0xe4, 0x93,
|
||||
0x02, 0x2c, 0x22, 0x21, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f,
|
||||
0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x73, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0xf3,
|
||||
0x01, 0x0a, 0x17, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48,
|
||||
0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x73, 0x65, 0x22, 0x9b, 0x01, 0x92, 0x41, 0x66, 0x12, 0x64, 0x41, 0x64, 0x64, 0x73, 0x20, 0x65,
|
||||
0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x2e, 0x20, 0x43, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64,
|
||||
0x20, 0x6f, 0x6e, 0x20, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74,
|
||||
0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x61, 0x64, 0x64, 0x72,
|
||||
0x65, 0x73, 0x73, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x73, 0x65, 0x74, 0x2e, 0x82, 0xd3,
|
||||
0xe4, 0x93, 0x02, 0x2c, 0x22, 0x21, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x64, 0x64, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x2d,
|
||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d,
|
||||
0x12, 0xa7, 0x02, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f,
|
||||
0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||
0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x9b, 0x01, 0x92,
|
||||
0x41, 0x66, 0x12, 0x64, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
|
||||
0x48, 0x6f, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x6f, 0x6e, 0x20,
|
||||
0x74, 0x68, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x20, 0x43, 0x61, 0x6e, 0x6e,
|
||||
0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20,
|
||||
0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x66, 0x69,
|
||||
0x65, 0x6c, 0x64, 0x20, 0x73, 0x65, 0x74, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x22, 0x21,
|
||||
0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d,
|
||||
0x3a, 0x73, 0x65, 0x74, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||
0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0xf3, 0x01, 0x0a, 0x17, 0x52,
|
||||
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53,
|
||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x22, 0x5f, 0x92, 0x41, 0x27, 0x12, 0x25, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
||||
0x73, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x66,
|
||||
0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x82,
|
||||
0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x22, 0x24, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x2d, 0x68,
|
||||
0x6f, 0x73, 0x74, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04,
|
||||
0x69, 0x74, 0x65, 0x6d, 0x12, 0x87, 0x02, 0x0a, 0x1a, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67,
|
||||
0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x73, 0x12, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e,
|
||||
0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
|
||||
0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x6a, 0x92, 0x41, 0x2f, 0x12, 0x2d, 0x41, 0x64, 0x64, 0x73, 0x20, 0x65, 0x78,
|
||||
0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61,
|
||||
0x6c, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x54,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x22, 0x27, 0x2f, 0x76,
|
||||
0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x61,
|
||||
0x64, 0x64, 0x2d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x73, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x84,
|
||||
0x02, 0x0a, 0x1a, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3d, 0x2e,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73,
|
||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72,
|
||||
0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x67, 0x92, 0x41,
|
||||
0x2c, 0x12, 0x2a, 0x53, 0x65, 0x74, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x72, 0x65, 0x64,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x6f,
|
||||
0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x82, 0xd3, 0xe4,
|
||||
0x93, 0x02, 0x32, 0x22, 0x27, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73,
|
||||
0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x2d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e,
|
||||
0x74, 0x69, 0x61, 0x6c, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62,
|
||||
0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x91, 0x02, 0x0a, 0x1d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
|
||||
0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74,
|
||||
0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x5f, 0x92, 0x41, 0x27, 0x12, 0x25, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0x20, 0x48, 0x6f,
|
||||
0x73, 0x74, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20,
|
||||
0x74, 0x68, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02,
|
||||
0x2f, 0x22, 0x24, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b,
|
||||
0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x2d,
|
||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d,
|
||||
0x12, 0x87, 0x02, 0x0a, 0x1a, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72,
|
||||
0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12,
|
||||
0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64,
|
||||
0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c,
|
||||
0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x40, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||
0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63,
|
||||
0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x41, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3e,
|
||||
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53,
|
||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6a,
|
||||
0x92, 0x41, 0x2f, 0x12, 0x2d, 0x41, 0x64, 0x64, 0x73, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x22, 0x27, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x64, 0x64, 0x2d, 0x63,
|
||||
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||
0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x84, 0x02, 0x0a, 0x1a, 0x53,
|
||||
0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69,
|
||||
0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||
0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72,
|
||||
0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6b, 0x92, 0x41,
|
||||
0x2d, 0x12, 0x2b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x66, 0x72,
|
||||
0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x82, 0xd3,
|
||||
0xe4, 0x93, 0x02, 0x35, 0x22, 0x2a, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x2d, 0x63, 0x72,
|
||||
0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
|
||||
0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x42, 0x57, 0x5a, 0x4b, 0x67, 0x69, 0x74,
|
||||
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72,
|
||||
0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72,
|
||||
0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b,
|
||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0xa2, 0xe3, 0x29, 0x06, 0x74, 0x61, 0x72, 0x67,
|
||||
0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43,
|
||||
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x67, 0x92, 0x41, 0x2c, 0x12, 0x2a, 0x53,
|
||||
0x65, 0x74, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69,
|
||||
0x61, 0x6c, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
|
||||
0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x22,
|
||||
0x27, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64,
|
||||
0x7d, 0x3a, 0x73, 0x65, 0x74, 0x2d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c,
|
||||
0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65,
|
||||
0x6d, 0x12, 0x91, 0x02, 0x0a, 0x1d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67,
|
||||
0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x73, 0x12, 0x40, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65,
|
||||
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x41, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43,
|
||||
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6b, 0x92, 0x41, 0x2d, 0x12, 0x2b, 0x52,
|
||||
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61,
|
||||
0x6c, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74,
|
||||
0x68, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x35,
|
||||
0x22, 0x2a, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69,
|
||||
0x64, 0x7d, 0x3a, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x2d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e,
|
||||
0x74, 0x69, 0x61, 0x6c, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62,
|
||||
0x04, 0x69, 0x74, 0x65, 0x6d, 0x42, 0x57, 0x5a, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f,
|
||||
0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
|
||||
0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61,
|
||||
0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x73, 0xa2, 0xe3, 0x29, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -53,8 +53,9 @@ type TargetServiceClient interface {
|
||||
// Host Sources added to the provided Target must be a child of a Catalog that
|
||||
// is a child of the same scope as this Target. If the scope or Target IDs are
|
||||
// missing, malformed, or reference non-existing resources, an error is
|
||||
// returned. An error is returned if a Host Source is attempted to be added to a
|
||||
// target that is already present on the Target.
|
||||
// returned. An error is returned if a Host Source is attempted to be added to
|
||||
// a target that is already present on the Target. If the given target already
|
||||
// has its address field set, a Bad Request error is returned.
|
||||
AddTargetHostSources(ctx context.Context, in *AddTargetHostSourcesRequest, opts ...grpc.CallOption) (*AddTargetHostSourcesResponse, error)
|
||||
// SetTargetHostSources sets the Target's Host Sources. Any existing Host
|
||||
// Sources on the Target are deleted if they are not included in this request.
|
||||
@@ -62,7 +63,8 @@ type TargetServiceClient interface {
|
||||
// Host Sources will be set. All Host Sources in the request must be a child
|
||||
// of a Catalog that is in the same scope as the provided Target. If any IDs
|
||||
// are missing, malformed, or references a non-existing resource, an error is
|
||||
// returned.
|
||||
// returned. If the given target already has its address field set, a Bad
|
||||
// Request error is returned.
|
||||
SetTargetHostSources(ctx context.Context, in *SetTargetHostSourcesRequest, opts ...grpc.CallOption) (*SetTargetHostSourcesResponse, error)
|
||||
// RemoveTargetHostSources removes the Host Sources from the specified Target.
|
||||
// The provided request must include the Target ID for the Target from which
|
||||
@@ -252,8 +254,9 @@ type TargetServiceServer interface {
|
||||
// Host Sources added to the provided Target must be a child of a Catalog that
|
||||
// is a child of the same scope as this Target. If the scope or Target IDs are
|
||||
// missing, malformed, or reference non-existing resources, an error is
|
||||
// returned. An error is returned if a Host Source is attempted to be added to a
|
||||
// target that is already present on the Target.
|
||||
// returned. An error is returned if a Host Source is attempted to be added to
|
||||
// a target that is already present on the Target. If the given target already
|
||||
// has its address field set, a Bad Request error is returned.
|
||||
AddTargetHostSources(context.Context, *AddTargetHostSourcesRequest) (*AddTargetHostSourcesResponse, error)
|
||||
// SetTargetHostSources sets the Target's Host Sources. Any existing Host
|
||||
// Sources on the Target are deleted if they are not included in this request.
|
||||
@@ -261,7 +264,8 @@ type TargetServiceServer interface {
|
||||
// Host Sources will be set. All Host Sources in the request must be a child
|
||||
// of a Catalog that is in the same scope as the provided Target. If any IDs
|
||||
// are missing, malformed, or references a non-existing resource, an error is
|
||||
// returned.
|
||||
// returned. If the given target already has its address field set, a Bad
|
||||
// Request error is returned.
|
||||
SetTargetHostSources(context.Context, *SetTargetHostSourcesRequest) (*SetTargetHostSourcesResponse, error)
|
||||
// RemoveTargetHostSources removes the Host Sources from the specified Target.
|
||||
// The provided request must include the Target ID for the Target from which
|
||||
|
||||
@@ -211,6 +211,16 @@ message Target {
|
||||
// Output only. The available actions on this resource for this user.
|
||||
repeated string authorized_actions = 300 [json_name = "authorized_actions"]; // @gotags: `class:"public"`
|
||||
|
||||
// Optional string value that represents a network resource and is used when establishing a session.
|
||||
google.protobuf.StringValue address = 540 [
|
||||
json_name = "address",
|
||||
(custom_options.v1.generate_sdk_option) = true,
|
||||
(custom_options.v1.mask_mapping) = {
|
||||
this: "address"
|
||||
that: "address"
|
||||
}
|
||||
]; // @gotags: `class:"public"`
|
||||
|
||||
// Deprecated fields
|
||||
reserved "application_credential_library_ids", "application_credential_libraries";
|
||||
reserved 150, 180;
|
||||
|
||||
@@ -102,8 +102,9 @@ service TargetService {
|
||||
// Host Sources added to the provided Target must be a child of a Catalog that
|
||||
// is a child of the same scope as this Target. If the scope or Target IDs are
|
||||
// missing, malformed, or reference non-existing resources, an error is
|
||||
// returned. An error is returned if a Host Source is attempted to be added to a
|
||||
// target that is already present on the Target.
|
||||
// returned. An error is returned if a Host Source is attempted to be added to
|
||||
// a target that is already present on the Target. If the given target already
|
||||
// has its address field set, a Bad Request error is returned.
|
||||
rpc AddTargetHostSources(AddTargetHostSourcesRequest) returns (AddTargetHostSourcesResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1/targets/{id}:add-host-sources"
|
||||
@@ -111,7 +112,7 @@ service TargetService {
|
||||
response_body: "item"
|
||||
};
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
summary: "Adds existing Host Sources to a Target."
|
||||
summary: "Adds existing Host Sources to a Target. Cannot be used on targets that have their address field set."
|
||||
};
|
||||
}
|
||||
|
||||
@@ -121,7 +122,8 @@ service TargetService {
|
||||
// Host Sources will be set. All Host Sources in the request must be a child
|
||||
// of a Catalog that is in the same scope as the provided Target. If any IDs
|
||||
// are missing, malformed, or references a non-existing resource, an error is
|
||||
// returned.
|
||||
// returned. If the given target already has its address field set, a Bad
|
||||
// Request error is returned.
|
||||
rpc SetTargetHostSources(SetTargetHostSourcesRequest) returns (SetTargetHostSourcesResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1/targets/{id}:set-host-sources"
|
||||
@@ -129,7 +131,7 @@ service TargetService {
|
||||
response_body: "item"
|
||||
};
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
summary: "Sources the Host Sources on the Target."
|
||||
summary: "Sources the Host Sources on the Target. Cannot be used on targets that have their address field set."
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ extend google.protobuf.FieldOptions {
|
||||
MaskMapping mask_mapping = 85464;
|
||||
|
||||
// generate_sdk_option is a directive used when generating the SDK to
|
||||
// indicate that an option should be created for the field
|
||||
// indicate that an option should be created for the field. This also controls
|
||||
// API options (DefaultX, WithX functions).
|
||||
bool generate_sdk_option = 85412;
|
||||
|
||||
// subtype is used for oneOf attribute subtypes, to identify that we only need to parse attributes
|
||||
|
||||
@@ -2,6 +2,7 @@ syntax = "proto3";
|
||||
|
||||
package controller.storage.target.store.v1;
|
||||
|
||||
import "controller/custom_options/v1/options.proto";
|
||||
import "controller/storage/timestamp/v1/timestamp.proto";
|
||||
|
||||
option go_package = "github.com/hashicorp/boundary/internal/target/store;store";
|
||||
@@ -79,6 +80,19 @@ message TargetHostSet {
|
||||
timestamp.v1.Timestamp create_time = 30;
|
||||
}
|
||||
|
||||
message TargetAddress {
|
||||
// target_id of the Target
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
string target_id = 10;
|
||||
|
||||
// address associated to the Target
|
||||
// @inject_tag: `gorm:"not_null"`
|
||||
string address = 20 [(custom_options.v1.mask_mapping) = {
|
||||
this: "address"
|
||||
that: "address"
|
||||
}];
|
||||
}
|
||||
|
||||
message CredentialLibrary {
|
||||
// target_id of the Target
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
|
||||
@@ -34,21 +34,18 @@ func (r *Repository) CreateSession(ctx context.Context, sessionWrapper wrapping.
|
||||
if newSession.TargetId == "" {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing target id")
|
||||
}
|
||||
if newSession.HostId == "" {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing host id")
|
||||
}
|
||||
if newSession.UserId == "" {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing user id")
|
||||
}
|
||||
if newSession.HostSetId == "" {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing host set id")
|
||||
}
|
||||
if newSession.AuthTokenId == "" {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing auth token id")
|
||||
}
|
||||
if newSession.ProjectId == "" {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing project id")
|
||||
}
|
||||
if newSession.HostId == "" && newSession.HostSetId == "" && newSession.Endpoint == "" {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing host source and endpoint")
|
||||
}
|
||||
if newSession.CtTofuToken != nil {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "ct is not empty")
|
||||
}
|
||||
@@ -91,6 +88,26 @@ func (r *Repository) CreateSession(ctx context.Context, sessionWrapper wrapping.
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
if newSession.HostSetId != "" && newSession.HostId != "" {
|
||||
hs, err := NewSessionHostSetHost(newSession.PublicId, newSession.HostSetId, newSession.HostId)
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if err = w.Create(ctx, hs); err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
returnedSession.HostSetId = hs.HostSetId
|
||||
returnedSession.HostId = hs.HostId
|
||||
} else if newSession.Endpoint != "" {
|
||||
ta, err := NewSessionTargetAddress(newSession.PublicId, newSession.TargetId)
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if err = w.Create(ctx, ta); err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
}
|
||||
|
||||
for _, cred := range newSession.DynamicCredentials {
|
||||
cred.SessionId = newSession.PublicId
|
||||
}
|
||||
@@ -197,6 +214,13 @@ func (r *Repository) LookupSession(ctx context.Context, sessionId string, opt ..
|
||||
session.StaticCredentials = staticCreds
|
||||
}
|
||||
|
||||
sessionHostSetHost := AllocSessionHostSetHost()
|
||||
if err := read.LookupWhere(ctx, sessionHostSetHost, "session_id = ?", []any{sessionId}); err != nil && !errors.IsNotFoundError(err) {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
session.HostSetId = sessionHostSetHost.HostSetId
|
||||
session.HostId = sessionHostSetHost.HostId
|
||||
|
||||
connections, err := fetchConnections(ctx, read, sessionId, db.WithOrder("create_time desc"))
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
@@ -583,6 +607,12 @@ func (r *Repository) updateState(ctx context.Context, sessionId string, sessionV
|
||||
if len(returnedStates) < 1 && returnedStates[0].Status != s {
|
||||
return errors.New(ctx, errors.InvalidSessionState, op, fmt.Sprintf("failed to update %s to a state of %s", sessionId, s.String()))
|
||||
}
|
||||
hostSetHost, err := fetchHostSetHost(ctx, reader, sessionId)
|
||||
if err != nil && !errors.IsNotFoundError(err) {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
updatedSession.HostId = hostSetHost.HostId
|
||||
updatedSession.HostSetId = hostSetHost.HostSetId
|
||||
return nil
|
||||
},
|
||||
)
|
||||
@@ -683,6 +713,15 @@ func fetchConnections(ctx context.Context, r db.Reader, sessionId string, opt ..
|
||||
return connections, nil
|
||||
}
|
||||
|
||||
func fetchHostSetHost(ctx context.Context, r db.Reader, sessionId string, opt ...db.Option) (*SessionHostSetHost, error) {
|
||||
const op = "session.fetchHostSetHost"
|
||||
var hostSetHost *SessionHostSetHost
|
||||
if err := r.SearchWhere(ctx, &hostSetHost, "session_id = ?", []any{sessionId}, opt...); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
return hostSetHost, nil
|
||||
}
|
||||
|
||||
// decryptAndMaybeUpdateSession switches between the database key and session key based on whether
|
||||
// the session uses a legacy private key or not. It also updates the encrypted session
|
||||
// in the database (if necessary). Eventually we should be able to remove this function
|
||||
|
||||
@@ -307,6 +307,29 @@ func TestRepository_CreateSession(t *testing.T) {
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid-static-address",
|
||||
args: args{
|
||||
composedOf: TestSessionTargetAddressParams(t, conn, wrapper, iamRepo),
|
||||
workerAddresses: workerAddresses,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty-host-source-endpoint",
|
||||
args: args{
|
||||
composedOf: func() ComposedOf {
|
||||
c := TestSessionParams(t, conn, wrapper, iamRepo)
|
||||
c.HostId = ""
|
||||
c.HostSetId = ""
|
||||
c.Endpoint = ""
|
||||
return c
|
||||
}(),
|
||||
workerAddresses: workerAddresses,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-userId",
|
||||
args: args{
|
||||
@@ -320,19 +343,6 @@ func TestRepository_CreateSession(t *testing.T) {
|
||||
wantErr: true,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-hostId",
|
||||
args: args{
|
||||
composedOf: func() ComposedOf {
|
||||
c := TestSessionParams(t, conn, wrapper, iamRepo)
|
||||
c.HostId = ""
|
||||
return c
|
||||
}(),
|
||||
workerAddresses: workerAddresses,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-targetId",
|
||||
args: args{
|
||||
@@ -346,19 +356,6 @@ func TestRepository_CreateSession(t *testing.T) {
|
||||
wantErr: true,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-hostSetId",
|
||||
args: args{
|
||||
composedOf: func() ComposedOf {
|
||||
c := TestSessionParams(t, conn, wrapper, iamRepo)
|
||||
c.HostSetId = ""
|
||||
return c
|
||||
}(),
|
||||
workerAddresses: workerAddresses,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsError: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-authTokenId",
|
||||
args: args{
|
||||
@@ -440,7 +437,7 @@ func TestRepository_CreateSession(t *testing.T) {
|
||||
HostSetId: tt.args.composedOf.HostSetId,
|
||||
AuthTokenId: tt.args.composedOf.AuthTokenId,
|
||||
ProjectId: tt.args.composedOf.ProjectId,
|
||||
Endpoint: "tcp://127.0.0.1:22",
|
||||
Endpoint: tt.args.composedOf.Endpoint,
|
||||
ExpirationTime: tt.args.composedOf.ExpirationTime,
|
||||
ConnectionLimit: tt.args.composedOf.ConnectionLimit,
|
||||
DynamicCredentials: tt.args.composedOf.DynamicCredentials,
|
||||
@@ -1254,19 +1251,19 @@ func TestRepository_CancelSessionViaFKNull(t *testing.T) {
|
||||
name: "canceled-only-once",
|
||||
cancelFk: func() cancelFk {
|
||||
s := setupFn()
|
||||
var err error
|
||||
s, err = repo.CancelSession(context.Background(), s.PublicId, s.Version)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, StatusCanceling, s.States[0].Status)
|
||||
|
||||
t := &static.Host{
|
||||
h := &static.Host{
|
||||
Host: &staticStore.Host{
|
||||
PublicId: s.HostId,
|
||||
},
|
||||
}
|
||||
|
||||
var err error
|
||||
s, err = repo.CancelSession(context.Background(), s.PublicId, s.Version)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, StatusCanceling, s.States[0].Status)
|
||||
return cancelFk{
|
||||
s: s,
|
||||
fkType: t,
|
||||
fkType: h,
|
||||
}
|
||||
}(),
|
||||
},
|
||||
|
||||
@@ -68,12 +68,8 @@ type Session struct {
|
||||
PublicId string `json:"public_id,omitempty" gorm:"primary_key"`
|
||||
// UserId for the session
|
||||
UserId string `json:"user_id,omitempty" gorm:"default:null"`
|
||||
// HostId of the session
|
||||
HostId string `json:"host_id,omitempty" gorm:"default:null"`
|
||||
// TargetId for the session
|
||||
TargetId string `json:"target_id,omitempty" gorm:"default:null"`
|
||||
// HostSetId for the session
|
||||
HostSetId string `json:"host_set_id,omitempty" gorm:"default:null"`
|
||||
// AuthTokenId for the session
|
||||
AuthTokenId string `json:"auth_token_id,omitempty" gorm:"default:null"`
|
||||
// ProjectId for the session
|
||||
@@ -124,6 +120,12 @@ type Session struct {
|
||||
// StaticCredentials for the session.
|
||||
StaticCredentials []*StaticCredential `gorm:"-"`
|
||||
|
||||
// HostSetId for the session
|
||||
HostSetId string `gorm:"-"`
|
||||
|
||||
// HostId of the session
|
||||
HostId string `gorm:"-"`
|
||||
|
||||
// Connections for the session are for read only and are ignored during write operations
|
||||
Connections []*Connection `gorm:"-"`
|
||||
|
||||
@@ -347,15 +349,9 @@ func (s *Session) validateNewSession() error {
|
||||
if s.UserId == "" {
|
||||
return errors.NewDeprecated(errors.InvalidParameter, op, "missing user id")
|
||||
}
|
||||
if s.HostId == "" {
|
||||
return errors.NewDeprecated(errors.InvalidParameter, op, "missing host id")
|
||||
}
|
||||
if s.TargetId == "" {
|
||||
return errors.NewDeprecated(errors.InvalidParameter, op, "missing target id")
|
||||
}
|
||||
if s.HostSetId == "" {
|
||||
return errors.NewDeprecated(errors.InvalidParameter, op, "missing host set id")
|
||||
}
|
||||
if s.AuthTokenId == "" {
|
||||
return errors.NewDeprecated(errors.InvalidParameter, op, "missing auth token id")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package session
|
||||
|
||||
import "github.com/hashicorp/boundary/internal/errors"
|
||||
|
||||
const (
|
||||
defaultSessionHostSetHostTableName = "session_host_set_host"
|
||||
)
|
||||
|
||||
// SessionHostSetHost contains information about a user's session with a target that has a host source association.
|
||||
type SessionHostSetHost struct {
|
||||
// SessionId of the session
|
||||
SessionId string `json:"session_id,omitempty" gorm:"primary_key"`
|
||||
// HostSetId of the session
|
||||
HostSetId string `json:"host_set_id,omitempty" gorm:"default:null"`
|
||||
// HostId of the session
|
||||
HostId string `json:"host_id,omitempty" gorm:"default:null"`
|
||||
|
||||
tableName string `gorm:"-"`
|
||||
}
|
||||
|
||||
// NewSessionHostSetHost creates a new in memory session to host set & host association.
|
||||
func NewSessionHostSetHost(sessionId, hostSetId, hostId string) (*SessionHostSetHost, error) {
|
||||
const op = "session.NewSessionHostSetHost"
|
||||
if sessionId == "" {
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing session id")
|
||||
}
|
||||
if hostSetId == "" {
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing host set id")
|
||||
}
|
||||
if hostId == "" {
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing host id")
|
||||
}
|
||||
shs := &SessionHostSetHost{
|
||||
SessionId: sessionId,
|
||||
HostSetId: hostSetId,
|
||||
HostId: hostId,
|
||||
}
|
||||
return shs, nil
|
||||
}
|
||||
|
||||
// TableName returns the tablename to override the default gorm table name
|
||||
func (s *SessionHostSetHost) TableName() string {
|
||||
if s.tableName != "" {
|
||||
return s.tableName
|
||||
}
|
||||
return defaultSessionHostSetHostTableName
|
||||
}
|
||||
|
||||
// SetTableName sets the tablename and satisfies the ReplayableMessage
|
||||
// interface. If the caller attempts to set the name to "" the name will be
|
||||
// reset to the default name.
|
||||
func (s *SessionHostSetHost) SetTableName(n string) {
|
||||
s.tableName = n
|
||||
}
|
||||
|
||||
// AllocSessionHostSet will allocate a SessionHostSetHost
|
||||
func AllocSessionHostSetHost() *SessionHostSetHost {
|
||||
return &SessionHostSetHost{}
|
||||
}
|
||||
|
||||
// Clone creates a clone of the SessionHostSetHost
|
||||
func (s *SessionHostSetHost) Clone() any {
|
||||
clone := &SessionHostSetHost{
|
||||
SessionId: s.SessionId,
|
||||
HostSetId: s.HostSetId,
|
||||
HostId: s.HostId,
|
||||
}
|
||||
return clone
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package session
|
||||
|
||||
import "github.com/hashicorp/boundary/internal/errors"
|
||||
|
||||
const (
|
||||
defaultSessionTargetAddressTableName = "session_target_address"
|
||||
)
|
||||
|
||||
// SessionTargetAddress contains information about a user's session with a target that has a direct network address association.
|
||||
type SessionTargetAddress struct {
|
||||
// SessionId of the session
|
||||
SessionId string `json:"session_id,omitempty" gorm:"primary_key"`
|
||||
// TargetId of the session
|
||||
TargetId string `json:"target_id,omitempty" gorm:"default:null"`
|
||||
|
||||
tableName string `gorm:"-"`
|
||||
}
|
||||
|
||||
// NewSessionTargetAddress creates a new in memory session target address.
|
||||
func NewSessionTargetAddress(sessionId, targetId string) (*SessionTargetAddress, error) {
|
||||
const op = "sesssion.NewSessionTargetAddress"
|
||||
if sessionId == "" {
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing session id")
|
||||
}
|
||||
if targetId == "" {
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing target id")
|
||||
}
|
||||
sta := &SessionTargetAddress{
|
||||
SessionId: sessionId,
|
||||
TargetId: targetId,
|
||||
}
|
||||
return sta, nil
|
||||
}
|
||||
|
||||
// TableName returns the tablename to override the default gorm table name
|
||||
func (s *SessionTargetAddress) TableName() string {
|
||||
if s.tableName != "" {
|
||||
return s.tableName
|
||||
}
|
||||
return defaultSessionTargetAddressTableName
|
||||
}
|
||||
|
||||
// SetTableName sets the tablename and satisfies the ReplayableMessage
|
||||
// interface. If the caller attempts to set the name to "" the name will be
|
||||
// reset to the default name.
|
||||
func (s *SessionTargetAddress) SetTableName(n string) {
|
||||
s.tableName = n
|
||||
}
|
||||
|
||||
// AllocSessionTargetAddress will allocate a SessionTargetAddress
|
||||
func AllocSessionTargetAddress() *SessionTargetAddress {
|
||||
return &SessionTargetAddress{}
|
||||
}
|
||||
|
||||
// Clone creates a clone of the SessionTargetAddress
|
||||
func (s *SessionTargetAddress) Clone() any {
|
||||
clone := &SessionTargetAddress{
|
||||
SessionId: s.SessionId,
|
||||
TargetId: s.TargetId,
|
||||
}
|
||||
return clone
|
||||
}
|
||||
@@ -45,7 +45,7 @@ func TestSession_Create(t *testing.T) {
|
||||
wantCreateErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
name: "valid-hostset-host",
|
||||
args: args{
|
||||
composedOf: composedOf,
|
||||
opt: []Option{WithExpirationTime(exp)},
|
||||
@@ -66,6 +66,48 @@ func TestSession_Create(t *testing.T) {
|
||||
},
|
||||
create: true,
|
||||
},
|
||||
{
|
||||
name: "valid-target-address",
|
||||
args: args{
|
||||
composedOf: func() ComposedOf {
|
||||
c := composedOf
|
||||
c.HostSetId = ""
|
||||
c.HostId = ""
|
||||
return c
|
||||
}(),
|
||||
opt: []Option{WithExpirationTime(exp)},
|
||||
addresses: defaultAddresses,
|
||||
},
|
||||
want: &Session{
|
||||
UserId: composedOf.UserId,
|
||||
HostId: "",
|
||||
HostSetId: "",
|
||||
TargetId: composedOf.TargetId,
|
||||
AuthTokenId: composedOf.AuthTokenId,
|
||||
ProjectId: composedOf.ProjectId,
|
||||
Endpoint: "tcp://127.0.0.1:22",
|
||||
ExpirationTime: composedOf.ExpirationTime,
|
||||
ConnectionLimit: composedOf.ConnectionLimit,
|
||||
DynamicCredentials: composedOf.DynamicCredentials,
|
||||
StaticCredentials: composedOf.StaticCredentials,
|
||||
},
|
||||
create: true,
|
||||
},
|
||||
{
|
||||
name: "invalid-missing-target-address-host-source",
|
||||
args: args{
|
||||
composedOf: func() ComposedOf {
|
||||
c := composedOf
|
||||
c.HostSetId = ""
|
||||
c.HostId = ""
|
||||
c.Endpoint = ""
|
||||
return c
|
||||
}(),
|
||||
addresses: defaultAddresses,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-userId",
|
||||
args: args{
|
||||
@@ -79,19 +121,6 @@ func TestSession_Create(t *testing.T) {
|
||||
wantErr: true,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-hostId",
|
||||
args: args{
|
||||
composedOf: func() ComposedOf {
|
||||
c := composedOf
|
||||
c.HostId = ""
|
||||
return c
|
||||
}(),
|
||||
addresses: defaultAddresses,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-targetId",
|
||||
args: args{
|
||||
@@ -105,19 +134,6 @@ func TestSession_Create(t *testing.T) {
|
||||
wantErr: true,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-hostSetId",
|
||||
args: args{
|
||||
composedOf: func() ComposedOf {
|
||||
c := composedOf
|
||||
c.HostSetId = ""
|
||||
return c
|
||||
}(),
|
||||
addresses: defaultAddresses,
|
||||
},
|
||||
wantErr: true,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "empty-authTokenId",
|
||||
args: args{
|
||||
|
||||
@@ -67,6 +67,28 @@ func TestState(t testing.TB, conn *db.DB, sessionId string, state Status) *State
|
||||
return s
|
||||
}
|
||||
|
||||
// TestSessionHostSetHost creates a test session to host set host association for the sessionId in the repository.
|
||||
func TestSessionHostSetHost(t testing.TB, conn *db.DB, sessionId, hostSetId, hostId string) {
|
||||
t.Helper()
|
||||
require := require.New(t)
|
||||
rw := db.New(conn)
|
||||
hs, err := NewSessionHostSetHost(sessionId, hostSetId, hostId)
|
||||
require.NoError(err)
|
||||
err = rw.Create(context.Background(), hs)
|
||||
require.NoError(err)
|
||||
}
|
||||
|
||||
// TestSessionTargetAddress creates a test session to target address association for the sessionId in the repository.
|
||||
func TestSessionTargetAddress(t testing.TB, conn *db.DB, sessionId, targetId string) {
|
||||
t.Helper()
|
||||
require := require.New(t)
|
||||
rw := db.New(conn)
|
||||
ta, err := NewSessionTargetAddress(sessionId, targetId)
|
||||
require.NoError(err)
|
||||
err = rw.Create(context.Background(), ta)
|
||||
require.NoError(err)
|
||||
}
|
||||
|
||||
// TestSession creates a test session composed of c in the repository. Options
|
||||
// are passed into New, and withServerId is handled locally.
|
||||
func TestSession(t testing.TB, conn *db.DB, rootWrapper wrapping.Wrapper, c ComposedOf, opt ...Option) *Session {
|
||||
@@ -113,6 +135,12 @@ func TestSession(t testing.TB, conn *db.DB, rootWrapper wrapping.Wrapper, c Comp
|
||||
require.NoError(err)
|
||||
}
|
||||
|
||||
if s.HostId != "" && s.HostSetId != "" {
|
||||
TestSessionHostSetHost(t, conn, s.PublicId, s.HostSetId, s.HostId)
|
||||
} else if s.Endpoint != "" {
|
||||
TestSessionTargetAddress(t, conn, s.PublicId, s.TargetId)
|
||||
}
|
||||
|
||||
ss, err := fetchStates(ctx, rw, s.PublicId, append(opts.withDbOpts, db.WithOrder("start_time desc"))...)
|
||||
require.NoError(err)
|
||||
s.States = ss
|
||||
@@ -120,6 +148,48 @@ func TestSession(t testing.TB, conn *db.DB, rootWrapper wrapping.Wrapper, c Comp
|
||||
return s
|
||||
}
|
||||
|
||||
func TestSessionWithTargetAddress(t testing.TB, conn *db.DB, wrapper wrapping.Wrapper, iamRepo *iam.Repository, opt ...Option) *Session {
|
||||
t.Helper()
|
||||
composedOf := TestSessionTargetAddressParams(t, conn, wrapper, iamRepo)
|
||||
future := timestamppb.New(time.Now().Add(time.Hour))
|
||||
exp := ×tamp.Timestamp{Timestamp: future}
|
||||
return TestSession(t, conn, wrapper, composedOf, append(opt, WithExpirationTime(exp))...)
|
||||
}
|
||||
|
||||
func TestSessionTargetAddressParams(t testing.TB, conn *db.DB, wrapper wrapping.Wrapper, iamRepo *iam.Repository) ComposedOf {
|
||||
t.Helper()
|
||||
ctx := context.Background()
|
||||
|
||||
require := require.New(t)
|
||||
rw := db.New(conn)
|
||||
org, proj := iam.TestScopes(t, iamRepo)
|
||||
|
||||
tcpTarget := tcp.TestTarget(ctx, t, conn, proj.PublicId, "test target")
|
||||
target.TestTargetAddress(t, conn, tcpTarget.GetPublicId(), "tcp://127.0.0.1:22")
|
||||
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
authMethod := password.TestAuthMethods(t, conn, org.PublicId, 1)[0]
|
||||
acct := password.TestAccount(t, conn, authMethod.GetPublicId(), "name1")
|
||||
user := iam.TestUser(t, iamRepo, org.PublicId, iam.WithAccountIds(acct.PublicId))
|
||||
|
||||
authTokenRepo, err := authtoken.NewRepository(rw, rw, kms)
|
||||
require.NoError(err)
|
||||
at, err := authTokenRepo.CreateAuthToken(ctx, user, acct.GetPublicId())
|
||||
require.NoError(err)
|
||||
|
||||
expTime := timestamppb.Now()
|
||||
expTime.Seconds += int64(tcpTarget.GetSessionMaxSeconds())
|
||||
return ComposedOf{
|
||||
UserId: user.PublicId,
|
||||
TargetId: tcpTarget.GetPublicId(),
|
||||
AuthTokenId: at.PublicId,
|
||||
ProjectId: tcpTarget.GetProjectId(),
|
||||
Endpoint: "tcp://127.0.0.1:22",
|
||||
ExpirationTime: ×tamp.Timestamp{Timestamp: expTime},
|
||||
ConnectionLimit: tcpTarget.GetSessionConnectionLimit(),
|
||||
}
|
||||
}
|
||||
|
||||
// TestDefaultSession creates a test session in the repository using defaults.
|
||||
func TestDefaultSession(t testing.TB, conn *db.DB, wrapper wrapping.Wrapper, iamRepo *iam.Repository, opt ...Option) *Session {
|
||||
t.Helper()
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package target
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/oplog"
|
||||
"github.com/hashicorp/boundary/internal/target/store"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultTargetAddressTableName = "target_address"
|
||||
)
|
||||
|
||||
// An Address represents the relationship between a target and a
|
||||
// network address.
|
||||
type Address struct {
|
||||
*store.TargetAddress
|
||||
tableName string `gorm:"-"`
|
||||
}
|
||||
|
||||
// Ensure Address implements interfaces
|
||||
var (
|
||||
_ db.VetForWriter = (*Address)(nil)
|
||||
_ oplog.ReplayableMessage = (*Address)(nil)
|
||||
)
|
||||
|
||||
// NewAddress creates a new in memory address. No options are
|
||||
// currently supported.
|
||||
func NewAddress(targetId, address string, _ ...Option) (*Address, error) {
|
||||
const op = "target.NewAddress"
|
||||
if targetId == "" {
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing target id")
|
||||
}
|
||||
if address == "" {
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing address")
|
||||
}
|
||||
t := &Address{
|
||||
TargetAddress: &store.TargetAddress{
|
||||
TargetId: targetId,
|
||||
Address: address,
|
||||
},
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// Clone creates a clone of the target address
|
||||
func (t *Address) Clone() any {
|
||||
cp := proto.Clone(t.TargetAddress)
|
||||
return &Address{
|
||||
TargetAddress: cp.(*store.TargetAddress),
|
||||
}
|
||||
}
|
||||
|
||||
// VetForWrite implements db.VetForWrite() interface and validates the target
|
||||
// address before it's written.
|
||||
func (t *Address) VetForWrite(ctx context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error {
|
||||
const op = "target.(Address).VetForWrite"
|
||||
if opType == db.CreateOp {
|
||||
if t.GetTargetId() == "" {
|
||||
return errors.New(ctx, errors.InvalidParameter, op, "missing target id")
|
||||
}
|
||||
if t.GetAddress() == "" {
|
||||
return errors.New(ctx, errors.InvalidParameter, op, "missing address")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TableName returns the tablename to override the default gorm table name
|
||||
func (t *Address) TableName() string {
|
||||
if t.tableName != "" {
|
||||
return t.tableName
|
||||
}
|
||||
return DefaultTargetAddressTableName
|
||||
}
|
||||
|
||||
// SetTableName sets the tablename and satisfies the ReplayableMessage
|
||||
// interface. If the caller attempts to set the name to "" the name will be
|
||||
// reset to the default name.
|
||||
func (t *Address) SetTableName(n string) {
|
||||
t.tableName = n
|
||||
}
|
||||
|
||||
func (t *Address) oplog(op oplog.OpType) oplog.Metadata {
|
||||
metadata := oplog.Metadata{
|
||||
"resource-public-id": []string{t.GetTargetId()},
|
||||
"resource-type": []string{"target address"},
|
||||
"op-type": []string{op.String()},
|
||||
}
|
||||
return metadata
|
||||
}
|
||||
|
||||
func (t *Address) TargetId() string {
|
||||
return t.GetTargetId()
|
||||
}
|
||||
|
||||
func (t *Address) Address() string {
|
||||
return t.GetAddress()
|
||||
}
|
||||
|
||||
func (t *Address) GetPublicId() string {
|
||||
return t.GetTargetId()
|
||||
}
|
||||
|
||||
// allocTargetAddress will allocate a address
|
||||
func allocTargetAddress() *Address {
|
||||
return &Address{
|
||||
TargetAddress: &store.TargetAddress{},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package target_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/target"
|
||||
"github.com/hashicorp/boundary/internal/target/store"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAddress_New(t *testing.T) {
|
||||
type args struct {
|
||||
targetId string
|
||||
address string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *target.Address
|
||||
wantErr errors.Code
|
||||
}{
|
||||
{
|
||||
name: "no-target_id",
|
||||
args: args{
|
||||
address: "0.0.0.0",
|
||||
},
|
||||
wantErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "no-address",
|
||||
args: args{
|
||||
targetId: "targ_0000000",
|
||||
},
|
||||
wantErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
args: args{
|
||||
targetId: "targ_0000000",
|
||||
address: "0.0.0.0",
|
||||
},
|
||||
want: &target.Address{
|
||||
TargetAddress: &store.TargetAddress{
|
||||
TargetId: "targ_0000000",
|
||||
Address: "0.0.0.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
got, err := target.NewAddress(tt.args.targetId, tt.args.address)
|
||||
if tt.wantErr != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErr), err), "want err: %q got: %q", tt.wantErr, err)
|
||||
assert.Nil(got)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
require.NotNil(got)
|
||||
assert.EqualValues(tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ type options struct {
|
||||
WithEgressWorkerFilter string
|
||||
WithIngressWorkerFilter string
|
||||
WithTargetIds []string
|
||||
WithAddress string
|
||||
}
|
||||
|
||||
func getDefaultOptions() options {
|
||||
@@ -64,6 +65,7 @@ func getDefaultOptions() options {
|
||||
WithWorkerFilter: "",
|
||||
WithEgressWorkerFilter: "",
|
||||
WithIngressWorkerFilter: "",
|
||||
WithAddress: "",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,3 +209,10 @@ func WithPermissions(perms []perms.Permission) Option {
|
||||
o.WithPermissions = perms
|
||||
}
|
||||
}
|
||||
|
||||
// WithAddress provides an optional network address
|
||||
func WithAddress(address string) Option {
|
||||
return func(o *options) {
|
||||
o.WithAddress = address
|
||||
}
|
||||
}
|
||||
+154
-84
@@ -125,6 +125,7 @@ func (r *Repository) LookupTarget(ctx context.Context, publicIdOrName string, op
|
||||
|
||||
target := allocTargetView()
|
||||
target.PublicId = publicIdOrName
|
||||
var address string
|
||||
var hostSources []HostSource
|
||||
var credSources []CredentialSource
|
||||
_, err := r.writer.DoTx(
|
||||
@@ -150,6 +151,13 @@ func (r *Repository) LookupTarget(ctx context.Context, publicIdOrName string, op
|
||||
if credSources, err = fetchCredentialSources(ctx, read, target.PublicId); err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
targetAddress, err := fetchAddress(ctx, read, target.PublicId)
|
||||
if err != nil && !errors.IsNotFoundError(err) {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if targetAddress != nil {
|
||||
address = targetAddress.GetAddress()
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
@@ -159,7 +167,7 @@ func (r *Repository) LookupTarget(ctx context.Context, publicIdOrName string, op
|
||||
}
|
||||
return nil, nil, nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
subtype, err := target.targetSubtype(ctx)
|
||||
subtype, err := target.targetSubtype(ctx, address)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
@@ -242,9 +250,28 @@ func (r *Repository) ListTargets(ctx context.Context, opt ...Option) ([]Target,
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
var targetIds []string
|
||||
for _, t := range foundTargets {
|
||||
targetIds = append(targetIds, t.GetPublicId())
|
||||
}
|
||||
|
||||
addresses := map[string]string{}
|
||||
var foundAddresses []*Address
|
||||
err = r.reader.SearchWhere(ctx, &foundAddresses, "target_id in (?)", []any{targetIds})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
for _, addr := range foundAddresses {
|
||||
addresses[addr.TargetId()] = addr.Address()
|
||||
}
|
||||
|
||||
targets := make([]Target, 0, len(foundTargets))
|
||||
for _, t := range foundTargets {
|
||||
subtype, err := t.targetSubtype(ctx)
|
||||
var address string
|
||||
if v, ok := addresses[t.GetPublicId()]; ok {
|
||||
address = v
|
||||
}
|
||||
subtype, err := t.targetSubtype(ctx, address)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
@@ -336,80 +363,6 @@ func (r *Repository) DeleteTarget(ctx context.Context, publicId string, _ ...Opt
|
||||
return rowsDeleted, nil
|
||||
}
|
||||
|
||||
// update a target in the db repository with an oplog entry.
|
||||
// It currently supports no options.
|
||||
func (r *Repository) update(ctx context.Context, target Target, version uint32, fieldMaskPaths []string, setToNullPaths []string, _ ...Option) (Target, []HostSource, []CredentialSource, int, error) {
|
||||
const op = "target.(Repository).update"
|
||||
if version == 0 {
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing version")
|
||||
}
|
||||
if target == nil {
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "nil target")
|
||||
}
|
||||
cloner, ok := target.(Cloneable)
|
||||
if !ok {
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "target is not cloneable")
|
||||
}
|
||||
dbOpts := []db.Option{
|
||||
db.WithVersion(&version),
|
||||
}
|
||||
projectId := target.GetProjectId()
|
||||
if projectId == "" {
|
||||
t := allocTargetView()
|
||||
t.PublicId = target.GetPublicId()
|
||||
if err := r.reader.LookupByPublicId(ctx, &t); err != nil {
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("lookup failed for %s", t.PublicId)))
|
||||
}
|
||||
projectId = t.ProjectId
|
||||
}
|
||||
oplogWrapper, err := r.kms.GetWrapper(ctx, projectId, kms.KeyPurposeOplog)
|
||||
if err != nil {
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
|
||||
}
|
||||
metadata := target.Oplog(oplog.OpType_OP_TYPE_UPDATE)
|
||||
dbOpts = append(dbOpts, db.WithOplog(oplogWrapper, metadata))
|
||||
|
||||
var rowsUpdated int
|
||||
var returnedTarget any
|
||||
var hostSources []HostSource
|
||||
var credSources []CredentialSource
|
||||
_, err = r.writer.DoTx(
|
||||
ctx,
|
||||
db.StdRetryCnt,
|
||||
db.ExpBackoff{},
|
||||
func(reader db.Reader, w db.Writer) error {
|
||||
returnedTarget = cloner.Clone()
|
||||
rowsUpdated, err = w.Update(
|
||||
ctx,
|
||||
returnedTarget,
|
||||
fieldMaskPaths,
|
||||
setToNullPaths,
|
||||
dbOpts...,
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if rowsUpdated > 1 {
|
||||
// return err, which will result in a rollback of the update
|
||||
return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been updated")
|
||||
}
|
||||
|
||||
if hostSources, err = fetchHostSources(ctx, reader, target.GetPublicId()); err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
if credSources, err = fetchCredentialSources(ctx, reader, target.GetPublicId()); err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
return returnedTarget.(Target), hostSources, credSources, rowsUpdated, nil
|
||||
}
|
||||
|
||||
// CreateTarget inserts into the repository and returns the new Target with
|
||||
// its list of host sets and credential libraries.
|
||||
// WithPublicId is the only supported option.
|
||||
@@ -455,6 +408,15 @@ func (r *Repository) CreateTarget(ctx context.Context, target Target, opt ...Opt
|
||||
t.SetPublicId(ctx, id)
|
||||
}
|
||||
|
||||
var address *Address
|
||||
var err error
|
||||
if t.GetAddress() != "" {
|
||||
address, err = NewAddress(t.GetPublicId(), t.GetAddress())
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
}
|
||||
|
||||
oplogWrapper, err := r.kms.GetWrapper(ctx, target.GetProjectId(), kms.KeyPurposeOplog)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
|
||||
@@ -480,6 +442,15 @@ func (r *Repository) CreateTarget(ctx context.Context, target Target, opt ...Opt
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to create target"))
|
||||
}
|
||||
msgs = append(msgs, &targetOplogMsg)
|
||||
|
||||
if address != nil {
|
||||
var targetAddressOplogMsg oplog.Message
|
||||
if err := w.Create(ctx, address, db.NewOplogMsg(&targetAddressOplogMsg)); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to create target address"))
|
||||
}
|
||||
msgs = append(msgs, &targetAddressOplogMsg)
|
||||
}
|
||||
|
||||
if err := w.WriteOplogEntryWith(ctx, oplogWrapper, targetTicket, metadata, msgs); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to write oplog"))
|
||||
}
|
||||
@@ -504,6 +475,15 @@ func (r *Repository) UpdateTarget(ctx context.Context, target Target, version ui
|
||||
if target == nil {
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target")
|
||||
}
|
||||
if target.GetPublicId() == "" {
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target public id")
|
||||
}
|
||||
if target.GetProjectId() == "" {
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing project id")
|
||||
}
|
||||
if version == 0 {
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing version")
|
||||
}
|
||||
vet, ok := subtypeRegistry.vetForUpdateFunc(target.GetType())
|
||||
if !ok {
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("unsupported target type %s", target.GetType()))
|
||||
@@ -512,10 +492,7 @@ func (r *Repository) UpdateTarget(ctx context.Context, target Target, version ui
|
||||
return nil, nil, nil, db.NoRowsAffected, err
|
||||
}
|
||||
|
||||
if target.GetPublicId() == "" {
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target public id")
|
||||
}
|
||||
|
||||
var addressEndpoint string
|
||||
for _, f := range fieldMaskPaths {
|
||||
switch {
|
||||
case strings.EqualFold("name", f):
|
||||
@@ -526,10 +503,13 @@ func (r *Repository) UpdateTarget(ctx context.Context, target Target, version ui
|
||||
case strings.EqualFold("workerfilter", f):
|
||||
case strings.EqualFold("egressworkerfilter", f):
|
||||
case strings.EqualFold("ingressworkerfilter", f):
|
||||
case strings.EqualFold("address", f):
|
||||
addressEndpoint = target.GetAddress()
|
||||
default:
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidFieldMask, op, fmt.Sprintf("invalid field mask: %s", f))
|
||||
}
|
||||
}
|
||||
|
||||
var dbMask, nullFields []string
|
||||
dbMask, nullFields = dbw.BuildUpdatePaths(
|
||||
map[string]any{
|
||||
@@ -541,6 +521,7 @@ func (r *Repository) UpdateTarget(ctx context.Context, target Target, version ui
|
||||
"WorkerFilter": target.GetWorkerFilter(),
|
||||
"EgressWorkerFilter": target.GetEgressWorkerFilter(),
|
||||
"IngressWorkerFilter": target.GetIngressWorkerFilter(),
|
||||
"Address": target.GetAddress(),
|
||||
},
|
||||
fieldMaskPaths,
|
||||
[]string{"SessionMaxSeconds", "SessionConnectionLimit"},
|
||||
@@ -548,21 +529,110 @@ func (r *Repository) UpdateTarget(ctx context.Context, target Target, version ui
|
||||
if len(dbMask) == 0 && len(nullFields) == 0 {
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.New(ctx, errors.EmptyFieldMask, op, "empty field mask")
|
||||
}
|
||||
var returnedTarget Target
|
||||
|
||||
// The Address field is not apart of the target schema in the database.
|
||||
// It is apart of a different table called target_address, which is why
|
||||
// the Address field must be filtered out of the dbMask & nullFields slices.
|
||||
var updateAddress, deleteAddress bool
|
||||
var filteredDbMask, filteredNullFields []string
|
||||
for _, f := range dbMask {
|
||||
switch {
|
||||
case strings.EqualFold("Address", f):
|
||||
updateAddress = true
|
||||
default:
|
||||
filteredDbMask = append(filteredDbMask, f)
|
||||
}
|
||||
}
|
||||
for _, f := range nullFields {
|
||||
switch {
|
||||
case strings.EqualFold("Address", f):
|
||||
deleteAddress = true
|
||||
default:
|
||||
filteredNullFields = append(filteredNullFields, f)
|
||||
}
|
||||
}
|
||||
|
||||
// If the Address field is the only present change, then we must still
|
||||
// update the target's version because a target address is a child object
|
||||
// of the target.
|
||||
if (len(filteredDbMask) == 0 && len(filteredNullFields) == 0) && (updateAddress || deleteAddress) {
|
||||
target.SetVersion(version + 1)
|
||||
filteredDbMask = append(filteredDbMask, "Version")
|
||||
}
|
||||
|
||||
oplogWrapper, err := r.kms.GetWrapper(ctx, target.GetProjectId(), kms.KeyPurposeOplog)
|
||||
if err != nil {
|
||||
return nil, nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
|
||||
}
|
||||
|
||||
var rowsUpdated int
|
||||
var returnedTarget Target
|
||||
var hostSources []HostSource
|
||||
var credSources []CredentialSource
|
||||
_, err := r.writer.DoTx(
|
||||
_, err = r.writer.DoTx(
|
||||
ctx,
|
||||
db.StdRetryCnt,
|
||||
db.ExpBackoff{},
|
||||
func(read db.Reader, w db.Writer) error {
|
||||
var err error
|
||||
t := target.Clone()
|
||||
returnedTarget, hostSources, credSources, rowsUpdated, err = r.update(ctx, t, version, dbMask, nullFields)
|
||||
rowsUpdated, err = w.Update(ctx, t, filteredDbMask, filteredNullFields,
|
||||
db.WithOplog(oplogWrapper, t.Oplog(oplog.OpType_OP_TYPE_UPDATE)),
|
||||
db.WithVersion(&version),
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if rowsUpdated > 1 {
|
||||
return errors.New(ctx, errors.MultipleRecords, op, "more than 1 target resource would have been updated")
|
||||
}
|
||||
|
||||
if hostSources, err = fetchHostSources(ctx, read, t.GetPublicId()); err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if credSources, err = fetchCredentialSources(ctx, read, t.GetPublicId()); err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
var address *Address
|
||||
switch {
|
||||
case updateAddress:
|
||||
if len(hostSources) > 0 {
|
||||
return errors.New(ctx, errors.Conflict, op, "unable to set address because one or more host sources is assigned to the given target")
|
||||
}
|
||||
address, err = NewAddress(t.GetPublicId(), addressEndpoint)
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if err := w.Create(ctx, address,
|
||||
db.WithOplog(oplogWrapper, address.oplog(oplog.OpType_OP_TYPE_UPDATE)),
|
||||
db.WithOnConflict(&db.OnConflict{
|
||||
Target: db.Columns{"target_id"},
|
||||
Action: db.UpdateAll(true),
|
||||
})); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to create target address"))
|
||||
}
|
||||
case deleteAddress:
|
||||
var err error
|
||||
address = allocTargetAddress()
|
||||
address.TargetAddress.TargetId = t.GetPublicId()
|
||||
rowsUpdated, err = w.Delete(ctx, address, db.WithOplog(oplogWrapper, address.oplog(oplog.OpType_OP_TYPE_DELETE)))
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete target address"))
|
||||
}
|
||||
if rowsUpdated > 1 {
|
||||
return errors.New(ctx, errors.MultipleRecords, op, "more than 1 target resource would have been deleted")
|
||||
}
|
||||
default:
|
||||
address, err = fetchAddress(ctx, read, t.GetPublicId())
|
||||
if err != nil && !errors.IsNotFoundError(err) {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to fetch target address"))
|
||||
}
|
||||
}
|
||||
if address != nil {
|
||||
t.SetAddress(address.GetAddress())
|
||||
}
|
||||
returnedTarget = t.Clone()
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package target
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
)
|
||||
|
||||
func fetchAddress(ctx context.Context, r db.Reader, targetId string) (*Address, error) {
|
||||
const op = "target.fetchAddress"
|
||||
var address *Address
|
||||
if err := r.SearchWhere(ctx, &address, "target_id = ?", []any{targetId}); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if address.TargetAddress == nil {
|
||||
return nil, errors.New(ctx, errors.RecordNotFound, op, fmt.Sprintf("%s target address not found", targetId), errors.WithoutEvent())
|
||||
}
|
||||
return address, nil
|
||||
}
|
||||
@@ -60,7 +60,7 @@ func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId st
|
||||
|
||||
var hostSources []HostSource
|
||||
var credSources []CredentialSource
|
||||
var updatedTarget any
|
||||
var updatedTarget Target
|
||||
_, err = r.writer.DoTx(
|
||||
ctx,
|
||||
db.StdRetryCnt,
|
||||
@@ -72,7 +72,7 @@ func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId st
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to get ticket"))
|
||||
}
|
||||
updatedTarget = target.(Cloneable).Clone()
|
||||
updatedTarget = target.Clone()
|
||||
var targetOplogMsg oplog.Message
|
||||
rowsUpdated, err := w.Update(ctx, updatedTarget, []string{"Version"}, nil, db.NewOplogMsg(&targetOplogMsg), db.WithVersion(&targetVersion))
|
||||
if err != nil {
|
||||
@@ -121,6 +121,13 @@ func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId st
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to retrieve credential sources after adding"))
|
||||
}
|
||||
address, err := fetchAddress(ctx, reader, targetId)
|
||||
if err != nil && !errors.IsNotFoundError(err) {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to retrieve target address after adding"))
|
||||
}
|
||||
if address != nil {
|
||||
updatedTarget.SetAddress(address.GetAddress())
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
@@ -58,18 +58,27 @@ func (r *Repository) AddTargetHostSources(ctx context.Context, targetId string,
|
||||
}
|
||||
var currentHostSources []HostSource
|
||||
var currentCredSources []CredentialSource
|
||||
var updatedTarget any
|
||||
var updatedTarget Target
|
||||
_, err = r.writer.DoTx(
|
||||
ctx,
|
||||
db.StdRetryCnt,
|
||||
db.ExpBackoff{},
|
||||
func(reader db.Reader, w db.Writer) error {
|
||||
address, err := fetchAddress(ctx, reader, targetId)
|
||||
if err != nil && !errors.IsNotFoundError(err) {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to retrieve current target address"))
|
||||
}
|
||||
if address != nil && address.GetAddress() != "" {
|
||||
return errors.New(ctx, errors.Conflict, op, "unable to add host sources because a network address is directly assigned to the given target")
|
||||
}
|
||||
|
||||
msgs := make([]*oplog.Message, 0, 2)
|
||||
targetTicket, err := w.GetTicket(ctx, target)
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to get ticket"))
|
||||
}
|
||||
updatedTarget = target.(Cloneable).Clone()
|
||||
|
||||
updatedTarget = target.Clone()
|
||||
var targetOplogMsg oplog.Message
|
||||
rowsUpdated, err := w.Update(ctx, updatedTarget, []string{"Version"}, nil, db.NewOplogMsg(&targetOplogMsg), db.WithVersion(&targetVersion))
|
||||
if err != nil {
|
||||
@@ -103,7 +112,8 @@ func (r *Repository) AddTargetHostSources(ctx context.Context, targetId string,
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("error creating sets"))
|
||||
}
|
||||
return updatedTarget.(Target), currentHostSources, currentCredSources, nil
|
||||
|
||||
return updatedTarget, currentHostSources, currentCredSources, nil
|
||||
}
|
||||
|
||||
// DeleteTargeHostSources deletes host sources from a target (targetId). The
|
||||
@@ -284,6 +294,14 @@ func (r *Repository) SetTargetHostSources(ctx context.Context, targetId string,
|
||||
db.StdRetryCnt,
|
||||
db.ExpBackoff{},
|
||||
func(reader db.Reader, w db.Writer) error {
|
||||
address, err := fetchAddress(ctx, reader, targetId)
|
||||
if err != nil && !errors.IsNotFoundError(err) {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to retrieve current target address"))
|
||||
}
|
||||
if address != nil && address.GetAddress() != "" {
|
||||
return errors.New(ctx, errors.Conflict, op, "unable to set host sources because a network address is directly assigned to the given target")
|
||||
}
|
||||
|
||||
msgs := make([]*oplog.Message, 0, 2)
|
||||
targetTicket, err := w.GetTicket(ctx, target)
|
||||
if err != nil {
|
||||
|
||||
+210
-128
@@ -8,6 +8,7 @@ package store
|
||||
|
||||
import (
|
||||
timestamp "github.com/hashicorp/boundary/internal/db/timestamp"
|
||||
_ "github.com/hashicorp/boundary/sdk/pbs/controller/protooptions"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -270,6 +271,65 @@ func (x *TargetHostSet) GetCreateTime() *timestamp.Timestamp {
|
||||
return nil
|
||||
}
|
||||
|
||||
type TargetAddress struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// target_id of the Target
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
TargetId string `protobuf:"bytes,10,opt,name=target_id,json=targetId,proto3" json:"target_id,omitempty" gorm:"primary_key"`
|
||||
// address associated to the Target
|
||||
// @inject_tag: `gorm:"not_null"`
|
||||
Address string `protobuf:"bytes,20,opt,name=address,proto3" json:"address,omitempty" gorm:"not_null"`
|
||||
}
|
||||
|
||||
func (x *TargetAddress) Reset() {
|
||||
*x = TargetAddress{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *TargetAddress) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TargetAddress) ProtoMessage() {}
|
||||
|
||||
func (x *TargetAddress) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TargetAddress.ProtoReflect.Descriptor instead.
|
||||
func (*TargetAddress) Descriptor() ([]byte, []int) {
|
||||
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *TargetAddress) GetTargetId() string {
|
||||
if x != nil {
|
||||
return x.TargetId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *TargetAddress) GetAddress() string {
|
||||
if x != nil {
|
||||
return x.Address
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type CredentialLibrary struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -292,7 +352,7 @@ type CredentialLibrary struct {
|
||||
func (x *CredentialLibrary) Reset() {
|
||||
*x = CredentialLibrary{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[2]
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -305,7 +365,7 @@ func (x *CredentialLibrary) String() string {
|
||||
func (*CredentialLibrary) ProtoMessage() {}
|
||||
|
||||
func (x *CredentialLibrary) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[2]
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -318,7 +378,7 @@ func (x *CredentialLibrary) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use CredentialLibrary.ProtoReflect.Descriptor instead.
|
||||
func (*CredentialLibrary) Descriptor() ([]byte, []int) {
|
||||
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{2}
|
||||
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *CredentialLibrary) GetTargetId() string {
|
||||
@@ -371,7 +431,7 @@ type StaticCredential struct {
|
||||
func (x *StaticCredential) Reset() {
|
||||
*x = StaticCredential{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[3]
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -384,7 +444,7 @@ func (x *StaticCredential) String() string {
|
||||
func (*StaticCredential) ProtoMessage() {}
|
||||
|
||||
func (x *StaticCredential) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[3]
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -397,7 +457,7 @@ func (x *StaticCredential) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use StaticCredential.ProtoReflect.Descriptor instead.
|
||||
func (*StaticCredential) Descriptor() ([]byte, []int) {
|
||||
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{3}
|
||||
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *StaticCredential) GetTargetId() string {
|
||||
@@ -453,7 +513,7 @@ type CredentialSource struct {
|
||||
func (x *CredentialSource) Reset() {
|
||||
*x = CredentialSource{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[4]
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -466,7 +526,7 @@ func (x *CredentialSource) String() string {
|
||||
func (*CredentialSource) ProtoMessage() {}
|
||||
|
||||
func (x *CredentialSource) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[4]
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -479,7 +539,7 @@ func (x *CredentialSource) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use CredentialSource.ProtoReflect.Descriptor instead.
|
||||
func (*CredentialSource) Descriptor() ([]byte, []int) {
|
||||
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{4}
|
||||
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *CredentialSource) GetTargetId() string {
|
||||
@@ -533,7 +593,7 @@ type CredentialSourceView struct {
|
||||
func (x *CredentialSourceView) Reset() {
|
||||
*x = CredentialSourceView{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[5]
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -546,7 +606,7 @@ func (x *CredentialSourceView) String() string {
|
||||
func (*CredentialSourceView) ProtoMessage() {}
|
||||
|
||||
func (x *CredentialSourceView) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[5]
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -559,7 +619,7 @@ func (x *CredentialSourceView) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use CredentialSourceView.ProtoReflect.Descriptor instead.
|
||||
func (*CredentialSourceView) Descriptor() ([]byte, []int) {
|
||||
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{5}
|
||||
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *CredentialSourceView) GetPublicId() string {
|
||||
@@ -584,109 +644,118 @@ var file_controller_storage_target_store_v1_target_proto_rawDesc = []byte{
|
||||
0x65, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x12, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74,
|
||||
0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x6f,
|
||||
0x72, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
|
||||
0x61, 0x6d, 0x70, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe0, 0x04, 0x0a, 0x0a, 0x54, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x56, 0x69, 0x65, 0x77, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
|
||||
0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49,
|
||||
0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63,
|
||||
0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63,
|
||||
0x72, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x2a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
|
||||
0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x1a, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x74,
|
||||
0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f,
|
||||
0x76, 0x31, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x22, 0xe0, 0x04, 0x0a, 0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x56, 0x69, 0x65,
|
||||
0x77, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x0a,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x12, 0x1d,
|
||||
0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69,
|
||||
0x6d, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69,
|
||||
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
|
||||
0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65,
|
||||
0x12, 0x4b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18,
|
||||
0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73,
|
||||
0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
|
||||
0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a,
|
||||
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07,
|
||||
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
|
||||
0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64,
|
||||
0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x5a, 0x20, 0x01, 0x28,
|
||||
0x0d, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x2e,
|
||||
0x0a, 0x13, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65,
|
||||
0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x73, 0x65, 0x73,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x38,
|
||||
0x0a, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x6e, 0x20, 0x01, 0x28, 0x05,
|
||||
0x52, 0x16, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x65, 0x72, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x78, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x31, 0x0a,
|
||||
0x14, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x66,
|
||||
0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x82, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x65, 0x67,
|
||||
0x72, 0x65, 0x73, 0x73, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72,
|
||||
0x12, 0x33, 0x0a, 0x15, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x65, 0x72, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x8c, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x13, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46,
|
||||
0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x99, 0x01, 0x0a, 0x0d, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x72, 0x67,
|
||||
0x65, 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x53,
|
||||
0x65, 0x74, 0x49, 0x64, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65,
|
||||
0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d,
|
||||
0x65, 0x22, 0x5e, 0x0a, 0x0d, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65,
|
||||
0x73, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12,
|
||||
0x30, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09,
|
||||
0x42, 0x16, 0xc2, 0xdd, 0x29, 0x12, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12,
|
||||
0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
|
||||
0x73, 0x22, 0xe0, 0x01, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c,
|
||||
0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x72, 0x67,
|
||||
0x65, 0x74, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69,
|
||||
0x61, 0x6c, 0x5f, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x13, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c,
|
||||
0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x72, 0x65, 0x64,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x1e,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c,
|
||||
0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67,
|
||||
0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||
0x54, 0x69, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65,
|
||||
0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d,
|
||||
0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x46, 0x20, 0x01,
|
||||
0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74,
|
||||
0x79, 0x70, 0x65, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12,
|
||||
0x21, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18,
|
||||
0x5a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f,
|
||||
0x72, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61,
|
||||
0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
||||
0x11, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63, 0x6f, 0x6e,
|
||||
0x64, 0x73, 0x12, 0x38, 0x0a, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f,
|
||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x6e,
|
||||
0x20, 0x01, 0x28, 0x05, 0x52, 0x16, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e,
|
||||
0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d,
|
||||
0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x78, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65,
|
||||
0x72, 0x12, 0x31, 0x0a, 0x14, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x65, 0x72, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x82, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x12, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69,
|
||||
0x6c, 0x74, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x15, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f,
|
||||
0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x8c, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x57, 0x6f, 0x72,
|
||||
0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x99, 0x01, 0x0a, 0x0d, 0x54, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74,
|
||||
0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x68,
|
||||
0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x49, 0x64, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61,
|
||||
0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61,
|
||||
0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xe0, 0x01, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e,
|
||||
0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x74,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x72, 0x65, 0x64,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12,
|
||||
0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x72, 0x70, 0x6f,
|
||||
0x73, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e,
|
||||
0x74, 0x69, 0x61, 0x6c, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x63,
|
||||
0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74,
|
||||
0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xd0, 0x01, 0x0a, 0x10, 0x53, 0x74, 0x61,
|
||||
0x74, 0x69, 0x63, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1b, 0x0a,
|
||||
0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x08, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72,
|
||||
0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x49, 0x64, 0x12,
|
||||
0x2d, 0x0a, 0x12, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x75,
|
||||
0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x72, 0x65,
|
||||
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x4b,
|
||||
0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x28, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
||||
0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
|
||||
0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xf1, 0x01, 0x0a, 0x10,
|
||||
0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||
0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12, 0x30, 0x0a,
|
||||
0x14, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x63, 0x72, 0x65,
|
||||
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12,
|
||||
0x2d, 0x0a, 0x12, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x75,
|
||||
0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x72, 0x65,
|
||||
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x4b,
|
||||
0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x28, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
||||
0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
|
||||
0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74,
|
||||
0x79, 0x70, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22,
|
||||
0x47, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x56, 0x69, 0x65, 0x77, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69,
|
||||
0x63, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c,
|
||||
0x69, 0x63, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x14, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68,
|
||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
|
||||
0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
||||
0x61, 0x6c, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b,
|
||||
0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x54, 0x69, 0x6d, 0x65, 0x22, 0xd0, 0x01, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x43,
|
||||
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x72,
|
||||
0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e,
|
||||
0x74, 0x69, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63,
|
||||
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x63,
|
||||
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73,
|
||||
0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x61, 0x6c, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f,
|
||||
0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65,
|
||||
0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xf1, 0x01, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x64,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09,
|
||||
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x08, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x72, 0x65,
|
||||
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x63,
|
||||
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73,
|
||||
0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x61, 0x6c, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f,
|
||||
0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65,
|
||||
0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
|
||||
0x32, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x47, 0x0a, 0x14, 0x43,
|
||||
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56,
|
||||
0x69, 0x65, 0x77, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64,
|
||||
0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
||||
0x74, 0x79, 0x70, 0x65, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75,
|
||||
0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x73, 0x74, 0x6f, 0x72,
|
||||
0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -701,23 +770,24 @@ func file_controller_storage_target_store_v1_target_proto_rawDescGZIP() []byte {
|
||||
return file_controller_storage_target_store_v1_target_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_controller_storage_target_store_v1_target_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||
var file_controller_storage_target_store_v1_target_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
||||
var file_controller_storage_target_store_v1_target_proto_goTypes = []interface{}{
|
||||
(*TargetView)(nil), // 0: controller.storage.target.store.v1.TargetView
|
||||
(*TargetHostSet)(nil), // 1: controller.storage.target.store.v1.TargetHostSet
|
||||
(*CredentialLibrary)(nil), // 2: controller.storage.target.store.v1.CredentialLibrary
|
||||
(*StaticCredential)(nil), // 3: controller.storage.target.store.v1.StaticCredential
|
||||
(*CredentialSource)(nil), // 4: controller.storage.target.store.v1.CredentialSource
|
||||
(*CredentialSourceView)(nil), // 5: controller.storage.target.store.v1.CredentialSourceView
|
||||
(*timestamp.Timestamp)(nil), // 6: controller.storage.timestamp.v1.Timestamp
|
||||
(*TargetAddress)(nil), // 2: controller.storage.target.store.v1.TargetAddress
|
||||
(*CredentialLibrary)(nil), // 3: controller.storage.target.store.v1.CredentialLibrary
|
||||
(*StaticCredential)(nil), // 4: controller.storage.target.store.v1.StaticCredential
|
||||
(*CredentialSource)(nil), // 5: controller.storage.target.store.v1.CredentialSource
|
||||
(*CredentialSourceView)(nil), // 6: controller.storage.target.store.v1.CredentialSourceView
|
||||
(*timestamp.Timestamp)(nil), // 7: controller.storage.timestamp.v1.Timestamp
|
||||
}
|
||||
var file_controller_storage_target_store_v1_target_proto_depIdxs = []int32{
|
||||
6, // 0: controller.storage.target.store.v1.TargetView.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
6, // 1: controller.storage.target.store.v1.TargetView.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
6, // 2: controller.storage.target.store.v1.TargetHostSet.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
6, // 3: controller.storage.target.store.v1.CredentialLibrary.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
6, // 4: controller.storage.target.store.v1.StaticCredential.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
6, // 5: controller.storage.target.store.v1.CredentialSource.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
7, // 0: controller.storage.target.store.v1.TargetView.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
7, // 1: controller.storage.target.store.v1.TargetView.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
7, // 2: controller.storage.target.store.v1.TargetHostSet.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
7, // 3: controller.storage.target.store.v1.CredentialLibrary.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
7, // 4: controller.storage.target.store.v1.StaticCredential.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
7, // 5: controller.storage.target.store.v1.CredentialSource.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
6, // [6:6] is the sub-list for method output_type
|
||||
6, // [6:6] is the sub-list for method input_type
|
||||
6, // [6:6] is the sub-list for extension type_name
|
||||
@@ -756,7 +826,7 @@ func file_controller_storage_target_store_v1_target_proto_init() {
|
||||
}
|
||||
}
|
||||
file_controller_storage_target_store_v1_target_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CredentialLibrary); i {
|
||||
switch v := v.(*TargetAddress); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@@ -768,7 +838,7 @@ func file_controller_storage_target_store_v1_target_proto_init() {
|
||||
}
|
||||
}
|
||||
file_controller_storage_target_store_v1_target_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*StaticCredential); i {
|
||||
switch v := v.(*CredentialLibrary); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@@ -780,7 +850,7 @@ func file_controller_storage_target_store_v1_target_proto_init() {
|
||||
}
|
||||
}
|
||||
file_controller_storage_target_store_v1_target_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CredentialSource); i {
|
||||
switch v := v.(*StaticCredential); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@@ -792,6 +862,18 @@ func file_controller_storage_target_store_v1_target_proto_init() {
|
||||
}
|
||||
}
|
||||
file_controller_storage_target_store_v1_target_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CredentialSource); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_controller_storage_target_store_v1_target_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CredentialSourceView); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@@ -810,7 +892,7 @@ func file_controller_storage_target_store_v1_target_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_controller_storage_target_store_v1_target_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 6,
|
||||
NumMessages: 7,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -28,6 +28,7 @@ type Target interface {
|
||||
GetWorkerFilter() string
|
||||
GetEgressWorkerFilter() string
|
||||
GetIngressWorkerFilter() string
|
||||
GetAddress() string
|
||||
Clone() Target
|
||||
SetPublicId(context.Context, string) error
|
||||
SetProjectId(string)
|
||||
@@ -42,6 +43,7 @@ type Target interface {
|
||||
SetWorkerFilter(string)
|
||||
SetEgressWorkerFilter(string)
|
||||
SetIngressWorkerFilter(string)
|
||||
SetAddress(string)
|
||||
Oplog(op oplog.OpType) oplog.Metadata
|
||||
}
|
||||
|
||||
@@ -55,6 +57,8 @@ var _ boundary.AuthzProtectedEntity = (*targetView)(nil)
|
||||
// underlying type.
|
||||
type targetView struct {
|
||||
*store.TargetView
|
||||
// Network address assigned to the Target.
|
||||
Address string `json:"address,omitempty" gorm:"-"`
|
||||
tableName string `gorm:"-"`
|
||||
}
|
||||
|
||||
@@ -105,7 +109,7 @@ func (t *targetView) Subtype() subtypes.Subtype {
|
||||
}
|
||||
|
||||
// targetSubtype converts the target view to the concrete subtype
|
||||
func (t *targetView) targetSubtype(ctx context.Context) (Target, error) {
|
||||
func (t *targetView) targetSubtype(ctx context.Context, address string) (Target, error) {
|
||||
const op = "target.targetView.targetSubtype"
|
||||
|
||||
alloc, ok := subtypeRegistry.allocFunc(t.Subtype())
|
||||
@@ -129,5 +133,6 @@ func (t *targetView) targetSubtype(ctx context.Context) (Target, error) {
|
||||
tt.SetWorkerFilter(t.WorkerFilter)
|
||||
tt.SetEgressWorkerFilter(t.EgressWorkerFilter)
|
||||
tt.SetIngressWorkerFilter(t.IngressWorkerFilter)
|
||||
tt.SetAddress(address)
|
||||
return tt, nil
|
||||
}
|
||||
@@ -27,6 +27,7 @@ const (
|
||||
// Target is a target.Target used for tests.
|
||||
type Target struct {
|
||||
*store.Target
|
||||
Address string `gorm:"-"`
|
||||
tableName string `gorm:"-"`
|
||||
}
|
||||
|
||||
@@ -125,10 +126,15 @@ func (t *Target) GetIngressWorkerFilter() string {
|
||||
return t.IngressWorkerFilter
|
||||
}
|
||||
|
||||
func (t *Target) GetAddress() string {
|
||||
return t.Address
|
||||
}
|
||||
|
||||
func (t *Target) Clone() target.Target {
|
||||
cp := proto.Clone(t.Target)
|
||||
return &Target{
|
||||
Target: cp.(*store.Target),
|
||||
Address: t.Address,
|
||||
Target: cp.(*store.Target),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,6 +191,10 @@ func (t *Target) SetIngressWorkerFilter(filter string) {
|
||||
t.IngressWorkerFilter = filter
|
||||
}
|
||||
|
||||
func (t *Target) SetAddress(a string) {
|
||||
t.Address = a
|
||||
}
|
||||
|
||||
func (t *Target) Oplog(op oplog.OpType) oplog.Metadata {
|
||||
return oplog.Metadata{
|
||||
"resource-public-id": []string{t.PublicId},
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package tcp
|
||||
|
||||
import "github.com/hashicorp/boundary/internal/target"
|
||||
import (
|
||||
"github.com/hashicorp/boundary/internal/target"
|
||||
"github.com/hashicorp/boundary/internal/target/store"
|
||||
)
|
||||
|
||||
// Expose functions and variables for tests.
|
||||
var (
|
||||
@@ -17,3 +20,12 @@ func NewTestTarget(projectId string, opt ...target.Option) target.Target {
|
||||
t.SetProjectId(projectId)
|
||||
return t
|
||||
}
|
||||
|
||||
// NewTestAddress is a test helper that bypasses the targetId & address checks
|
||||
// performed by NewAddress, allowing tests to create a target Address with
|
||||
// nil fields for more robust testing.
|
||||
func NewTestAddress() *target.Address {
|
||||
return &target.Address{
|
||||
TargetAddress: &store.TargetAddress{},
|
||||
}
|
||||
}
|
||||
@@ -50,13 +50,15 @@ func TestRepository_AddTargetHostSets(t *testing.T) {
|
||||
type args struct {
|
||||
targetVersion uint32
|
||||
wantTargetIds bool
|
||||
wantAddress bool
|
||||
opt []target.Option
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
wantErrIs error
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
wantErrMsg string
|
||||
wantErrIs error
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
@@ -66,6 +68,16 @@ func TestRepository_AddTargetHostSets(t *testing.T) {
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "address-mutually-exclusive-relationship",
|
||||
args: args{
|
||||
targetVersion: 1,
|
||||
wantAddress: true,
|
||||
wantTargetIds: true,
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrMsg: "unable to add host sources because a network address is directly assigned to the given target",
|
||||
},
|
||||
{
|
||||
name: "bad-version",
|
||||
args: args{
|
||||
@@ -99,11 +111,20 @@ func TestRepository_AddTargetHostSets(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
projTarget := tcp.TestTarget(ctx, t, conn, staticProj.PublicId, "static-proj")
|
||||
|
||||
var address *target.Address
|
||||
if tt.args.wantAddress {
|
||||
address = target.TestTargetAddress(t, conn, projTarget.GetPublicId(), "8.8.8.8")
|
||||
}
|
||||
|
||||
var hostSourceIds []string
|
||||
origTarget, origHostSet, _, err := repo.LookupTarget(ctx, projTarget.GetPublicId())
|
||||
require.NoError(err)
|
||||
require.Equal(0, len(origHostSet))
|
||||
|
||||
if address != nil {
|
||||
require.Equal(address.GetAddress(), origTarget.GetAddress())
|
||||
}
|
||||
|
||||
if tt.args.wantTargetIds {
|
||||
hostSourceIds = createHostSetsFn([]string{staticProj.PublicId})
|
||||
}
|
||||
@@ -114,6 +135,9 @@ func TestRepository_AddTargetHostSets(t *testing.T) {
|
||||
if tt.wantErrIs != nil {
|
||||
assert.Truef(errors.Is(err, tt.wantErrIs), "unexpected error %s", err.Error())
|
||||
}
|
||||
if tt.wantErrMsg != "" {
|
||||
assert.Contains(err.Error(), tt.wantErrMsg)
|
||||
}
|
||||
// test to see of the target version update oplog was not created
|
||||
err = db.TestVerifyOplog(t, rw, projTarget.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
@@ -448,6 +472,7 @@ func TestRepository_SetTargetHostSets(t *testing.T) {
|
||||
setup func(target.Target) []target.HostSource
|
||||
args args
|
||||
wantAffectedRows int
|
||||
wantErrMsg string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
@@ -461,6 +486,17 @@ func TestRepository_SetTargetHostSets(t *testing.T) {
|
||||
wantErr: false,
|
||||
wantAffectedRows: 10,
|
||||
},
|
||||
{
|
||||
name: "address-mutually-exclusive-relationship",
|
||||
args: args{
|
||||
target: tcp.TestTarget(ctx, t, conn, proj.PublicId, "invalid-host-source", target.WithAddress("8.8.8.8")),
|
||||
targetVersion: 2, // yep, since setupFn will increment it to 2
|
||||
hostSourceIds: []string{testHostSetIds[0], testHostSetIds[1]},
|
||||
addToOrigHostSources: true,
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrMsg: "unable to set host sources because a network address is directly assigned to the given target",
|
||||
},
|
||||
{
|
||||
name: "no-change",
|
||||
setup: setupFn,
|
||||
|
||||
@@ -64,6 +64,21 @@ func TestRepository_CreateTarget(t *testing.T) {
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "with-address",
|
||||
args: args{
|
||||
target: func() target.Target {
|
||||
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
||||
target.WithName("with-address"),
|
||||
target.WithDescription("with-address"),
|
||||
target.WithDefaultPort(80),
|
||||
target.WithAddress("8.8.8.8"))
|
||||
require.NoError(t, err)
|
||||
return target
|
||||
}(),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "nil-target",
|
||||
args: args{
|
||||
@@ -187,6 +202,7 @@ func TestRepository_CreateTarget(t *testing.T) {
|
||||
|
||||
foundTarget, foundHostSources, foundCredLibs, err := repo.LookupTarget(context.Background(), tar.GetPublicId())
|
||||
assert.NoError(err)
|
||||
assert.Equal(tt.args.target.GetAddress(), tar.GetAddress())
|
||||
assert.True(proto.Equal(tar.(*tcp.Target), foundTarget.(*tcp.Target)))
|
||||
assert.Equal(hostSources, foundHostSources)
|
||||
assert.Equal(credSources, foundCredLibs)
|
||||
@@ -224,6 +240,7 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
type args struct {
|
||||
name string
|
||||
description string
|
||||
address string
|
||||
port uint32
|
||||
fieldMaskPaths []string
|
||||
opt []target.Option
|
||||
@@ -231,16 +248,17 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
PublicId *string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
newProjectId string
|
||||
newName string
|
||||
newTargetOpts []target.Option
|
||||
args args
|
||||
wantRowsUpdate int
|
||||
wantErr bool
|
||||
wantErrMsg string
|
||||
wantIsError errors.Code
|
||||
wantDup bool
|
||||
name string
|
||||
newProjectId string
|
||||
newName string
|
||||
newTargetOpts []target.Option
|
||||
args args
|
||||
wantRowsUpdate int
|
||||
wantErr bool
|
||||
wantErrMsg string
|
||||
wantIsError errors.Code
|
||||
wantDup bool
|
||||
wantHostSources bool
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
@@ -249,9 +267,63 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
fieldMaskPaths: []string{"Name"},
|
||||
ProjectId: proj.PublicId,
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: false,
|
||||
wantRowsUpdate: 1,
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: false,
|
||||
wantRowsUpdate: 1,
|
||||
wantHostSources: true,
|
||||
},
|
||||
|
||||
{
|
||||
name: "valid-address",
|
||||
args: args{
|
||||
name: "valid-address" + id,
|
||||
fieldMaskPaths: []string{"Name", "Address"},
|
||||
ProjectId: proj.PublicId,
|
||||
address: "8.8.8.8",
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: false,
|
||||
wantRowsUpdate: 1,
|
||||
wantHostSources: false,
|
||||
},
|
||||
{
|
||||
name: "null-address",
|
||||
args: args{
|
||||
fieldMaskPaths: []string{"Address"},
|
||||
ProjectId: proj.PublicId,
|
||||
address: "null",
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
newTargetOpts: []target.Option{target.WithAddress("8.8.8.8")},
|
||||
wantErr: false,
|
||||
wantRowsUpdate: 1,
|
||||
wantHostSources: false,
|
||||
},
|
||||
{
|
||||
name: "delete-address",
|
||||
args: args{
|
||||
fieldMaskPaths: []string{"Address"},
|
||||
ProjectId: proj.PublicId,
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
newTargetOpts: []target.Option{target.WithAddress("8.8.8.8")},
|
||||
wantErr: false,
|
||||
wantRowsUpdate: 1,
|
||||
wantHostSources: false,
|
||||
},
|
||||
{
|
||||
name: "host-source-mutually-exclusive-relationship",
|
||||
args: args{
|
||||
name: "invalid-address" + id,
|
||||
address: "8.8.8.8",
|
||||
fieldMaskPaths: []string{"Name", "Address"},
|
||||
ProjectId: proj.PublicId,
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantErrMsg: "unable to set address because one or more host sources is assigned to the given target",
|
||||
wantRowsUpdate: 0,
|
||||
wantHostSources: true,
|
||||
},
|
||||
{
|
||||
name: "valid-no-op",
|
||||
@@ -260,10 +332,11 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
fieldMaskPaths: []string{"Name"},
|
||||
ProjectId: proj.PublicId,
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
newName: "valid-no-op" + id,
|
||||
wantErr: false,
|
||||
wantRowsUpdate: 1,
|
||||
newProjectId: proj.PublicId,
|
||||
newName: "valid-no-op" + id,
|
||||
wantErr: false,
|
||||
wantRowsUpdate: 1,
|
||||
wantHostSources: true,
|
||||
},
|
||||
{
|
||||
name: "not-found",
|
||||
@@ -273,11 +346,12 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
ProjectId: proj.PublicId,
|
||||
PublicId: func() *string { s := "1"; return &s }(),
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantRowsUpdate: 0,
|
||||
wantErrMsg: "record not found, search issue: error #1100",
|
||||
wantIsError: errors.RecordNotFound,
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantRowsUpdate: 0,
|
||||
wantErrMsg: "record not found, search issue: error #1100",
|
||||
wantIsError: errors.RecordNotFound,
|
||||
wantHostSources: true,
|
||||
},
|
||||
{
|
||||
name: "null-name",
|
||||
@@ -286,11 +360,12 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
fieldMaskPaths: []string{"Name"},
|
||||
ProjectId: proj.PublicId,
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
newName: "null-name" + id,
|
||||
wantErr: true,
|
||||
wantRowsUpdate: 0,
|
||||
wantErrMsg: "db.DoTx: target.(Repository).UpdateTarget: target.(Repository).update: db.DoTx: target.(Repository).update: db.Update: name must not be empty: not null constraint violated: integrity violation: error #1001",
|
||||
newProjectId: proj.PublicId,
|
||||
newName: "null-name" + id,
|
||||
wantErr: true,
|
||||
wantRowsUpdate: 0,
|
||||
wantErrMsg: "db.DoTx: target.(Repository).UpdateTarget: db.Update: name must not be empty: not null constraint violated: integrity violation: error #1001",
|
||||
wantHostSources: true,
|
||||
},
|
||||
{
|
||||
name: "null-description",
|
||||
@@ -299,10 +374,11 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
fieldMaskPaths: []string{"Description"},
|
||||
ProjectId: proj.PublicId,
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
newTargetOpts: []target.Option{target.WithDescription("null-description" + id)},
|
||||
wantErr: false,
|
||||
wantRowsUpdate: 1,
|
||||
newProjectId: proj.PublicId,
|
||||
newTargetOpts: []target.Option{target.WithDescription("null-description" + id)},
|
||||
wantErr: false,
|
||||
wantRowsUpdate: 1,
|
||||
wantHostSources: true,
|
||||
},
|
||||
{
|
||||
name: "empty-field-mask",
|
||||
@@ -311,11 +387,12 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
fieldMaskPaths: []string{},
|
||||
ProjectId: proj.PublicId,
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantRowsUpdate: 0,
|
||||
wantErrMsg: "target.(Repository).UpdateTarget: empty field mask: parameter violation: error #104",
|
||||
wantIsError: errors.EmptyFieldMask,
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantRowsUpdate: 0,
|
||||
wantErrMsg: "target.(Repository).UpdateTarget: empty field mask: parameter violation: error #104",
|
||||
wantIsError: errors.EmptyFieldMask,
|
||||
wantHostSources: true,
|
||||
},
|
||||
{
|
||||
name: "nil-fieldmask",
|
||||
@@ -324,11 +401,12 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
fieldMaskPaths: nil,
|
||||
ProjectId: proj.PublicId,
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantRowsUpdate: 0,
|
||||
wantErrMsg: "target.(Repository).UpdateTarget: empty field mask: parameter violation: error #104",
|
||||
wantIsError: errors.EmptyFieldMask,
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantRowsUpdate: 0,
|
||||
wantErrMsg: "target.(Repository).UpdateTarget: empty field mask: parameter violation: error #104",
|
||||
wantIsError: errors.EmptyFieldMask,
|
||||
wantHostSources: true,
|
||||
},
|
||||
{
|
||||
name: "read-only-fields",
|
||||
@@ -337,11 +415,12 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
fieldMaskPaths: []string{"CreateTime"},
|
||||
ProjectId: proj.PublicId,
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantRowsUpdate: 0,
|
||||
wantErrMsg: "target.(Repository).UpdateTarget: invalid field mask: CreateTime: parameter violation: error #103",
|
||||
wantIsError: errors.InvalidFieldMask,
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantRowsUpdate: 0,
|
||||
wantErrMsg: "target.(Repository).UpdateTarget: invalid field mask: CreateTime: parameter violation: error #103",
|
||||
wantIsError: errors.InvalidFieldMask,
|
||||
wantHostSources: true,
|
||||
},
|
||||
{
|
||||
name: "unknown-fields",
|
||||
@@ -350,11 +429,12 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
fieldMaskPaths: []string{"Alice"},
|
||||
ProjectId: proj.PublicId,
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantRowsUpdate: 0,
|
||||
wantErrMsg: "target.(Repository).UpdateTarget: invalid field mask: Alice: parameter violation: error #103",
|
||||
wantIsError: errors.InvalidFieldMask,
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantRowsUpdate: 0,
|
||||
wantErrMsg: "target.(Repository).UpdateTarget: invalid field mask: Alice: parameter violation: error #103",
|
||||
wantIsError: errors.InvalidFieldMask,
|
||||
wantHostSources: true,
|
||||
},
|
||||
{
|
||||
name: "no-public-id",
|
||||
@@ -364,11 +444,12 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
ProjectId: proj.PublicId,
|
||||
PublicId: pubId(""),
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantErrMsg: "target.(Repository).UpdateTarget: missing target public id: parameter violation: error #100",
|
||||
wantIsError: errors.InvalidParameter,
|
||||
wantRowsUpdate: 0,
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantErrMsg: "target.(Repository).UpdateTarget: missing target public id: parameter violation: error #100",
|
||||
wantIsError: errors.InvalidParameter,
|
||||
wantRowsUpdate: 0,
|
||||
wantHostSources: true,
|
||||
},
|
||||
{
|
||||
name: "project-id-no-mask",
|
||||
@@ -376,21 +457,11 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
name: "project-id" + id,
|
||||
ProjectId: proj.PublicId,
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantErrMsg: "target.(Repository).UpdateTarget: empty field mask: parameter violation: error #104",
|
||||
wantIsError: errors.EmptyFieldMask,
|
||||
},
|
||||
{
|
||||
name: "empty-project-id-with-name-mask",
|
||||
args: args{
|
||||
name: "empty-project-id" + id,
|
||||
fieldMaskPaths: []string{"Name"},
|
||||
ProjectId: "",
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: false,
|
||||
wantRowsUpdate: 1,
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantErrMsg: "target.(Repository).UpdateTarget: empty field mask: parameter violation: error #104",
|
||||
wantIsError: errors.EmptyFieldMask,
|
||||
wantHostSources: true,
|
||||
},
|
||||
{
|
||||
name: "dup-name",
|
||||
@@ -399,11 +470,12 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
fieldMaskPaths: []string{"Name"},
|
||||
ProjectId: proj.PublicId,
|
||||
},
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantDup: true,
|
||||
wantErrMsg: " already exists in project " + proj.PublicId,
|
||||
wantIsError: errors.NotUnique,
|
||||
newProjectId: proj.PublicId,
|
||||
wantErr: true,
|
||||
wantDup: true,
|
||||
wantErrMsg: " already exists in project " + proj.PublicId,
|
||||
wantIsError: errors.NotUnique,
|
||||
wantHostSources: true,
|
||||
},
|
||||
}
|
||||
css := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), len(tests))
|
||||
@@ -416,11 +488,18 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
_ = tcp.TestTarget(ctx, t, conn, proj.PublicId, tt.args.name)
|
||||
}
|
||||
|
||||
testCats := static.TestCatalogs(t, conn, proj.PublicId, 1)
|
||||
hsets := static.TestSets(t, conn, testCats[0].GetPublicId(), 5)
|
||||
testHostSetIds := make([]string, 0, len(hsets))
|
||||
for _, hs := range hsets {
|
||||
testHostSetIds = append(testHostSetIds, hs.PublicId)
|
||||
testHostSetIds := []string{}
|
||||
if tt.wantHostSources {
|
||||
testCats := static.TestCatalogs(t, conn, proj.PublicId, 1)
|
||||
hsets := static.TestSets(t, conn, testCats[0].GetPublicId(), 5)
|
||||
testHostSetIds = make([]string, 0, len(hsets))
|
||||
for _, hs := range hsets {
|
||||
testHostSetIds = append(testHostSetIds, hs.PublicId)
|
||||
}
|
||||
tt.newTargetOpts = append(
|
||||
tt.newTargetOpts,
|
||||
target.WithHostSources(testHostSetIds),
|
||||
)
|
||||
}
|
||||
|
||||
cls := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 5)
|
||||
@@ -438,7 +517,6 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
|
||||
tt.newTargetOpts = append(
|
||||
tt.newTargetOpts,
|
||||
target.WithHostSources(testHostSetIds),
|
||||
target.WithCredentialLibraries(testCredLibs),
|
||||
)
|
||||
name := tt.newName
|
||||
@@ -451,6 +529,7 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
target.WithName(tt.args.name),
|
||||
target.WithDescription(tt.args.description),
|
||||
target.WithDefaultPort(tt.args.port),
|
||||
target.WithAddress(tt.args.address),
|
||||
)
|
||||
updateTarget.SetPublicId(ctx, tar.GetPublicId())
|
||||
if tt.args.PublicId != nil {
|
||||
@@ -464,6 +543,7 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
||||
assert.Nil(targetAfterUpdate)
|
||||
assert.Equal(0, updatedRows)
|
||||
assert.NotEmpty(err.Error())
|
||||
assert.Contains(err.Error(), tt.wantErrMsg)
|
||||
err = db.TestVerifyOplog(t, rw, tar.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second))
|
||||
assert.Error(err)
|
||||
@@ -478,6 +558,7 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
afterUpdateIds = append(afterUpdateIds, hs.Id())
|
||||
}
|
||||
assert.Equal(testHostSetIds, afterUpdateIds)
|
||||
assert.Equal(tt.args.address, targetAfterUpdate.GetAddress())
|
||||
|
||||
afterUpdateIds = make([]string, 0, len(credSources))
|
||||
for _, cl := range credSources {
|
||||
@@ -487,13 +568,14 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
|
||||
switch tt.name {
|
||||
case "valid-no-op":
|
||||
assert.Equal(tar.GetUpdateTime(), targetAfterUpdate.GetUpdateTime())
|
||||
assert.Equal(tar.GetUpdateTime().String(), targetAfterUpdate.GetUpdateTime().String())
|
||||
default:
|
||||
assert.NotEqual(tar.GetUpdateTime(), targetAfterUpdate.GetUpdateTime())
|
||||
}
|
||||
foundTarget, _, _, err := repo.LookupTarget(context.Background(), tar.GetPublicId())
|
||||
assert.NoError(err)
|
||||
assert.True(proto.Equal(targetAfterUpdate.((*tcp.Target)), foundTarget.((*tcp.Target))))
|
||||
assert.Equal(targetAfterUpdate.GetAddress(), foundTarget.GetAddress())
|
||||
underlyingDB, err := conn.SqlDB(ctx)
|
||||
require.NoError(err)
|
||||
dbassert := dbassert.New(t, underlyingDB)
|
||||
|
||||
@@ -27,6 +27,8 @@ const (
|
||||
// that can be accessed via TCP. It is a subtype of target.Target.
|
||||
type Target struct {
|
||||
*store.Target
|
||||
// Network address assigned to the Target.
|
||||
Address string `json:"address,omitempty" gorm:"-"`
|
||||
tableName string `gorm:"-"`
|
||||
}
|
||||
|
||||
@@ -57,6 +59,7 @@ func (h targetHooks) NewTarget(projectId string, opt ...target.Option) (target.T
|
||||
EgressWorkerFilter: opts.WithEgressWorkerFilter,
|
||||
IngressWorkerFilter: opts.WithIngressWorkerFilter,
|
||||
},
|
||||
Address: opts.WithAddress,
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
@@ -72,7 +75,8 @@ func (h targetHooks) AllocTarget() target.Target {
|
||||
func (t *Target) Clone() target.Target {
|
||||
cp := proto.Clone(t.Target)
|
||||
return &Target{
|
||||
Target: cp.(*store.Target),
|
||||
Target: cp.(*store.Target),
|
||||
Address: t.Address,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +128,10 @@ func (t *Target) GetType() subtypes.Subtype {
|
||||
return Subtype
|
||||
}
|
||||
|
||||
func (t *Target) GetAddress() string {
|
||||
return t.Address
|
||||
}
|
||||
|
||||
func (t *Target) SetPublicId(ctx context.Context, publicId string) error {
|
||||
const op = "tcp.(Target).SetPublicId"
|
||||
if !strings.HasPrefix(publicId, TargetPrefix+"_") {
|
||||
@@ -181,3 +189,7 @@ func (t *Target) SetEgressWorkerFilter(filter string) {
|
||||
func (t *Target) SetIngressWorkerFilter(filter string) {
|
||||
t.IngressWorkerFilter = filter
|
||||
}
|
||||
|
||||
func (t *Target) SetAddress(address string) {
|
||||
t.Address = address
|
||||
}
|
||||
@@ -324,7 +324,9 @@ func TestTarget_Clone(t *testing.T) {
|
||||
t.Run("valid", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
_, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
tar := tcp.TestTarget(ctx, t, conn, proj.PublicId, tcp.TestTargetName(t, proj.PublicId))
|
||||
tar := tcp.TestTarget(ctx, t, conn, proj.PublicId, tcp.TestTargetName(t, proj.PublicId),
|
||||
target.WithAddress("8.8.8.8"),
|
||||
)
|
||||
cp := tar.Clone()
|
||||
assert.True(proto.Equal(cp.(*tcp.Target).Target, tar.(*tcp.Target).Target))
|
||||
})
|
||||
|
||||
@@ -26,6 +26,13 @@ func TestTarget(ctx context.Context, t testing.TB, conn *db.DB, projectId, name
|
||||
err = rw.Create(context.Background(), tar)
|
||||
require.NoError(err)
|
||||
|
||||
if opts.WithAddress != "" {
|
||||
address, err := target.NewAddress(tar.GetPublicId(), opts.WithAddress)
|
||||
require.NoError(err)
|
||||
require.NotNil(address)
|
||||
err = rw.Create(context.Background(), address)
|
||||
require.NoError(err)
|
||||
}
|
||||
if len(opts.WithHostSources) > 0 {
|
||||
newHostSets := make([]any, 0, len(opts.WithHostSources))
|
||||
for _, s := range opts.WithHostSources {
|
||||
|
||||
@@ -23,6 +23,17 @@ func TestNewCredentialLibrary(targetId, credentialLibraryId string, purpose cred
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewTargetAddress creates a new in memory TargetAddress
|
||||
// representing the association between a Target and network address.
|
||||
func TestNewTargetAddress(targetId, address string) *Address {
|
||||
return &Address{
|
||||
TargetAddress: &store.TargetAddress{
|
||||
TargetId: targetId,
|
||||
Address: address,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewStaticCredential creates a new in memory StaticCredential
|
||||
// representing the relationship between targetId and credentialId with
|
||||
// the given purpose.
|
||||
@@ -47,3 +58,15 @@ func TestCredentialLibrary(t testing.TB, conn *db.DB, targetId, libraryId string
|
||||
require.NoError(err)
|
||||
return lib
|
||||
}
|
||||
|
||||
// TestTargetAddress creates am association for targetId and
|
||||
// a given address value.
|
||||
func TestTargetAddress(t testing.TB, conn *db.DB, targetId, address string) *Address {
|
||||
t.Helper()
|
||||
require := require.New(t)
|
||||
rw := db.New(conn)
|
||||
staticAddress := TestNewTargetAddress(targetId, address)
|
||||
err := rw.Create(context.Background(), staticAddress)
|
||||
require.NoError(err)
|
||||
return staticAddress
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/hashicorp/boundary/api/credentials"
|
||||
"github.com/hashicorp/boundary/api/credentialstores"
|
||||
"github.com/hashicorp/boundary/api/hostcatalogs"
|
||||
"github.com/hashicorp/boundary/api/hosts"
|
||||
"github.com/hashicorp/boundary/api/hostsets"
|
||||
"github.com/hashicorp/boundary/api/roles"
|
||||
"github.com/hashicorp/boundary/api/targets"
|
||||
@@ -379,6 +380,172 @@ func TestList(t *testing.T) {
|
||||
assert.Equal(filterItem.Id, ul.Items[0].Id)
|
||||
}
|
||||
|
||||
func TestTarget_AddressMutualExclusiveRelationship(t *testing.T) {
|
||||
tc := controller.NewTestController(t, nil)
|
||||
t.Cleanup(tc.Shutdown)
|
||||
|
||||
client := tc.Client()
|
||||
at := tc.Token()
|
||||
client.SetToken(at.Token)
|
||||
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(at.UserId))
|
||||
tClient := targets.NewClient(client)
|
||||
|
||||
// Create target with a network address association
|
||||
targetResp, err := tClient.Create(tc.Context(), "tcp", proj.GetPublicId(),
|
||||
targets.WithName("test-address"), targets.WithAddress("localhost"), targets.WithTcpTargetDefaultPort(22))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, targetResp)
|
||||
require.Equal(t, "localhost", targetResp.GetItem().Address)
|
||||
|
||||
// Setup host catalog, host set, & host resources
|
||||
hc, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, hc)
|
||||
hs, err := hostsets.NewClient(client).Create(tc.Context(), hc.Item.Id)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, hs)
|
||||
h, err := hosts.NewClient(client).Create(tc.Context(), hc.Item.Id, hosts.WithStaticHostAddress("localhost"))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, h)
|
||||
hUpdate, err := hostsets.NewClient(client).AddHosts(tc.Context(), hs.Item.Id, hs.Item.Version, []string{h.GetItem().Id})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, hUpdate)
|
||||
|
||||
// Expect error when associating a host source to the target with a direct network address association
|
||||
targetId := targetResp.GetItem().Id
|
||||
version := targetResp.GetItem().Version
|
||||
updateResp, err := tClient.AddHostSources(tc.Context(), targetId, version, []string{hs.Item.Id})
|
||||
require.Error(t, err)
|
||||
require.Nil(t, updateResp)
|
||||
apiErr := api.AsServerError(err)
|
||||
require.NotNil(t, apiErr)
|
||||
require.Equal(t, http.StatusBadRequest, apiErr.Response().StatusCode())
|
||||
|
||||
// Remove direct network address association. Successfully add a host source to target.
|
||||
targetResp, err = tClient.Update(tc.Context(), targetId, version, targets.DefaultAddress())
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, targetResp)
|
||||
require.Empty(t, targetResp.GetItem().Address)
|
||||
version = targetResp.GetItem().Version
|
||||
updateResp, err = tClient.AddHostSources(tc.Context(), targetId, version, []string{hs.Item.Id})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, updateResp)
|
||||
require.Empty(t, updateResp.GetItem().Address)
|
||||
require.Equal(t, []string{hs.Item.Id}, updateResp.GetItem().HostSourceIds)
|
||||
}
|
||||
|
||||
func TestTarget_HostSourceMutualExclusiveRelationship(t *testing.T) {
|
||||
tc := controller.NewTestController(t, nil)
|
||||
t.Cleanup(tc.Shutdown)
|
||||
|
||||
client := tc.Client()
|
||||
at := tc.Token()
|
||||
client.SetToken(at.Token)
|
||||
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(at.UserId))
|
||||
tClient := targets.NewClient(client)
|
||||
|
||||
// Setup host catalog, host set, & host resources
|
||||
hc, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, hc)
|
||||
hs, err := hostsets.NewClient(client).Create(tc.Context(), hc.Item.Id)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, hs)
|
||||
h, err := hosts.NewClient(client).Create(tc.Context(), hc.Item.Id, hosts.WithStaticHostAddress("localhost"))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, h)
|
||||
hUpdate, err := hostsets.NewClient(client).AddHosts(tc.Context(), hs.Item.Id, hs.Item.Version, []string{h.GetItem().Id})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, hUpdate)
|
||||
|
||||
// Create target without a network address association
|
||||
targetResp, err := tClient.Create(tc.Context(), "tcp", proj.GetPublicId(),
|
||||
targets.WithName("test-host-source"), targets.WithTcpTargetDefaultPort(22))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, targetResp)
|
||||
require.Empty(t, targetResp.GetItem().Address)
|
||||
|
||||
// Expect error when associating a address to the target with a host source association
|
||||
targetId := targetResp.GetItem().Id
|
||||
version := targetResp.GetItem().Version
|
||||
updateResp, err := tClient.AddHostSources(tc.Context(), targetId, version, []string{hs.Item.Id})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, updateResp)
|
||||
require.Empty(t, updateResp.GetItem().Address)
|
||||
require.Equal(t, []string{hs.Item.Id}, updateResp.GetItem().HostSourceIds)
|
||||
version = updateResp.GetItem().Version
|
||||
updateResp, err = tClient.Update(tc.Context(), targetId, version, targets.WithAddress("localhost"))
|
||||
require.Error(t, err)
|
||||
require.Nil(t, updateResp)
|
||||
apiErr := api.AsServerError(err)
|
||||
require.NotNil(t, apiErr)
|
||||
require.Equal(t, http.StatusBadRequest, apiErr.Response().StatusCode())
|
||||
|
||||
// Remove host source association. Successfully assign a network address to the target.
|
||||
updateResp, err = tClient.RemoveHostSources(tc.Context(), targetId, version, []string{hs.Item.Id})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, updateResp)
|
||||
require.Empty(t, updateResp.GetItem().HostSourceIds)
|
||||
version = updateResp.GetItem().Version
|
||||
updateResp, err = tClient.Update(tc.Context(), targetId, version, targets.WithAddress("localhost"))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, updateResp)
|
||||
require.Equal(t, "localhost", updateResp.GetItem().Address)
|
||||
require.Empty(t, updateResp.GetItem().HostSourceIds)
|
||||
}
|
||||
|
||||
func TestCreateTarget_DirectlyAttachedAddress(t *testing.T) {
|
||||
tc := controller.NewTestController(t, nil)
|
||||
t.Cleanup(tc.Shutdown)
|
||||
|
||||
client := tc.Client()
|
||||
at := tc.Token()
|
||||
client.SetToken(at.Token)
|
||||
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(at.UserId))
|
||||
tClient := targets.NewClient(client)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
address string
|
||||
}{
|
||||
{
|
||||
name: "target-ipv4-address",
|
||||
address: "127.0.0.1",
|
||||
},
|
||||
{
|
||||
name: "target-dns-address",
|
||||
address: "null",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
createResp, err := tClient.Create(tc.Context(), "tcp", proj.PublicId,
|
||||
targets.WithName(tt.name), targets.WithAddress(tt.address), targets.WithTcpTargetDefaultPort(22))
|
||||
require.NoError(err)
|
||||
require.NotNil(createResp)
|
||||
assert.Equal(tt.address, createResp.GetItem().Address)
|
||||
|
||||
targetId := createResp.GetItem().Id
|
||||
version := createResp.GetItem().Version
|
||||
readResp, err := tClient.Read(tc.Context(), targetId)
|
||||
require.NoError(err)
|
||||
require.NotNil(readResp)
|
||||
assert.Equal(tt.address, readResp.GetItem().Address)
|
||||
|
||||
updateResp, err := tClient.Update(tc.Context(), targetId, version, targets.DefaultAddress())
|
||||
require.NoError(err)
|
||||
require.NotNil(updateResp)
|
||||
assert.Empty(updateResp.GetItem().Address)
|
||||
|
||||
readResp, err = tClient.Read(tc.Context(), targetId)
|
||||
require.NoError(err)
|
||||
require.NotNil(readResp)
|
||||
assert.Empty(readResp.GetItem().Address)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func comparableSlice(in []*targets.Target) []targets.Target {
|
||||
var filtered []targets.Target
|
||||
for _, i := range in {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
load _authorized_actions
|
||||
|
||||
export TGT_NAME='test'
|
||||
export TGT_NAME_WITH_ADDR='test-address'
|
||||
|
||||
function create_tcp_target() {
|
||||
local sid=$1
|
||||
@@ -13,6 +14,19 @@ function create_tcp_target() {
|
||||
-format json
|
||||
}
|
||||
|
||||
function create_tcp_target_with_addr() {
|
||||
local sid=$1
|
||||
local addr=$2
|
||||
local port=$3
|
||||
local name=$4
|
||||
boundary targets create tcp \
|
||||
-address $addr \
|
||||
-default-port $port \
|
||||
-name $name \
|
||||
-scope-id $sid \
|
||||
-format json
|
||||
}
|
||||
|
||||
function read_target() {
|
||||
boundary targets read -id $1 -format json
|
||||
}
|
||||
@@ -25,12 +39,24 @@ function list_targets() {
|
||||
boundary targets list -scope-id $1 -format json
|
||||
}
|
||||
|
||||
function update_address() {
|
||||
local id=$1
|
||||
local addr=$2
|
||||
boundary targets update tcp -id $id -address $2
|
||||
}
|
||||
|
||||
function assoc_host_sources() {
|
||||
local id=$1
|
||||
local hst=$2
|
||||
boundary targets add-host-sources -id $id -host-source $hst
|
||||
}
|
||||
|
||||
function remove_host_sources() {
|
||||
local id=$1
|
||||
local hst=$2
|
||||
boundary targets remove-host-sources -id $id -host-source $hst
|
||||
}
|
||||
|
||||
function target_id_from_name() {
|
||||
local sid=$1
|
||||
local name=$2
|
||||
|
||||
@@ -100,3 +100,36 @@ load _helpers
|
||||
run read_target $id
|
||||
[ "$status" -eq 1 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: create target with a network address" {
|
||||
run create_tcp_target_with_addr $DEFAULT_P_ID "localhost" 22 $TGT_NAME_WITH_ADDR
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: cannot assign an host source to a target with an address" {
|
||||
local id=$(target_id_from_name $DEFAULT_P_ID $TGT_NAME_WITH_ADDR)
|
||||
run assoc_host_sources $id $DEFAULT_HOST_SET
|
||||
[ "$status" -eq 1 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: can assign an host source to a target after deleting address" {
|
||||
local id=$(target_id_from_name $DEFAULT_P_ID $TGT_NAME_WITH_ADDR)
|
||||
run update_address $id "null"
|
||||
[ "$status" -eq 0 ]
|
||||
run assoc_host_sources $id $DEFAULT_HOST_SET
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: cannot assign an address to a target with an host source" {
|
||||
local id=$(target_id_from_name $DEFAULT_P_ID $TGT_NAME_WITH_ADDR)
|
||||
run update_address $id "localhost"
|
||||
[ "$status" -eq 1 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: can assign an an address to a target after deleting host source" {
|
||||
local id=$(target_id_from_name $DEFAULT_P_ID $TGT_NAME_WITH_ADDR)
|
||||
run remove_host_sources $id $DEFAULT_HOST_SET
|
||||
[ "$status" -eq 0 ]
|
||||
run update_address $id "localhost"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
@@ -372,6 +372,8 @@ type Target struct {
|
||||
Attrs isTarget_Attrs `protobuf_oneof:"attrs"`
|
||||
// Output only. The available actions on this resource for this user.
|
||||
AuthorizedActions []string `protobuf:"bytes,300,rep,name=authorized_actions,proto3" json:"authorized_actions,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
// Optional string value that represents a network resource and is used when establishing a session.
|
||||
Address *wrapperspb.StringValue `protobuf:"bytes,540,opt,name=address,proto3" json:"address,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
}
|
||||
|
||||
func (x *Target) Reset() {
|
||||
@@ -598,6 +600,13 @@ func (x *Target) GetAuthorizedActions() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Target) GetAddress() *wrapperspb.StringValue {
|
||||
if x != nil {
|
||||
return x.Address
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type isTarget_Attrs interface {
|
||||
isTarget_Attrs()
|
||||
}
|
||||
@@ -1234,7 +1243,7 @@ var file_controller_api_resources_targets_v1_target_proto_rawDesc = []byte{
|
||||
0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x64,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x52, 0x12, 0x63, 0x72,
|
||||
0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79,
|
||||
0x22, 0xe8, 0x13, 0x0a, 0x06, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
||||
0x22, 0xbd, 0x14, 0x0a, 0x06, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
||||
0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73,
|
||||
0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73,
|
||||
0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65,
|
||||
@@ -1379,122 +1388,127 @@ var file_controller_api_resources_targets_v1_target_proto_rawDesc = []byte{
|
||||
0x67, 0x65, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2f, 0x0a,
|
||||
0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x18, 0xac, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x75, 0x74, 0x68,
|
||||
0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x07,
|
||||
0x0a, 0x05, 0x61, 0x74, 0x74, 0x72, 0x73, 0x4a, 0x06, 0x08, 0x96, 0x01, 0x10, 0x97, 0x01, 0x4a,
|
||||
0x06, 0x08, 0xb4, 0x01, 0x10, 0xb5, 0x01, 0x4a, 0x06, 0x08, 0xf4, 0x03, 0x10, 0xf5, 0x03, 0x4a,
|
||||
0x06, 0x08, 0xfe, 0x03, 0x10, 0xff, 0x03, 0x4a, 0x04, 0x08, 0x64, 0x10, 0x65, 0x4a, 0x04, 0x08,
|
||||
0x6e, 0x10, 0x6f, 0x52, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x6c, 0x69, 0x62, 0x72,
|
||||
0x61, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x52, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f,
|
||||
0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x52, 0x1c, 0x65, 0x67, 0x72, 0x65, 0x73,
|
||||
0x73, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x52, 0x19, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f,
|
||||
0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
||||
0x65, 0x73, 0x52, 0x0c, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x73,
|
||||
0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x73, 0x22, 0x87, 0x01, 0x0a, 0x13,
|
||||
0x54, 0x63, 0x70, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
|
||||
0x74, 0x65, 0x73, 0x12, 0x70, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70,
|
||||
0x6f, 0x72, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74,
|
||||
0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x2e, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29,
|
||||
0x26, 0x0a, 0x17, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65,
|
||||
0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x0b, 0x44, 0x65, 0x66, 0x61,
|
||||
0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74,
|
||||
0x5f, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x87, 0x01, 0x0a, 0x13, 0x53, 0x73, 0x68, 0x54, 0x61, 0x72,
|
||||
0x67, 0x65, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x70, 0x0a,
|
||||
0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0a, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x42, 0x2e, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x26, 0x0a, 0x17, 0x61, 0x74, 0x74,
|
||||
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f,
|
||||
0x70, 0x6f, 0x72, 0x74, 0x12, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72,
|
||||
0x74, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x22,
|
||||
0x26, 0x0a, 0x0a, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a,
|
||||
0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0xed, 0x03, 0x0a, 0x18, 0x53, 0x65, 0x73, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x44, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x5f, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f,
|
||||
0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61,
|
||||
0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f,
|
||||
0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f,
|
||||
0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
|
||||
0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x63,
|
||||
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18,
|
||||
0x5a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69,
|
||||
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x78, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65,
|
||||
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x70, 0x72, 0x69,
|
||||
0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x82, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||
0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07,
|
||||
0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x8c, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x68, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69,
|
||||
0x6e, 0x74, 0x18, 0x8d, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f,
|
||||
0x69, 0x6e, 0x74, 0x12, 0x52, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x6e,
|
||||
0x66, 0x6f, 0x18, 0x96, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0xeb, 0x03, 0x0a, 0x14, 0x53, 0x65, 0x73, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64,
|
||||
0x12, 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x43,
|
||||
0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72,
|
||||
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x73, 0x63,
|
||||
0x6f, 0x70, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
|
||||
0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x32,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x12, 0x20, 0x0a,
|
||||
0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x3c, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x12,
|
||||
0x18, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x46, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70,
|
||||
0x65, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x30, 0x0a,
|
||||
0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x53,
|
||||
0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x9c, 0x04, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x1a,
|
||||
0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x12, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
|
||||
0x73, 0x12, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72,
|
||||
0x65, 0x73, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x61, 0x74, 0x74, 0x72, 0x73, 0x4a, 0x06, 0x08, 0x96,
|
||||
0x01, 0x10, 0x97, 0x01, 0x4a, 0x06, 0x08, 0xb4, 0x01, 0x10, 0xb5, 0x01, 0x4a, 0x06, 0x08, 0xf4,
|
||||
0x03, 0x10, 0xf5, 0x03, 0x4a, 0x06, 0x08, 0xfe, 0x03, 0x10, 0xff, 0x03, 0x4a, 0x04, 0x08, 0x64,
|
||||
0x10, 0x65, 0x4a, 0x04, 0x08, 0x6e, 0x10, 0x6f, 0x52, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c,
|
||||
0x5f, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x52, 0x20, 0x61, 0x70,
|
||||
0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e,
|
||||
0x74, 0x69, 0x61, 0x6c, 0x5f, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x52, 0x1c,
|
||||
0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61,
|
||||
0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x52, 0x19, 0x65, 0x67,
|
||||
0x72, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f,
|
||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x0c, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65,
|
||||
0x74, 0x5f, 0x69, 0x64, 0x73, 0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x73,
|
||||
0x22, 0x87, 0x01, 0x0a, 0x13, 0x54, 0x63, 0x70, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x74,
|
||||
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x70, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61,
|
||||
0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c,
|
||||
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
|
||||
0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x2e, 0xa0, 0xda,
|
||||
0x29, 0x01, 0xc2, 0xdd, 0x29, 0x26, 0x0a, 0x17, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
|
||||
0x65, 0x73, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x12,
|
||||
0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x0c, 0x64, 0x65,
|
||||
0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x87, 0x01, 0x0a, 0x13, 0x53,
|
||||
0x73, 0x68, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
|
||||
0x65, 0x73, 0x12, 0x70, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f,
|
||||
0x72, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33,
|
||||
0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x2e, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x26,
|
||||
0x0a, 0x17, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x66,
|
||||
0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75,
|
||||
0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f,
|
||||
0x70, 0x6f, 0x72, 0x74, 0x22, 0x26, 0x0a, 0x0a, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e,
|
||||
0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0a, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0xed, 0x03, 0x0a,
|
||||
0x18, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x73,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73,
|
||||
0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x72,
|
||||
0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65,
|
||||
0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||
0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70,
|
||||
0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x3e, 0x0a, 0x0c,
|
||||
0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c,
|
||||
0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04,
|
||||
0x74, 0x79, 0x70, 0x65, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
|
||||
0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c,
|
||||
0x69, 0x6d, 0x69, 0x74, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x6e,
|
||||
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x20, 0x0a, 0x0b,
|
||||
0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x78, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x21,
|
||||
0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x82, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65,
|
||||
0x79, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x8c, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x68, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x08, 0x65,
|
||||
0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x8d, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x52, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x96, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f,
|
||||
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52,
|
||||
0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0xeb, 0x03, 0x0a,
|
||||
0x14, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x5f, 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x1e, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63,
|
||||
0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x6e, 0x66,
|
||||
0x6f, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61,
|
||||
0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
|
||||
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
|
||||
0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61,
|
||||
0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x32, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f,
|
||||
0x69, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65,
|
||||
0x74, 0x5f, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x46, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x12,
|
||||
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79,
|
||||
0x70, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x13, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74,
|
||||
0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x61, 0x75, 0x74, 0x68,
|
||||
0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12,
|
||||
0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x64, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x58, 0x0a, 0x0b, 0x63,
|
||||
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x18, 0x6e, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70,
|
||||
0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67,
|
||||
0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x72,
|
||||
0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e,
|
||||
0x74, 0x69, 0x61, 0x6c, 0x73, 0x22, 0x54, 0x0a, 0x1a, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12,
|
||||
0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x17,
|
||||
0x53, 0x73, 0x68, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x43, 0x72, 0x65,
|
||||
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b,
|
||||
0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,
|
||||
0x65, 0x4b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x16, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f,
|
||||
0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79,
|
||||
0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x42, 0x50, 0x5a, 0x4e, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f,
|
||||
0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x73, 0x64, 0x6b, 0x2f,
|
||||
0x70, 0x62, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61,
|
||||
0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x74, 0x61, 0x72,
|
||||
0x67, 0x65, 0x74, 0x73, 0x3b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x33,
|
||||
0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
||||
0x18, 0x64, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
||||
0x12, 0x58, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x18,
|
||||
0x6e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
|
||||
0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x0b, 0x63,
|
||||
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x22, 0x54, 0x0a, 0x1a, 0x55, 0x73,
|
||||
0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x72,
|
||||
0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
|
||||
0x22, 0x8c, 0x01, 0x0a, 0x17, 0x53, 0x73, 0x68, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b,
|
||||
0x65, 0x79, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08,
|
||||
0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76,
|
||||
0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70,
|
||||
0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x16, 0x70, 0x72, 0x69,
|
||||
0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72,
|
||||
0x61, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x70, 0x72, 0x69, 0x76, 0x61,
|
||||
0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x42,
|
||||
0x50, 0x5a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61,
|
||||
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79,
|
||||
0x2f, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x62, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||
0x73, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x3b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -1552,19 +1566,20 @@ var file_controller_api_resources_targets_v1_target_proto_depIdxs = []int32{
|
||||
12, // 18: controller.api.resources.targets.v1.Target.attributes:type_name -> google.protobuf.Struct
|
||||
5, // 19: controller.api.resources.targets.v1.Target.tcp_target_attributes:type_name -> controller.api.resources.targets.v1.TcpTargetAttributes
|
||||
6, // 20: controller.api.resources.targets.v1.Target.ssh_target_attributes:type_name -> controller.api.resources.targets.v1.SshTargetAttributes
|
||||
16, // 21: controller.api.resources.targets.v1.TcpTargetAttributes.default_port:type_name -> google.protobuf.UInt32Value
|
||||
16, // 22: controller.api.resources.targets.v1.SshTargetAttributes.default_port:type_name -> google.protobuf.UInt32Value
|
||||
13, // 23: controller.api.resources.targets.v1.SessionAuthorizationData.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo
|
||||
15, // 24: controller.api.resources.targets.v1.SessionAuthorizationData.created_time:type_name -> google.protobuf.Timestamp
|
||||
7, // 25: controller.api.resources.targets.v1.SessionAuthorizationData.worker_info:type_name -> controller.api.resources.targets.v1.WorkerInfo
|
||||
13, // 26: controller.api.resources.targets.v1.SessionAuthorization.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo
|
||||
15, // 27: controller.api.resources.targets.v1.SessionAuthorization.created_time:type_name -> google.protobuf.Timestamp
|
||||
3, // 28: controller.api.resources.targets.v1.SessionAuthorization.credentials:type_name -> controller.api.resources.targets.v1.SessionCredential
|
||||
29, // [29:29] is the sub-list for method output_type
|
||||
29, // [29:29] is the sub-list for method input_type
|
||||
29, // [29:29] is the sub-list for extension type_name
|
||||
29, // [29:29] is the sub-list for extension extendee
|
||||
0, // [0:29] is the sub-list for field type_name
|
||||
14, // 21: controller.api.resources.targets.v1.Target.address:type_name -> google.protobuf.StringValue
|
||||
16, // 22: controller.api.resources.targets.v1.TcpTargetAttributes.default_port:type_name -> google.protobuf.UInt32Value
|
||||
16, // 23: controller.api.resources.targets.v1.SshTargetAttributes.default_port:type_name -> google.protobuf.UInt32Value
|
||||
13, // 24: controller.api.resources.targets.v1.SessionAuthorizationData.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo
|
||||
15, // 25: controller.api.resources.targets.v1.SessionAuthorizationData.created_time:type_name -> google.protobuf.Timestamp
|
||||
7, // 26: controller.api.resources.targets.v1.SessionAuthorizationData.worker_info:type_name -> controller.api.resources.targets.v1.WorkerInfo
|
||||
13, // 27: controller.api.resources.targets.v1.SessionAuthorization.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo
|
||||
15, // 28: controller.api.resources.targets.v1.SessionAuthorization.created_time:type_name -> google.protobuf.Timestamp
|
||||
3, // 29: controller.api.resources.targets.v1.SessionAuthorization.credentials:type_name -> controller.api.resources.targets.v1.SessionCredential
|
||||
30, // [30:30] is the sub-list for method output_type
|
||||
30, // [30:30] is the sub-list for method input_type
|
||||
30, // [30:30] is the sub-list for extension type_name
|
||||
30, // [30:30] is the sub-list for extension extendee
|
||||
0, // [0:30] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_controller_api_resources_targets_v1_target_proto_init() }
|
||||
|
||||
@@ -129,7 +129,8 @@ var (
|
||||
// optional controller.custom_options.v1.MaskMapping mask_mapping = 85464;
|
||||
E_MaskMapping = &file_controller_custom_options_v1_options_proto_extTypes[0]
|
||||
// generate_sdk_option is a directive used when generating the SDK to
|
||||
// indicate that an option should be created for the field
|
||||
// indicate that an option should be created for the field. This also controls
|
||||
// API options (DefaultX, WithX functions).
|
||||
//
|
||||
// optional bool generate_sdk_option = 85412;
|
||||
E_GenerateSdkOption = &file_controller_custom_options_v1_options_proto_extTypes[1]
|
||||
|
||||
@@ -61,14 +61,64 @@ func CreateNewTargetCli(t testing.TB, ctx context.Context, projectId string, def
|
||||
return newTargetId
|
||||
}
|
||||
|
||||
// AddHostSourceToTargetCli uses the cli to add a host source (host set or host) to a target
|
||||
func AddHostSourceToTargetCli(t testing.TB, ctx context.Context, targetId string, hostSourceId string) {
|
||||
// CreateNewAddressTargetCli uses the cli to create a new target using an
|
||||
// address in boundary.
|
||||
// Returns the id of the new target.
|
||||
func CreateNewAddressTargetCli(t testing.TB, ctx context.Context, projectId string, defaultPort string, address string) string {
|
||||
output := e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"targets", "create", "tcp",
|
||||
"-scope-id", projectId,
|
||||
"-default-port", defaultPort,
|
||||
"-name", "e2e Target",
|
||||
"-address", address,
|
||||
"-format", "json",
|
||||
),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var newTargetResult targets.TargetCreateResult
|
||||
err := json.Unmarshal(output.Stdout, &newTargetResult)
|
||||
require.NoError(t, err)
|
||||
newTargetId := newTargetResult.Item.Id
|
||||
t.Logf("Created Target: %s", newTargetId)
|
||||
|
||||
return newTargetId
|
||||
}
|
||||
|
||||
// AddHostSourceToTargetCli uses the cli to add a host source (host set or host)
|
||||
// to a target.
|
||||
// Boundary's `add-host-sources` functionality appends a new host source to the
|
||||
// existing set of host sources in the target.
|
||||
func AddHostSourceToTargetCli(t testing.TB, ctx context.Context, targetId, hostSourceId string) {
|
||||
output := e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs("targets", "add-host-sources", "-id", targetId, "-host-source", hostSourceId),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
}
|
||||
|
||||
// SetHostSourceToTargetCli uses the cli to set a host source (host set or host)
|
||||
// to a target.
|
||||
// Boundary's `set-host-sources` functionality replaces all existing host sets
|
||||
// on a target with the provided one.
|
||||
func SetHostSourceToTargetCli(t testing.TB, ctx context.Context, targetId, hostSourceId string) {
|
||||
output := e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs("targets", "set-host-sources", "-id", targetId, "-host-source", hostSourceId),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
}
|
||||
|
||||
// RemoveHostSourceFromTargetCli uses the cli to remove a host source (host set or host) to a target
|
||||
func RemoveHostSourceFromTargetCli(t testing.TB, ctx context.Context, targetId, hostSourceId string) {
|
||||
output := e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"targets", "remove-host-sources",
|
||||
"-id", targetId,
|
||||
"-host-source", hostSourceId,
|
||||
),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
}
|
||||
|
||||
// AddCredentialSourceToTargetCli uses the cli to add a credential source (credential library or
|
||||
// credential) to a target
|
||||
func AddCredentialSourceToTargetCli(t testing.TB, ctx context.Context, targetId string, credentialSourceId string) {
|
||||
|
||||
@@ -0,0 +1,340 @@
|
||||
package static_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/testing/internal/e2e"
|
||||
"github.com/hashicorp/boundary/testing/internal/e2e/boundary"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestCliCreateUpdateTargetAddress asserts that creating and updating a target
|
||||
// using a valid address is successful.
|
||||
func TestCliCreateUpdateTargetAddress(t *testing.T) {
|
||||
e2e.MaybeSkipTest(t)
|
||||
c, err := loadConfig()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
boundary.AuthenticateAdminCli(t, ctx)
|
||||
newOrgId := boundary.CreateNewOrgCli(t, ctx)
|
||||
t.Cleanup(func() {
|
||||
ctx := context.Background()
|
||||
boundary.AuthenticateAdminCli(t, ctx)
|
||||
output := e2e.RunCommand(ctx, "boundary", e2e.WithArgs("scopes", "delete", "-id", newOrgId))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
newProjectId := boundary.CreateNewProjectCli(t, ctx, newOrgId)
|
||||
newTargetId := boundary.CreateNewAddressTargetCli(t, ctx, newProjectId, c.TargetPort, c.TargetIp)
|
||||
|
||||
// Connect to target and print host's IP address
|
||||
output := e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"connect",
|
||||
"-target-id", newTargetId,
|
||||
"-exec", "/usr/bin/ssh", "--",
|
||||
"-l", c.TargetSshUser,
|
||||
"-i", c.TargetSshKeyPath,
|
||||
"-o", "UserKnownHostsFile=/dev/null",
|
||||
"-o", "StrictHostKeyChecking=no",
|
||||
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
|
||||
"-p", "{{boundary.port}}", // this is provided by boundary
|
||||
"{{boundary.ip}}",
|
||||
"hostname", "-i",
|
||||
),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
parts := strings.Fields(string(output.Stdout))
|
||||
hostIp := parts[len(parts)-1]
|
||||
require.Equal(t, c.TargetIp, hostIp, "SSH session did not return expected output")
|
||||
t.Log("Successfully connected to target")
|
||||
|
||||
// Remove target address. We have now no address or host sources.
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"targets", "update", "tcp",
|
||||
"-id", newTargetId,
|
||||
"-address", "null",
|
||||
"-format", "json",
|
||||
),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
// Connect to target and print host's IP address - should error because
|
||||
// there's no place to connect to.
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"connect",
|
||||
"-target-id", newTargetId,
|
||||
"-format", "json",
|
||||
"-exec", "/usr/bin/ssh", "--",
|
||||
"-l", c.TargetSshUser,
|
||||
"-i", c.TargetSshKeyPath,
|
||||
"-o", "UserKnownHostsFile=/dev/null",
|
||||
"-o", "StrictHostKeyChecking=no",
|
||||
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
|
||||
"-p", "{{boundary.port}}", // this is provided by boundary
|
||||
"{{boundary.ip}}",
|
||||
"hostname", "-i",
|
||||
),
|
||||
)
|
||||
require.Error(t, output.Err, string(output.Stderr))
|
||||
|
||||
var response boundary.CliError
|
||||
require.NoError(t, json.Unmarshal(output.Stderr, &response))
|
||||
require.Equal(t, http.StatusNotFound, response.Status, "Expected error when connecting to target with no host sources or address")
|
||||
|
||||
// Add a valid address back in.
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"targets", "update", "tcp",
|
||||
"-id", newTargetId,
|
||||
"-address", c.TargetIp,
|
||||
"-format", "json",
|
||||
),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
// Connect to target and print host's IP address.
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"connect",
|
||||
"-target-id", newTargetId,
|
||||
"-exec", "/usr/bin/ssh", "--",
|
||||
"-l", c.TargetSshUser,
|
||||
"-i", c.TargetSshKeyPath,
|
||||
"-o", "UserKnownHostsFile=/dev/null",
|
||||
"-o", "StrictHostKeyChecking=no",
|
||||
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
|
||||
"-p", "{{boundary.port}}", // this is provided by boundary
|
||||
"{{boundary.ip}}",
|
||||
"hostname", "-i",
|
||||
),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
parts = strings.Fields(string(output.Stdout))
|
||||
hostIp = parts[len(parts)-1]
|
||||
require.Equal(t, c.TargetIp, hostIp, "SSH session did not return expected output")
|
||||
t.Log("Successfully connected to target")
|
||||
}
|
||||
|
||||
// TestCliTargetAddressToHostSource asserts that we can change a target using an
|
||||
// address to a target using host sources only if we remove the address first.
|
||||
// TestCliTargetAddressToHostSource and TestCliTargetHostSourceToAddress are separate,
|
||||
// independent tests because switching between host sources and address is not a
|
||||
// commutative operation (they use different codepaths).
|
||||
func TestCliTargetAddressToHostSource(t *testing.T) {
|
||||
e2e.MaybeSkipTest(t)
|
||||
c, err := loadConfig()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
boundary.AuthenticateAdminCli(t, ctx)
|
||||
newOrgId := boundary.CreateNewOrgCli(t, ctx)
|
||||
t.Cleanup(func() {
|
||||
ctx := context.Background()
|
||||
boundary.AuthenticateAdminCli(t, ctx)
|
||||
output := e2e.RunCommand(ctx, "boundary", e2e.WithArgs("scopes", "delete", "-id", newOrgId))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
newProjectId := boundary.CreateNewProjectCli(t, ctx, newOrgId)
|
||||
newHostCatalogId := boundary.CreateNewHostCatalogCli(t, ctx, newProjectId)
|
||||
newHostSetId := boundary.CreateNewHostSetCli(t, ctx, newHostCatalogId)
|
||||
newHostId := boundary.CreateNewHostCli(t, ctx, newHostCatalogId, c.TargetIp)
|
||||
boundary.AddHostToHostSetCli(t, ctx, newHostSetId, newHostId)
|
||||
newTargetId := boundary.CreateNewAddressTargetCli(t, ctx, newProjectId, c.TargetPort, c.TargetIp)
|
||||
|
||||
// Connect to target and print host's IP address
|
||||
output := e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"connect",
|
||||
"-target-id", newTargetId,
|
||||
"-exec", "/usr/bin/ssh", "--",
|
||||
"-l", c.TargetSshUser,
|
||||
"-i", c.TargetSshKeyPath,
|
||||
"-o", "UserKnownHostsFile=/dev/null",
|
||||
"-o", "StrictHostKeyChecking=no",
|
||||
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
|
||||
"-p", "{{boundary.port}}", // this is provided by boundary
|
||||
"{{boundary.ip}}",
|
||||
"hostname", "-i",
|
||||
),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
parts := strings.Fields(string(output.Stdout))
|
||||
hostIp := parts[len(parts)-1]
|
||||
require.Equal(t, c.TargetIp, hostIp, "SSH session did not return expected output")
|
||||
t.Log("Successfully connected to target")
|
||||
|
||||
// Attempt add-host-sources. Should error because the target has an address.
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"targets", "add-host-sources",
|
||||
"-id", newTargetId,
|
||||
"-host-source", newHostSetId,
|
||||
"-format", "json",
|
||||
),
|
||||
)
|
||||
require.Error(t, output.Err, "Target add-host-sources did not return expected error")
|
||||
|
||||
var response boundary.CliError
|
||||
require.NoError(t, json.Unmarshal(output.Stderr, &response))
|
||||
require.Equal(t, http.StatusBadRequest, response.Status, "Expected error when adding host source to target with an address")
|
||||
|
||||
// Attempt set-host-sources. Should error because the target has an address.
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"targets", "set-host-sources",
|
||||
"-id", newTargetId,
|
||||
"-host-source", newHostSetId,
|
||||
"-format", "json",
|
||||
),
|
||||
)
|
||||
require.Error(t, output.Err, "Target set-host-sources did not return expected error")
|
||||
require.NoError(t, json.Unmarshal(output.Stderr, &response))
|
||||
require.Equal(t, http.StatusBadRequest, response.Status, "Expected error when setting host source to target with an address")
|
||||
|
||||
// Remove the target's address. We should now be able to add/set host
|
||||
// sources.
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"targets", "update", "tcp",
|
||||
"-id", newTargetId,
|
||||
"-address", "null",
|
||||
"-format", "json",
|
||||
),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
boundary.AddHostSourceToTargetCli(t, ctx, newTargetId, newHostSetId)
|
||||
boundary.SetHostSourceToTargetCli(t, ctx, newTargetId, newHostSetId)
|
||||
|
||||
// Connect to target and print host's IP address, now using the host source.
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"connect",
|
||||
"-target-id", newTargetId,
|
||||
"-exec", "/usr/bin/ssh", "--",
|
||||
"-l", c.TargetSshUser,
|
||||
"-i", c.TargetSshKeyPath,
|
||||
"-o", "UserKnownHostsFile=/dev/null",
|
||||
"-o", "StrictHostKeyChecking=no",
|
||||
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
|
||||
"-p", "{{boundary.port}}", // this is provided by boundary
|
||||
"{{boundary.ip}}",
|
||||
"hostname", "-i",
|
||||
),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
parts = strings.Fields(string(output.Stdout))
|
||||
hostIp = parts[len(parts)-1]
|
||||
require.Equal(t, c.TargetIp, hostIp, "SSH session did not return expected output")
|
||||
t.Log("Successfully connected to target")
|
||||
}
|
||||
|
||||
// TestCliTargetHostSourceToAddress asserts that we can change a target using host
|
||||
// source(s) to a target using an address only if we remove the host sources
|
||||
// first.
|
||||
// TestCliTargetAddressToHostSource and TestCliTargetHostSourceToAddress are separate,
|
||||
// independent tests because switching between host sources and address is not a
|
||||
// commutative operation (they use different codepaths).
|
||||
func TestCliTargetHostSourceToAddress(t *testing.T) {
|
||||
e2e.MaybeSkipTest(t)
|
||||
c, err := loadConfig()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
boundary.AuthenticateAdminCli(t, ctx)
|
||||
newOrgId := boundary.CreateNewOrgCli(t, ctx)
|
||||
t.Cleanup(func() {
|
||||
ctx := context.Background()
|
||||
boundary.AuthenticateAdminCli(t, ctx)
|
||||
output := e2e.RunCommand(ctx, "boundary", e2e.WithArgs("scopes", "delete", "-id", newOrgId))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
newProjectId := boundary.CreateNewProjectCli(t, ctx, newOrgId)
|
||||
newHostCatalogId := boundary.CreateNewHostCatalogCli(t, ctx, newProjectId)
|
||||
newHostSetId := boundary.CreateNewHostSetCli(t, ctx, newHostCatalogId)
|
||||
newHostId := boundary.CreateNewHostCli(t, ctx, newHostCatalogId, c.TargetIp)
|
||||
boundary.AddHostToHostSetCli(t, ctx, newHostSetId, newHostId)
|
||||
newTargetId := boundary.CreateNewTargetCli(t, ctx, newProjectId, c.TargetPort)
|
||||
boundary.AddHostSourceToTargetCli(t, ctx, newTargetId, newHostSetId)
|
||||
|
||||
// Connect to target and print host's IP address
|
||||
output := e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"connect",
|
||||
"-target-id", newTargetId,
|
||||
"-exec", "/usr/bin/ssh", "--",
|
||||
"-l", c.TargetSshUser,
|
||||
"-i", c.TargetSshKeyPath,
|
||||
"-o", "UserKnownHostsFile=/dev/null",
|
||||
"-o", "StrictHostKeyChecking=no",
|
||||
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
|
||||
"-p", "{{boundary.port}}", // this is provided by boundary
|
||||
"{{boundary.ip}}",
|
||||
"hostname", "-i",
|
||||
),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
parts := strings.Fields(string(output.Stdout))
|
||||
hostIp := parts[len(parts)-1]
|
||||
require.Equal(t, c.TargetIp, hostIp, "SSH session did not return expected output")
|
||||
t.Log("Successfully connected to target")
|
||||
|
||||
// Attempt to add an address to the target - should error because we have
|
||||
// host sources set.
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"targets", "update", "tcp",
|
||||
"-id", newTargetId,
|
||||
"-address", c.TargetIp,
|
||||
"-format", "json",
|
||||
),
|
||||
)
|
||||
require.Error(t, output.Err, "Target update did not return expected error")
|
||||
|
||||
var response boundary.CliError
|
||||
require.NoError(t, json.Unmarshal(output.Stderr, &response))
|
||||
require.Equal(t, http.StatusBadRequest, response.Status, "Expected error when setting address to target with a host source")
|
||||
|
||||
boundary.RemoveHostSourceFromTargetCli(t, ctx, newTargetId, newHostSetId)
|
||||
|
||||
// Attempt to add an address to the target again - should work
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"targets", "update", "tcp",
|
||||
"-id", newTargetId,
|
||||
"-address", c.TargetIp,
|
||||
"-format", "json",
|
||||
),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
// Connect to target and print host's IP address
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"connect",
|
||||
"-target-id", newTargetId,
|
||||
"-exec", "/usr/bin/ssh", "--",
|
||||
"-l", c.TargetSshUser,
|
||||
"-i", c.TargetSshKeyPath,
|
||||
"-o", "UserKnownHostsFile=/dev/null",
|
||||
"-o", "StrictHostKeyChecking=no",
|
||||
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
|
||||
"-p", "{{boundary.port}}", // this is provided by boundary
|
||||
"{{boundary.ip}}",
|
||||
"hostname", "-i",
|
||||
),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
}
|
||||
@@ -130,8 +130,8 @@ However, a target can be one of many types of targets, and a concrete
|
||||
implementation of a target is a `tcp` type of target. Therefore an extra
|
||||
parameter is required when creating or updating a target:
|
||||
|
||||
- `boundary targets tcp create`
|
||||
- `boundary targets tcp update`
|
||||
- `boundary targets create tcp`
|
||||
- `boundary targets update tcp`
|
||||
|
||||
This allows the CLI to perform proper presentation and validation of parameters
|
||||
and functions for the given type.
|
||||
|
||||
Loaded 100 of 104 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user