Handler for Host CRUDL actions (#287)

This commit is contained in:
Todd Knight authored and GitHub committed 2020-08-20 08:20:26 -07:00
1 parent 8dad85fef4
commit d5678c4f80
33 files changed
+1944 -372

No files matched your search

+11 -9
View File
@@ -14,15 +14,17 @@ import (
)
type Host struct {
Id string `json:"id,omitempty"`
Scope *scopes.ScopeInfo `json:"scope,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
CreatedTime time.Time `json:"created_time,omitempty"`
UpdatedTime time.Time `json:"updated_time,omitempty"`
Version uint32 `json:"version,omitempty"`
Type string `json:"type,omitempty"`
Address string `json:"address,omitempty"`
Id string `json:"id,omitempty"`
Scope *scopes.ScopeInfo `json:"scope,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
CreatedTime time.Time `json:"created_time,omitempty"`
UpdatedTime time.Time `json:"updated_time,omitempty"`
Version uint32 `json:"version,omitempty"`
Type string `json:"type,omitempty"`
HostCatalogId string `json:"host_catalog_id,omitempty"`
HostSetIds []string `json:"host_set_ids,omitempty"`
Attributes map[string]interface{} `json:"attributes,omitempty"`
}
type HostsClient struct {
+116
View File
@@ -0,0 +1,116 @@
package hosts_test
import (
"net/http"
"testing"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hosts"
"github.com/hashicorp/boundary/internal/host/static"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/servers/controller"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestHost_Crud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "paum_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
hc, apiErr, err := hosts.NewHostCatalogsClient(projClient).Create(tc.Context(), "static")
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
checkHost := func(step string, h *hosts.Host, apiErr *api.Error, err error, wantedName string, wantVersion uint32) {
require.NoError(err, step)
if !assert.Nil(apiErr, step) && apiErr.Message != "" {
t.Errorf("ApiError message: %q", apiErr.Message)
}
assert.NotNil(h, "returned no resource", step)
gotName := ""
if h.Name != "" {
gotName = h.Name
}
assert.Equal(wantedName, gotName, step)
assert.Equal(wantVersion, h.Version)
}
hClient := hosts.NewHostsClient(projClient)
h, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithName("foo"), hosts.WithStaticHostAddress("someaddress"))
checkHost("create", h, apiErr, err, "foo", 1)
h, apiErr, err = hClient.Read(tc.Context(), hc.Id, h.Id)
checkHost("read", h, apiErr, err, "foo", 1)
h, apiErr, err = hClient.Update(tc.Context(), hc.Id, h.Id, h.Version, hosts.WithName("bar"))
checkHost("update", h, apiErr, err, "bar", 2)
h, apiErr, err = hClient.Update(tc.Context(), hc.Id, h.Id, h.Version, hosts.DefaultName())
checkHost("update", h, apiErr, err, "", 3)
existed, apiErr, err := hClient.Delete(tc.Context(), hc.Id, h.Id)
assert.NoError(err)
assert.True(existed, "Expected existing catalog when deleted, but it wasn't.")
existed, apiErr, err = hClient.Delete(tc.Context(), hc.Id, h.Id)
assert.NoError(err)
assert.False(existed, "Expected catalog to not exist when deleted, but it did.")
}
// TODO: Get better coverage for expected errors and error formats.
func TestHost_Errors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "paum_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
defer tc.Shutdown()
client := tc.Client()
_, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(proj.GetPublicId())
hc, apiErr, err := hosts.NewHostCatalogsClient(client).Create(tc.Context(), "static")
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
hClient := hosts.NewHostsClient(client)
h, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithName("foo"), hosts.WithStaticHostAddress("someaddress"))
require.NoError(err)
require.Nil(apiErr)
assert.NotNil(h)
_, apiErr, err = hClient.Create(tc.Context(), hc.Id, hosts.WithName("foo"), hosts.WithStaticHostAddress("someaddress"))
require.NoError(err)
assert.NotNil(apiErr)
_, apiErr, err = hClient.Read(tc.Context(), hc.Id, static.HostPrefix+"_doesntexis")
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(apiErr.Status, http.StatusNotFound)
_, apiErr, err = hClient.Read(tc.Context(), hc.Id, "invalid id")
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusForbidden, apiErr.Status)
}
+16 -4
View File
@@ -53,15 +53,27 @@ func WithAutomaticVersioning() Option {
}
}
func WithAddress(inAddress string) Option {
func WithStaticHostAddress(inAddress string) Option {
return func(o *options) {
o.valueMap["address"] = inAddress
raw, ok := o.valueMap["attributes"]
if !ok {
raw = interface{}(map[string]interface{}{})
}
val := raw.(map[string]interface{})
val["address"] = inAddress
o.valueMap["attributes"] = val
}
}
func DefaultAddress() Option {
func DefaultStaticHostAddress() Option {
return func(o *options) {
o.valueMap["address"] = nil
raw, ok := o.valueMap["attributes"]
if !ok {
raw = interface{}(map[string]interface{}{})
}
val := raw.(map[string]interface{})
val["address"] = nil
o.valueMap["attributes"] = val
}
}
+6
View File
@@ -0,0 +1,6 @@
// Code generated by "make api"; DO NOT EDIT.
package hosts
type StaticHostAttributes struct {
Address string `json:"address,omitempty"`
}
+5
View File
@@ -258,6 +258,11 @@ var inputStructs = []*structInfo{
pathArgs: []string{"host-catalog", "host"},
versionEnabled: true,
},
{
inProto: &hosts.StaticHostAttributes{},
outFile: "hosts/static_host_attributes.gen.go",
subtypeName: "StaticHost",
},
{
inProto: &hosts.HostSet{},
outFile: "hosts/host_set.gen.go",
+1 -1
View File
@@ -112,7 +112,7 @@ func (c *CreateCommand) Run(args []string) int {
host, apiErr, err := hosts.NewHostsClient(client).Create(c.Context,
c.flagCatalogId,
hosts.WithAddress(c.flagAddress),
hosts.WithStaticHostAddress(c.flagAddress),
hosts.WithName(c.flagName),
hosts.WithDescription(c.flagDescription))
+15 -11
View File
@@ -1322,13 +1322,6 @@
"$ref": "#/definitions/controller.api.resources.hosts.v1.Host"
}
},
{
"name": "version",
"in": "query",
"required": false,
"type": "integer",
"format": "int64"
},
{
"name": "update_mask",
"in": "query",
@@ -2292,16 +2285,27 @@
"version": {
"type": "integer",
"format": "int64",
"description": "The version can be used in subsequent write requests to ensure this resource\nhas not changed and to fail the write if it has.\nOutput only.",
"readOnly": true
"description": "The version can be used in subsequent write requests to ensure this resource\nhas not changed and to fail the write if it has."
},
"type": {
"type": "string",
"title": "The type of the resource, to help differentiate schemas"
},
"address": {
"host_catalog_id": {
"type": "string",
"title": "The address (DNS or IP name) used to reach the host"
"title": "The host catalog this host set is a part of\nOutput only"
},
"host_set_ids": {
"type": "array",
"items": {
"type": "string"
},
"description": "A list of host sets this host is in\nOutput only.",
"readOnly": true
},
"attributes": {
"type": "object",
"description": "The attributes that are applied for the specific host type."
}
},
"title": "Host contains all fields related to a Host resource"
@@ -8,6 +8,7 @@ package hosts
import (
proto "github.com/golang/protobuf/proto"
_struct "github.com/golang/protobuf/ptypes/struct"
timestamp "github.com/golang/protobuf/ptypes/timestamp"
wrappers "github.com/golang/protobuf/ptypes/wrappers"
scopes "github.com/hashicorp/boundary/internal/gen/controller/api/resources/scopes"
@@ -53,12 +54,17 @@ type Host struct {
UpdatedTime *timestamp.Timestamp `protobuf:"bytes,60,opt,name=updated_time,proto3" json:"updated_time,omitempty"`
// The version can be used in subsequent write requests to ensure this resource
// has not changed and to fail the write if it has.
// Output only.
Version uint32 `protobuf:"varint,70,opt,name=version,proto3" json:"version,omitempty"`
// The type of the resource, to help differentiate schemas
Type *wrappers.StringValue `protobuf:"bytes,80,opt,name=type,proto3" json:"type,omitempty"`
// The address (DNS or IP name) used to reach the host
Address *wrappers.StringValue `protobuf:"bytes,90,opt,name=address,proto3" json:"address,omitempty"`
Type string `protobuf:"bytes,80,opt,name=type,proto3" json:"type,omitempty"`
// The host catalog this host set is a part of
// Output only
HostCatalogId string `protobuf:"bytes,90,opt,name=host_catalog_id,proto3" json:"host_catalog_id,omitempty"`
// A list of host sets this host is in
// Output only.
HostSetIds []string `protobuf:"bytes,100,rep,name=host_set_ids,json=hostSetIds,proto3" json:"host_set_ids,omitempty"`
// The attributes that are applied for the specific host type.
Attributes *_struct.Struct `protobuf:"bytes,110,opt,name=attributes,proto3" json:"attributes,omitempty"`
}
func (x *Host) Reset() {
@@ -142,14 +148,76 @@ func (x *Host) GetVersion() uint32 {
return 0
}
func (x *Host) GetType() *wrappers.StringValue {
func (x *Host) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *Host) GetHostCatalogId() string {
if x != nil {
return x.HostCatalogId
}
return ""
}
func (x *Host) GetHostSetIds() []string {
if x != nil {
return x.HostSetIds
}
return nil
}
func (x *Host) GetAddress() *wrappers.StringValue {
func (x *Host) GetAttributes() *_struct.Struct {
if x != nil {
return x.Attributes
}
return nil
}
type StaticHostAttributes struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The address (DNS or IP name) used to reach the host
Address *wrappers.StringValue `protobuf:"bytes,10,opt,name=address,proto3" json:"address,omitempty"`
}
func (x *StaticHostAttributes) Reset() {
*x = StaticHostAttributes{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_api_resources_hosts_v1_host_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *StaticHostAttributes) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StaticHostAttributes) ProtoMessage() {}
func (x *StaticHostAttributes) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_resources_hosts_v1_host_proto_msgTypes[1]
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 StaticHostAttributes.ProtoReflect.Descriptor instead.
func (*StaticHostAttributes) Descriptor() ([]byte, []int) {
return file_controller_api_resources_hosts_v1_host_proto_rawDescGZIP(), []int{1}
}
func (x *StaticHostAttributes) GetAddress() *wrappers.StringValue {
if x != nil {
return x.Address
}
@@ -164,55 +232,68 @@ var file_controller_api_resources_hosts_v1_host_proto_rawDesc = []byte{
0x2f, 0x76, 0x31, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x21,
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, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x76,
0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x1a, 0x2e, 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, 0x73, 0x63, 0x6f,
0x70, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 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, 0x22, 0x91,
0x04, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20,
0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65,
0x18, 0x14, 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, 0x46, 0x0a, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x1e, 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, 0x14, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd,
0x29, 0x0c, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x62, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x18, 0x28, 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, 0x22, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29,
0x1a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b,
0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73,
0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61,
0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x32, 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, 0x3e, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61,
0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x3c, 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, 0x75, 0x70, 0x64, 0x61,
0x74, 0x65, 0x64, 0x5f, 0x74, 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, 0x30, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x50, 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, 0x52, 0x04,
0x74, 0x79, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18,
0x5a, 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, 0x04, 0xa0, 0xda, 0x29, 0x01, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,
0x73, 0x73, 0x42, 0x51, 0x5a, 0x4f, 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,
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x3b,
0x68, 0x6f, 0x73, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x31, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x1a, 0x2e, 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, 0x73, 0x63, 0x6f, 0x70, 0x65,
0x73, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
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, 0x22, 0xc0, 0x04, 0x0a,
0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28,
0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x14,
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, 0x46, 0x0a, 0x04, 0x6e, 0x61,
0x6d, 0x65, 0x18, 0x1e, 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, 0x14, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x0c,
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61,
0x6d, 0x65, 0x12, 0x62, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
0x6e, 0x18, 0x28, 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, 0x22, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x1a, 0x0a,
0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x64, 0x65,
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x32, 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, 0x3e, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x3c, 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, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
0x64, 0x5f, 0x74, 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, 0x28, 0x0a, 0x0f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74,
0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x68,
0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x12, 0x20,
0x0a, 0x0c, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x64,
0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x49, 0x64, 0x73,
0x12, 0x3d, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x6e,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x04, 0xa0,
0xda, 0x29, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22,
0x75, 0x0a, 0x14, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x41, 0x74, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x5d, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,
0x73, 0x73, 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, 0x53, 0x74, 0x72, 0x69, 0x6e,
0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x25, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x1d,
0x0a, 0x12, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 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, 0x51, 0x5a, 0x4f, 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, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x68, 0x6f,
0x73, 0x74, 0x73, 0x3b, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
@@ -227,21 +308,23 @@ func file_controller_api_resources_hosts_v1_host_proto_rawDescGZIP() []byte {
return file_controller_api_resources_hosts_v1_host_proto_rawDescData
}
var file_controller_api_resources_hosts_v1_host_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_controller_api_resources_hosts_v1_host_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_controller_api_resources_hosts_v1_host_proto_goTypes = []interface{}{
(*Host)(nil), // 0: controller.api.resources.hosts.v1.Host
(*scopes.ScopeInfo)(nil), // 1: controller.api.resources.scopes.v1.ScopeInfo
(*wrappers.StringValue)(nil), // 2: google.protobuf.StringValue
(*timestamp.Timestamp)(nil), // 3: google.protobuf.Timestamp
(*StaticHostAttributes)(nil), // 1: controller.api.resources.hosts.v1.StaticHostAttributes
(*scopes.ScopeInfo)(nil), // 2: controller.api.resources.scopes.v1.ScopeInfo
(*wrappers.StringValue)(nil), // 3: google.protobuf.StringValue
(*timestamp.Timestamp)(nil), // 4: google.protobuf.Timestamp
(*_struct.Struct)(nil), // 5: google.protobuf.Struct
}
var file_controller_api_resources_hosts_v1_host_proto_depIdxs = []int32{
1, // 0: controller.api.resources.hosts.v1.Host.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo
2, // 1: controller.api.resources.hosts.v1.Host.name:type_name -> google.protobuf.StringValue
2, // 2: controller.api.resources.hosts.v1.Host.description:type_name -> google.protobuf.StringValue
3, // 3: controller.api.resources.hosts.v1.Host.created_time:type_name -> google.protobuf.Timestamp
3, // 4: controller.api.resources.hosts.v1.Host.updated_time:type_name -> google.protobuf.Timestamp
2, // 5: controller.api.resources.hosts.v1.Host.type:type_name -> google.protobuf.StringValue
2, // 6: controller.api.resources.hosts.v1.Host.address:type_name -> google.protobuf.StringValue
2, // 0: controller.api.resources.hosts.v1.Host.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo
3, // 1: controller.api.resources.hosts.v1.Host.name:type_name -> google.protobuf.StringValue
3, // 2: controller.api.resources.hosts.v1.Host.description:type_name -> google.protobuf.StringValue
4, // 3: controller.api.resources.hosts.v1.Host.created_time:type_name -> google.protobuf.Timestamp
4, // 4: controller.api.resources.hosts.v1.Host.updated_time:type_name -> google.protobuf.Timestamp
5, // 5: controller.api.resources.hosts.v1.Host.attributes:type_name -> google.protobuf.Struct
3, // 6: controller.api.resources.hosts.v1.StaticHostAttributes.address:type_name -> google.protobuf.StringValue
7, // [7:7] is the sub-list for method output_type
7, // [7:7] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
@@ -267,6 +350,18 @@ func file_controller_api_resources_hosts_v1_host_proto_init() {
return nil
}
}
file_controller_api_resources_hosts_v1_host_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*StaticHostAttributes); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
@@ -274,7 +369,7 @@ func file_controller_api_resources_hosts_v1_host_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_controller_api_resources_hosts_v1_host_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
@@ -362,9 +362,8 @@ type UpdateHostRequest struct {
HostCatalogId string `protobuf:"bytes,1,opt,name=host_catalog_id,proto3" json:"host_catalog_id,omitempty"`
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
Version uint32 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"`
Item *hosts.Host `protobuf:"bytes,4,opt,name=item,proto3" json:"item,omitempty"`
UpdateMask *field_mask.FieldMask `protobuf:"bytes,5,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"`
Item *hosts.Host `protobuf:"bytes,3,opt,name=item,proto3" json:"item,omitempty"`
UpdateMask *field_mask.FieldMask `protobuf:"bytes,4,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"`
}
func (x *UpdateHostRequest) Reset() {
@@ -413,13 +412,6 @@ func (x *UpdateHostRequest) GetId() string {
return ""
}
func (x *UpdateHostRequest) GetVersion() uint32 {
if x != nil {
return x.Version
}
return 0
}
func (x *UpdateHostRequest) GetItem() *hosts.Host {
if x != nil {
return x.Item
@@ -636,104 +628,102 @@ var file_controller_api_services_v1_host_service_proto_rawDesc = []byte{
0x0b, 0x32, 0x27, 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, 0x68, 0x6f, 0x73,
0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d,
0x22, 0xe1, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52,
0x22, 0xc7, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63,
0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64,
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x04, 0x69, 0x74,
0x65, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 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, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73,
0x74, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74,
0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46,
0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
0x4d, 0x61, 0x73, 0x6b, 0x22, 0x51, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x6f,
0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x69, 0x74,
0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 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, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73,
0x74, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x4d, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x0f,
0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61,
0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x2e, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07,
0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65,
0x78, 0x69, 0x73, 0x74, 0x65, 0x64, 0x32, 0x81, 0x08, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xc0, 0x01, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x48, 0x6f,
0x73, 0x74, 0x12, 0x2a, 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,
0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b,
0x12, 0x3b, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27,
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, 0x47, 0x65, 0x74, 0x48,
0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5c, 0x82, 0xd3, 0xe4,
0x93, 0x02, 0x3f, 0x12, 0x37, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f,
0x2a, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2f,
0x7b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64,
0x7d, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74,
0x65, 0x6d, 0x92, 0x41, 0x14, 0x12, 0x12, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69,
0x6e, 0x67, 0x6c, 0x65, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x12, 0xd1, 0x01, 0x0a, 0x09, 0x4c, 0x69,
0x73, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x2c, 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, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 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, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x67, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x12, 0x32, 0x2f, 0x76,
0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d,
0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x7b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63,
0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x73,
0x92, 0x41, 0x2a, 0x12, 0x28, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x48, 0x6f,
0x73, 0x74, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63,
0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0xcc, 0x01,
0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x2d, 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, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x2e,
0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x3b, 0x0a,
0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x04, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a,
0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x51, 0x0a, 0x12, 0x55, 0x70,
0x64, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x3b, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27,
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, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x2e,
0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x4d, 0x0a,
0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61, 0x6c,
0x6f, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x68, 0x6f, 0x73,
0x74, 0x5f, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02,
0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x2e, 0x0a, 0x12,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x64, 0x32, 0x81, 0x08, 0x0a,
0x0b, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xc0, 0x01, 0x0a,
0x07, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x2a, 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, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 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, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x5c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3f, 0x12, 0x37, 0x2f, 0x76, 0x31, 0x2f, 0x73,
0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74,
0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x7b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61,
0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x2f, 0x7b, 0x69,
0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x14, 0x12, 0x12, 0x47, 0x65, 0x74,
0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x12,
0xd1, 0x01, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x2c, 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, 0x4c, 0x69, 0x73, 0x74, 0x48,
0x6f, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 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, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48,
0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, 0x82, 0xd3, 0xe4,
0x93, 0x02, 0x40, 0x22, 0x32, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f,
0x2a, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2f,
0x7b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64,
0x7d, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69,
0x74, 0x65, 0x6d, 0x92, 0x41, 0x16, 0x12, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x61,
0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x12, 0xca, 0x01, 0x0a,
0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x2d, 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, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48,
0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 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, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x6f,
0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5d, 0x82, 0xd3, 0xe4, 0x93,
0x02, 0x45, 0x32, 0x37, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a,
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x6f, 0x73,
0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x67, 0x82, 0xd3, 0xe4, 0x93,
0x02, 0x34, 0x12, 0x32, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a,
0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x7b,
0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x7d,
0x2f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x04, 0x69, 0x74, 0x65,
0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x0f, 0x12, 0x0d, 0x55, 0x70, 0x64, 0x61,
0x74, 0x65, 0x20, 0x61, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x12, 0xbe, 0x01, 0x0a, 0x0a, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x2d, 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, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 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, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x51, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x2a,
0x37, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x68, 0x6f,
0x73, 0x74, 0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x7b, 0x68, 0x6f, 0x73,
0x74, 0x5f, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x68, 0x6f,
0x73, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x92, 0x41, 0x0f, 0x12, 0x0d, 0x44, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x20, 0x61, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x42, 0x4d, 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, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
0x2f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x92, 0x41, 0x2a, 0x12, 0x28, 0x4c, 0x69, 0x73, 0x74, 0x20,
0x61, 0x6c, 0x6c, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68,
0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x63, 0x61, 0x74, 0x61,
0x6c, 0x6f, 0x67, 0x12, 0xcc, 0x01, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6f,
0x73, 0x74, 0x12, 0x2d, 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,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x2e, 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, 0x43,
0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x5f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x40, 0x22, 0x32, 0x2f, 0x76, 0x31, 0x2f, 0x73,
0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74,
0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x7b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61,
0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x3a, 0x04, 0x69,
0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x16, 0x12, 0x14, 0x43, 0x72,
0x65, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x48, 0x6f,
0x73, 0x74, 0x12, 0xca, 0x01, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73,
0x74, 0x12, 0x2d, 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, 0x55,
0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x2e, 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, 0x55, 0x70,
0x64, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x5d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x45, 0x32, 0x37, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63,
0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74, 0x61,
0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x7b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61, 0x6c,
0x6f, 0x67, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64,
0x7d, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x0f,
0x12, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x12,
0xbe, 0x01, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x2d,
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, 0x44, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 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, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x51, 0x82,
0xd3, 0xe4, 0x93, 0x02, 0x39, 0x2a, 0x37, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65,
0x73, 0x2f, 0x2a, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67,
0x73, 0x2f, 0x7b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f,
0x69, 0x64, 0x7d, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x92, 0x41,
0x0f, 0x12, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x20, 0x61, 0x20, 0x48, 0x6f, 0x73, 0x74,
0x42, 0x4d, 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, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -947,11 +937,37 @@ const _ = grpc.SupportPackageIsVersion6
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type HostServiceClient interface {
// This retrieves the host specified in the request using the basic view.
// GetHost returns a stored Host if present. The provided request
// must include the host catalog and host ID for the resource being
// retrieved. If any of those IDs are missing, malformed or reference a
// non existing resource an error is returned.
GetHost(ctx context.Context, in *GetHostRequest, opts ...grpc.CallOption) (*GetHostResponse, error)
// ListHosts returns a list of stored hosts which exist inside the scope
// referenced inside the request. The request must include the scope ID and
// the host catalog id for the hosts being retrieved. If the any of those
// are missing, malformed, or reference a non existing scope, an error is
// returned.
ListHosts(ctx context.Context, in *ListHostsRequest, opts ...grpc.CallOption) (*ListHostsResponse, error)
// CreateHost creates and stores a host in boundary. The provided
// request must include the scope and host catalog ids in which the host
// will be created. If the scope or catalog id is missing, malformed or references a
// non existing resource, an error is returned. If a name is provided that
// is in use by another host in the same host catalog, an error is returned.
CreateHost(ctx context.Context, in *CreateHostRequest, opts ...grpc.CallOption) (*CreateHostResponse, error)
// UpdateHost updates an existing host in boundary. The provided
// host must not have any read only fields set. The update mask must be
// included in the request and contain at least 1 mutable field. To unset
// a field's value, include the field in the update mask and don't set it
// in the provided host. An error is returned if either the scope
// or host catalog or host ids are missing or reference a non existing
// resource. An error is also returned if the request attempts to update the
// name to one that is already in use in this host catalog.
UpdateHost(ctx context.Context, in *UpdateHostRequest, opts ...grpc.CallOption) (*UpdateHostResponse, error)
// DeleteHost removes a host from Boundary. If the provided scope,
// host catalog, or host ids are malformed or not provided an error is
// returned. No error is returned if any of the ids reference resources that
// do not exist since the response itself specifies if the resource existed
// before the DeleteHost request was received.
DeleteHost(ctx context.Context, in *DeleteHostRequest, opts ...grpc.CallOption) (*DeleteHostResponse, error)
}
@@ -1010,11 +1026,37 @@ func (c *hostServiceClient) DeleteHost(ctx context.Context, in *DeleteHostReques
// HostServiceServer is the server API for HostService service.
type HostServiceServer interface {
// This retrieves the host specified in the request using the basic view.
// GetHost returns a stored Host if present. The provided request
// must include the host catalog and host ID for the resource being
// retrieved. If any of those IDs are missing, malformed or reference a
// non existing resource an error is returned.
GetHost(context.Context, *GetHostRequest) (*GetHostResponse, error)
// ListHosts returns a list of stored hosts which exist inside the scope
// referenced inside the request. The request must include the scope ID and
// the host catalog id for the hosts being retrieved. If the any of those
// are missing, malformed, or reference a non existing scope, an error is
// returned.
ListHosts(context.Context, *ListHostsRequest) (*ListHostsResponse, error)
// CreateHost creates and stores a host in boundary. The provided
// request must include the scope and host catalog ids in which the host
// will be created. If the scope or catalog id is missing, malformed or references a
// non existing resource, an error is returned. If a name is provided that
// is in use by another host in the same host catalog, an error is returned.
CreateHost(context.Context, *CreateHostRequest) (*CreateHostResponse, error)
// UpdateHost updates an existing host in boundary. The provided
// host must not have any read only fields set. The update mask must be
// included in the request and contain at least 1 mutable field. To unset
// a field's value, include the field in the update mask and don't set it
// in the provided host. An error is returned if either the scope
// or host catalog or host ids are missing or reference a non existing
// resource. An error is also returned if the request attempts to update the
// name to one that is already in use in this host catalog.
UpdateHost(context.Context, *UpdateHostRequest) (*UpdateHostResponse, error)
// DeleteHost removes a host from Boundary. If the provided scope,
// host catalog, or host ids are malformed or not provided an error is
// returned. No error is returned if any of the ids reference resources that
// do not exist since the response itself specifies if the resource existed
// before the DeleteHost request was received.
DeleteHost(context.Context, *DeleteHostRequest) (*DeleteHostResponse, error)
}
@@ -1951,11 +1951,11 @@ type RoleServiceClient interface {
// ID is missing, malformed, or references a non-existing resource, an
// error is returned. It is not an error to have duplicate grants.
SetRoleGrants(ctx context.Context, in *SetRoleGrantsRequest, opts ...grpc.CallOption) (*SetRoleGrantsResponse, error)
// RemoveRoleGrants removes the users and/or groups from the specified role.
// RemoveRoleGrants removes the grants from the specified role.
// The provided request must include the scope and the role IDs from which the
// users and/or groups will be removed. If either ID is missing, malformed, or
// references a non-existing org, an error is returned. It is not an error to
// have duplicate user/group IDs.
// grants will be removed. If either ID is missing, malformed, or
// references a non-existing scope, an error is returned. It is not an error to
// have duplicate grants.
RemoveRoleGrants(ctx context.Context, in *RemoveRoleGrantsRequest, opts ...grpc.CallOption) (*RemoveRoleGrantsResponse, error)
}
@@ -2127,11 +2127,11 @@ type RoleServiceServer interface {
// ID is missing, malformed, or references a non-existing resource, an
// error is returned. It is not an error to have duplicate grants.
SetRoleGrants(context.Context, *SetRoleGrantsRequest) (*SetRoleGrantsResponse, error)
// RemoveRoleGrants removes the users and/or groups from the specified role.
// RemoveRoleGrants removes the grants from the specified role.
// The provided request must include the scope and the role IDs from which the
// users and/or groups will be removed. If either ID is missing, malformed, or
// references a non-existing org, an error is returned. It is not an error to
// have duplicate user/group IDs.
// grants will be removed. If either ID is missing, malformed, or
// references a non-existing scope, an error is returned. It is not an error to
// have duplicate grants.
RemoveRoleGrants(context.Context, *RemoveRoleGrantsRequest) (*RemoveRoleGrantsResponse, error)
}
@@ -878,26 +878,26 @@ type UserServiceClient interface {
// resource an error is returned.
GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error)
// ListUsers returns a list of stored users which exist inside the org
// referenced inside the request. The request must include the org ID for
// referenced inside the request. The request must include the scope ID for
// the users being retrieved. If the scope ID is missing, malformed, or
// reference a non existing scope, an error is returned.
ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (*ListUsersResponse, error)
// CreateUser creates and stores a user in boundary. The provided
// request must include the org id in which the user will be created.
// If the org id is missing, malformed or references a non existing
// org, an error is returned. If a name is provided that is in
// use in another user in the same org, an error is returned.
// request must include the scope id in which the user will be created.
// If the scope id is missing, malformed or references a non existing
// scope, an error is returned. If a name is provided that is in
// use in another user in the same scope, an error is returned.
CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*CreateUserResponse, error)
// UpdateUser updates an existing user in boundary. The provided
// user must not have any read only fields set. The update mask must be
// included in the request and contain at least 1 mutable field. To unset
// a field's value, include the field in the update mask and don't set it
// in the provided user. An error is returned if either the org
// in the provided user. An error is returned if either the scope
// or user ids are missing or reference a non existing resource. An error
// is also returned if the request attempts to update the name to one that is
// already in use in this org.
// already in use in this scope.
UpdateUser(ctx context.Context, in *UpdateUserRequest, opts ...grpc.CallOption) (*UpdateUserResponse, error)
// DeleteUser removes a user from Boundary. If the provided org or user ids
// DeleteUser removes a user from Boundary. If the provided scope or user ids
// are malformed or not provided an error is returned. No error is returned
// if either ids reference resources that do not exist as the response itself
// specifies if the resource existed before the DeleteUser request was
@@ -966,26 +966,26 @@ type UserServiceServer interface {
// resource an error is returned.
GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error)
// ListUsers returns a list of stored users which exist inside the org
// referenced inside the request. The request must include the org ID for
// referenced inside the request. The request must include the scope ID for
// the users being retrieved. If the scope ID is missing, malformed, or
// reference a non existing scope, an error is returned.
ListUsers(context.Context, *ListUsersRequest) (*ListUsersResponse, error)
// CreateUser creates and stores a user in boundary. The provided
// request must include the org id in which the user will be created.
// If the org id is missing, malformed or references a non existing
// org, an error is returned. If a name is provided that is in
// use in another user in the same org, an error is returned.
// request must include the scope id in which the user will be created.
// If the scope id is missing, malformed or references a non existing
// scope, an error is returned. If a name is provided that is in
// use in another user in the same scope, an error is returned.
CreateUser(context.Context, *CreateUserRequest) (*CreateUserResponse, error)
// UpdateUser updates an existing user in boundary. The provided
// user must not have any read only fields set. The update mask must be
// included in the request and contain at least 1 mutable field. To unset
// a field's value, include the field in the update mask and don't set it
// in the provided user. An error is returned if either the org
// in the provided user. An error is returned if either the scope
// or user ids are missing or reference a non existing resource. An error
// is also returned if the request attempts to update the name to one that is
// already in use in this org.
// already in use in this scope.
UpdateUser(context.Context, *UpdateUserRequest) (*UpdateUserResponse, error)
// DeleteUser removes a user from Boundary. If the provided org or user ids
// DeleteUser removes a user from Boundary. If the provided scope or user ids
// are malformed or not provided an error is returned. No error is returned
// if either ids reference resources that do not exist as the response itself
// specifies if the resource existed before the DeleteUser request was
+1 -1
View File
@@ -16,7 +16,7 @@ func ExampleNewHostCatalog() {
func ExampleNewHost() {
catalogPublicId := "sthc_1234"
host, _ := static.NewHost(catalogPublicId, "127.0.0.1")
host, _ := static.NewHost(catalogPublicId, static.WithAddress("127.0.0.1"))
fmt.Println(host.Address)
// Output:
// 127.0.0.1
+2 -5
View File
@@ -18,19 +18,16 @@ type Host struct {
// NewHost creates a new in memory Host for address assigned to catalogId.
// Name and description are the only valid options. All other options are
// ignored.
func NewHost(catalogId, address string, opt ...Option) (*Host, error) {
func NewHost(catalogId string, opt ...Option) (*Host, error) {
if catalogId == "" {
return nil, fmt.Errorf("new: static host: no catalog id: %w", db.ErrInvalidParameter)
}
if address == "" {
return nil, fmt.Errorf("new: static host: no address: %w", db.ErrInvalidParameter)
}
opts := getOpts(opt...)
host := &Host{
Host: &store.Host{
CatalogId: catalogId,
Address: address,
Address: opts.withAddress,
Name: opts.withName,
Description: opts.withDescription,
},
+1 -22
View File
@@ -109,30 +109,9 @@ func TestHostCatalog_New(t *testing.T) {
}
}
func testCatalogs(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, scopeId string, count int) []*HostCatalog {
t.Helper()
assert := assert.New(t)
var cats []*HostCatalog
for i := 0; i < count; i++ {
cat, err := NewHostCatalog(scopeId)
assert.NoError(err)
assert.NotNil(cat)
id, err := newHostCatalogId()
assert.NoError(err)
assert.NotEmpty(id)
cat.PublicId = id
w := db.New(conn)
err2 := w.Create(context.Background(), cat)
assert.NoError(err2)
cats = append(cats, cat)
}
return cats
}
func testCatalog(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, scopeId string) *HostCatalog {
t.Helper()
cats := testCatalogs(t, conn, wrapper, scopeId, 1)
cats := TestCatalogs(t, conn, scopeId, 1)
return cats[0]
}
+3 -3
View File
@@ -17,17 +17,17 @@ func TestHostSetMember_New(t *testing.T) {
wrapper := db.TestWrapper(t)
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
cats := testCatalogs(t, conn, wrapper, prj.PublicId, 2)
cats := TestCatalogs(t, conn, prj.PublicId, 2)
blueCat := cats[0]
blueSets := testSets(t, conn, blueCat.GetPublicId(), 2)
blueHosts := testHosts(t, conn, blueCat.GetPublicId(), 2)
blueHosts := TestHosts(t, conn, blueCat.GetPublicId(), 2)
// TODO(mgaffney) 05/2020:
// these will be needed when the repository code is done
// greenCat := cats[1]
// greenSets := testSets(t, conn, greenCat.GetPublicId(), 2)
// greenHosts := testHosts(t, conn, greenCat.GetPublicId(), 2)
// greenHosts := TestHosts(t, conn, greenCat.GetPublicId(), 2)
var tests = []struct {
name string
+12 -37
View File
@@ -2,13 +2,11 @@ package static
import (
"context"
"fmt"
"testing"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/host/static/store"
"github.com/hashicorp/boundary/internal/iam"
"github.com/jinzhu/gorm"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -22,7 +20,6 @@ func TestHost_New(t *testing.T) {
conn.LogMode(false)
type args struct {
catalogId string
address string
opts []Option
}
@@ -37,7 +34,6 @@ func TestHost_New(t *testing.T) {
name: "blank-catalogId",
args: args{
catalogId: "",
address: "127.0.0.1",
},
want: nil,
wantCreateErr: true,
@@ -46,16 +42,19 @@ func TestHost_New(t *testing.T) {
name: "blank-address",
args: args{
catalogId: cat.GetPublicId(),
address: "",
},
want: nil,
wantCreateErr: true,
want: &Host{
Host: &store.Host{
CatalogId: cat.GetPublicId(),
},
},
wantWriteErr: true,
},
{
name: "address-to-short",
args: args{
catalogId: cat.GetPublicId(),
address: "1234567",
opts: []Option{WithAddress("1234567")},
},
want: &Host{
Host: &store.Host{
@@ -69,7 +68,7 @@ func TestHost_New(t *testing.T) {
name: "minimum-address",
args: args{
catalogId: cat.GetPublicId(),
address: "12345678",
opts: []Option{WithAddress("12345678")},
},
want: &Host{
Host: &store.Host{
@@ -82,21 +81,20 @@ func TestHost_New(t *testing.T) {
name: "valid-no-options",
args: args{
catalogId: cat.GetPublicId(),
address: "127.0.0.1",
},
want: &Host{
Host: &store.Host{
CatalogId: cat.GetPublicId(),
Address: "127.0.0.1",
},
},
wantWriteErr: true,
},
{
name: "valid-with-name",
args: args{
catalogId: cat.GetPublicId(),
address: "127.0.0.1",
opts: []Option{
WithAddress("127.0.0.1"),
WithName("test-name"),
},
},
@@ -112,8 +110,8 @@ func TestHost_New(t *testing.T) {
name: "valid-with-description",
args: args{
catalogId: cat.GetPublicId(),
address: "127.0.0.1",
opts: []Option{
WithAddress("127.0.0.1"),
WithDescription("test-description"),
},
},
@@ -131,7 +129,7 @@ func TestHost_New(t *testing.T) {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert := assert.New(t)
got, err := NewHost(tt.args.catalogId, tt.args.address, tt.args.opts...)
got, err := NewHost(tt.args.catalogId, tt.args.opts...)
if tt.wantCreateErr {
assert.Error(err)
assert.Nil(got)
@@ -158,29 +156,6 @@ func TestHost_New(t *testing.T) {
}
}
func testHosts(t *testing.T, conn *gorm.DB, catalogId string, count int) []*Host {
t.Helper()
assert := assert.New(t)
var hosts []*Host
for i := 0; i < count; i++ {
host, err := NewHost(catalogId, fmt.Sprintf("%s-%d", catalogId, i))
assert.NoError(err)
assert.NotNil(host)
id, err := newHostCatalogId()
assert.NoError(err)
assert.NotEmpty(id)
host.PublicId = id
w := db.New(conn)
err2 := w.Create(context.Background(), host)
assert.NoError(err2)
hosts = append(hosts, host)
}
return hosts
}
func TestHost_SetTableName(t *testing.T) {
defaultTableName := "static_host"
tests := []struct {
@@ -87,7 +87,7 @@ func TestStaticHost_ImmutableFields(t *testing.T) {
ts := timestamp.Timestamp{Timestamp: &timestamppb.Timestamp{Seconds: 0, Nanos: 0}}
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
cat := testCatalog(t, conn, wrapper, prj.PublicId)
hosts := testHosts(t, conn, cat.GetPublicId(), 1)
hosts := TestHosts(t, conn, cat.GetPublicId(), 1)
new := hosts[0]
@@ -237,7 +237,7 @@ func TestStaticHostSetMember_ImmutableFields(t *testing.T) {
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
cat := testCatalog(t, conn, wrapper, prj.PublicId)
sets := testSets(t, conn, cat.GetPublicId(), 1)
hosts := testHosts(t, conn, cat.GetPublicId(), 1)
hosts := TestHosts(t, conn, cat.GetPublicId(), 1)
new, err := NewHostSetMember(sets[0].PublicId, hosts[0].PublicId)
require.NoError(t, err)
+9
View File
@@ -17,12 +17,14 @@ type options struct {
withName string
withDescription string
withLimit int
withAddress string
}
func getDefaultOptions() options {
return options{
withDescription: "",
withName: "",
withAddress: "",
}
}
@@ -48,3 +50,10 @@ func WithLimit(l int) Option {
o.withLimit = l
}
}
// WithAddress provides an optional address.
func WithAddress(address string) Option {
return func(o *options) {
o.withAddress = address
}
}
+6
View File
@@ -26,4 +26,10 @@ func Test_GetOpts(t *testing.T) {
testOpts.withLimit = 5
assert.Equal(t, opts, testOpts)
})
t.Run("WithAddress", func(t *testing.T) {
opts := getOpts(WithAddress("test"))
testOpts := getDefaultOptions()
testOpts.withAddress = "test"
assert.Equal(t, opts, testOpts)
})
}
@@ -484,7 +484,7 @@ func TestRepository_UpdateCatalog(t *testing.T) {
name := "test-dup-name"
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
cats := testCatalogs(t, conn, wrapper, prj.PublicId, 2)
cats := TestCatalogs(t, conn, prj.PublicId, 2)
c1 := cats[0]
c1.Name = name
got1, gotCount1, err := repo.UpdateCatalog(context.Background(), c1, 1, []string{"name"})
+18 -18
View File
@@ -26,7 +26,7 @@ func TestRepository_CreateHost(t *testing.T) {
kms := kms.TestKms(t, conn, wrapper)
iamRepo := iam.TestRepo(t, conn, wrapper)
_, prj := iam.TestScopes(t, iamRepo)
catalog := testCatalogs(t, conn, wrapper, prj.PublicId, 1)[0]
catalog := TestCatalogs(t, conn, prj.PublicId, 1)[0]
var tests = []struct {
name string
@@ -174,7 +174,7 @@ func TestRepository_CreateHost(t *testing.T) {
require.NotNil(repo)
_, prj := iam.TestScopes(t, iamRepo)
catalog := testCatalogs(t, conn, wrapper, prj.PublicId, 1)[0]
catalog := TestCatalogs(t, conn, prj.PublicId, 1)[0]
in := &Host{
Host: &store.Host{
@@ -205,7 +205,7 @@ func TestRepository_CreateHost(t *testing.T) {
require.NotNil(repo)
_, prj := iam.TestScopes(t, iamRepo)
catalogs := testCatalogs(t, conn, wrapper, prj.PublicId, 2)
catalogs := TestCatalogs(t, conn, prj.PublicId, 2)
catalogA, catalogB := catalogs[0], catalogs[1]
@@ -585,7 +585,7 @@ func TestRepository_UpdateHost(t *testing.T) {
require.NotNil(repo)
_, prj := iam.TestScopes(t, iamRepo)
catalog := testCatalogs(t, conn, wrapper, prj.PublicId, 1)[0]
catalog := TestCatalogs(t, conn, prj.PublicId, 1)[0]
tt.orig.CatalogId = catalog.PublicId
orig, err := repo.CreateHost(context.Background(), prj.GetPublicId(), tt.orig)
@@ -634,8 +634,8 @@ func TestRepository_UpdateHost(t *testing.T) {
name := "test-dup-name"
_, prj := iam.TestScopes(t, iamRepo)
catalog := testCatalogs(t, conn, wrapper, prj.PublicId, 1)[0]
hs := testHosts(t, conn, catalog.PublicId, 2)
catalog := TestCatalogs(t, conn, prj.PublicId, 1)[0]
hs := TestHosts(t, conn, catalog.PublicId, 2)
hA, hB := hs[0], hs[1]
@@ -664,7 +664,7 @@ func TestRepository_UpdateHost(t *testing.T) {
require.NotNil(repo)
_, prj := iam.TestScopes(t, iamRepo)
catalogs := testCatalogs(t, conn, wrapper, prj.PublicId, 2)
catalogs := TestCatalogs(t, conn, prj.PublicId, 2)
catalogA, catalogB := catalogs[0], catalogs[1]
@@ -708,12 +708,12 @@ func TestRepository_UpdateHost(t *testing.T) {
require.NotNil(repo)
_, prj := iam.TestScopes(t, iamRepo)
catalogs := testCatalogs(t, conn, wrapper, prj.PublicId, 2)
catalogs := TestCatalogs(t, conn, prj.PublicId, 2)
catalogA, catalogB := catalogs[0], catalogs[1]
hA := testHosts(t, conn, catalogA.PublicId, 1)[0]
hB := testHosts(t, conn, catalogB.PublicId, 1)[0]
hA := TestHosts(t, conn, catalogA.PublicId, 1)[0]
hB := TestHosts(t, conn, catalogB.PublicId, 1)[0]
assert.NotEqual(hA.CatalogId, hB.CatalogId)
orig := hA.clone()
@@ -739,8 +739,8 @@ func TestRepository_LookupHost(t *testing.T) {
iamRepo := iam.TestRepo(t, conn, wrapper)
_, prj := iam.TestScopes(t, iamRepo)
catalog := testCatalogs(t, conn, wrapper, prj.PublicId, 1)[0]
host := testHosts(t, conn, catalog.PublicId, 1)[0]
catalog := TestCatalogs(t, conn, prj.PublicId, 1)[0]
host := TestHosts(t, conn, catalog.PublicId, 1)[0]
hostId, err := newHostId()
require.NoError(t, err)
@@ -792,10 +792,10 @@ func TestRepository_ListHosts(t *testing.T) {
iamRepo := iam.TestRepo(t, conn, wrapper)
_, prj := iam.TestScopes(t, iamRepo)
catalogs := testCatalogs(t, conn, wrapper, prj.PublicId, 2)
catalogs := TestCatalogs(t, conn, prj.PublicId, 2)
catalogA, catalogB := catalogs[0], catalogs[1]
hosts := testHosts(t, conn, catalogA.PublicId, 3)
hosts := TestHosts(t, conn, catalogA.PublicId, 3)
var tests = []struct {
name string
@@ -851,9 +851,9 @@ func TestRepository_ListHosts_Limits(t *testing.T) {
iamRepo := iam.TestRepo(t, conn, wrapper)
_, prj := iam.TestScopes(t, iamRepo)
catalog := testCatalogs(t, conn, wrapper, prj.PublicId, 1)[0]
catalog := TestCatalogs(t, conn, prj.PublicId, 1)[0]
count := 10
hosts := testHosts(t, conn, catalog.PublicId, count)
hosts := TestHosts(t, conn, catalog.PublicId, count)
var tests = []struct {
name string
@@ -921,8 +921,8 @@ func TestRepository_DeleteHost(t *testing.T) {
iamRepo := iam.TestRepo(t, conn, wrapper)
_, prj := iam.TestScopes(t, iamRepo)
catalog := testCatalogs(t, conn, wrapper, prj.PublicId, 1)[0]
host := testHosts(t, conn, catalog.PublicId, 1)[0]
catalog := TestCatalogs(t, conn, prj.PublicId, 1)[0]
host := TestHosts(t, conn, catalog.PublicId, 1)[0]
newHostId, err := newHostId()
require.NoError(t, err)
+48 -40
View File
@@ -475,7 +475,7 @@ var file_controller_storage_host_static_store_v1_static_proto_rawDesc = []byte{
0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73,
0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x22, 0xc6, 0x02, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62,
0x22, 0x9b, 0x03, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75,
0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f,
@@ -487,45 +487,53 @@ var file_controller_storage_host_static_store_v1_static_proto_rawDesc = []byte{
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, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f,
0x67, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x74, 0x61,
0x6c, 0x6f, 0x67, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12,
0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xaf, 0x02, 0x0a, 0x07, 0x48, 0x6f,
0x73, 0x74, 0x53, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f,
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x49, 0x64, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d,
0x65, 0x18, 0x02, 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, 0x03,
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, 0x12, 0x0a, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 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,
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64,
0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x49,
0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01,
0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5e, 0x0a, 0x0d, 0x48,
0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07,
0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68,
0x6f, 0x73, 0x74, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a,
0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x09, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x49, 0x64, 0x42, 0x40, 0x5a, 0x3e, 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, 0x68, 0x6f, 0x73, 0x74, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x69,
0x63, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
0x12, 0x24, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x10,
0xc2, 0xdd, 0x29, 0x0c, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xc2, 0xdd, 0x29,
0x1a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b,
0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73,
0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x74, 0x61,
0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61,
0x74, 0x61, 0x6c, 0x6f, 0x67, 0x49, 0x64, 0x12, 0x3b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,
0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xc2, 0xdd, 0x29, 0x1d, 0x0a, 0x07,
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
0x74, 0x65, 0x73, 0x2e, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18,
0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xe1,
0x02, 0x0a, 0x07, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75,
0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70,
0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74,
0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 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, 0x03, 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, 0x24, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42,
0x10, 0xc2, 0xdd, 0x29, 0x0c, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xc2, 0xdd,
0x29, 0x1a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12,
0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65,
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x74,
0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63,
0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x22, 0x5e, 0x0a, 0x0d, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x4d, 0x65, 0x6d,
0x62, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06,
0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x65,
0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69,
0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67,
0x49, 0x64, 0x42, 0x40, 0x5a, 0x3e, 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, 0x68, 0x6f, 0x73,
0x74, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x73,
0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
+27
View File
@@ -2,6 +2,7 @@ package static
import (
"context"
"fmt"
"testing"
"github.com/hashicorp/boundary/internal/db"
@@ -32,3 +33,29 @@ func TestCatalogs(t *testing.T, conn *gorm.DB, scopeId string, count int) []*Hos
}
return cats
}
// TestHosts creates count number of static hosts to the provided DB
// with the provided catalog id. The catalog must have been created previously.
// If any errors are encountered during the creation of the host, the test will fail.
func TestHosts(t *testing.T, conn *gorm.DB, catalogId string, count int) []*Host {
t.Helper()
assert := assert.New(t)
var hosts []*Host
for i := 0; i < count; i++ {
host, err := NewHost(catalogId, WithAddress(fmt.Sprintf("%s-%d", catalogId, i)))
assert.NoError(err)
assert.NotNil(host)
id, err := newHostId()
assert.NoError(err)
assert.NotEmpty(id)
host.PublicId = id
w := db.New(conn)
err2 := w.Create(context.Background(), host)
assert.NoError(err2)
hosts = append(hosts, host)
}
return hosts
}
+20
View File
@@ -24,3 +24,23 @@ func Test_TestCatalogs(t *testing.T) {
assert.NotEmpty(c.GetPublicId())
}
}
func Test_TestHosts(t *testing.T) {
t.Helper()
assert, require := assert.New(t), require.New(t)
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
require.NotNil(org)
assert.NotEmpty(org.GetPublicId())
c := TestCatalogs(t, conn, org.GetPublicId(), 1)[0]
count := 4
accounts := TestHosts(t, conn, c.GetPublicId(), count)
assert.Len(accounts, count)
for _, a := range accounts {
assert.NotEmpty(a.GetPublicId())
}
}
@@ -4,6 +4,7 @@ package controller.api.resources.hosts.v1;
option go_package = "github.com/hashicorp/boundary/internal/gen/controller/api/resources/hosts;hosts";
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
import "controller/api/resources/scopes/v1/scope.proto";
@@ -35,12 +36,24 @@ message Host {
// The version can be used in subsequent write requests to ensure this resource
// has not changed and to fail the write if it has.
// Output only.
uint32 version = 70;
// The type of the resource, to help differentiate schemas
google.protobuf.StringValue type = 80;
string type = 80;
// The address (DNS or IP name) used to reach the host
google.protobuf.StringValue address = 90 [(custom_options.v1.generate_sdk_option) = true];
// The host catalog this host set is a part of
// Output only
string host_catalog_id = 90 [json_name="host_catalog_id"];
// A list of host sets this host is in
// Output only.
repeated string host_set_ids = 100;
// The attributes that are applied for the specific host type.
google.protobuf.Struct attributes = 110 [(custom_options.v1.generate_sdk_option) = true];
}
message StaticHostAttributes {
// The address (DNS or IP name) used to reach the host
google.protobuf.StringValue address = 10 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this:"attributes.address" that: "address"}];
}
@@ -10,7 +10,10 @@ import "google/protobuf/field_mask.proto";
import "controller/api/resources/hosts/v1/host.proto";
service HostService {
// This retrieves the host specified in the request using the basic view.
// GetHost returns a stored Host if present. The provided request
// must include the host catalog and host ID for the resource being
// retrieved. If any of those IDs are missing, malformed or reference a
// non existing resource an error is returned.
rpc GetHost(GetHostRequest) returns (GetHostResponse) {
option (google.api.http) = {
get: "/v1/scopes/*/host-catalogs/{host_catalog_id}/hosts/{id}"
@@ -20,6 +23,12 @@ service HostService {
summary: "Gets a single Host"
};
}
// ListHosts returns a list of stored hosts which exist inside the scope
// referenced inside the request. The request must include the scope ID and
// the host catalog id for the hosts being retrieved. If the any of those
// are missing, malformed, or reference a non existing scope, an error is
// returned.
rpc ListHosts(ListHostsRequest) returns (ListHostsResponse) {
option (google.api.http) = {
get: "/v1/scopes/*/host-catalogs/{host_catalog_id}/hosts"
@@ -28,6 +37,12 @@ service HostService {
summary: "List all Hosts for the specified catalog"
};
}
// CreateHost creates and stores a host in boundary. The provided
// request must include the scope and host catalog ids in which the host
// will be created. If the scope or catalog id is missing, malformed or references a
// non existing resource, an error is returned. If a name is provided that
// is in use by another host in the same host catalog, an error is returned.
rpc CreateHost(CreateHostRequest) returns (CreateHostResponse) {
option (google.api.http) = {
post: "/v1/scopes/*/host-catalogs/{host_catalog_id}/hosts"
@@ -38,6 +53,15 @@ service HostService {
summary: "Create a single Host"
};
}
// UpdateHost updates an existing host in boundary. The provided
// host must not have any read only fields set. The update mask must be
// included in the request and contain at least 1 mutable field. To unset
// a field's value, include the field in the update mask and don't set it
// in the provided host. An error is returned if either the scope
// or host catalog or host ids are missing or reference a non existing
// resource. An error is also returned if the request attempts to update the
// name to one that is already in use in this host catalog.
rpc UpdateHost(UpdateHostRequest) returns (UpdateHostResponse) {
option (google.api.http) = {
patch: "/v1/scopes/*/host-catalogs/{host_catalog_id}/hosts/{id}"
@@ -48,6 +72,12 @@ service HostService {
summary: "Update a Host"
};
}
// DeleteHost removes a host from Boundary. If the provided scope,
// host catalog, or host ids are malformed or not provided an error is
// returned. No error is returned if any of the ids reference resources that
// do not exist since the response itself specifies if the resource existed
// before the DeleteHost request was received.
rpc DeleteHost(DeleteHostRequest) returns (DeleteHostResponse) {
option (google.api.http) = {
delete: "/v1/scopes/*/host-catalogs/{host_catalog_id}/hosts/{id}"
@@ -90,9 +120,8 @@ message CreateHostResponse {
message UpdateHostRequest {
string host_catalog_id = 1 [json_name="host_catalog_id"];
string id = 2;
uint32 version = 3;
api.resources.hosts.v1.Host item = 4;
google.protobuf.FieldMask update_mask = 5;
api.resources.hosts.v1.Host item = 3;
google.protobuf.FieldMask update_mask = 4;
}
message UpdateHostResponse {
@@ -166,11 +166,11 @@ service RoleService {
};
}
// RemoveRoleGrants removes the users and/or groups from the specified role.
// RemoveRoleGrants removes the grants from the specified role.
// The provided request must include the scope and the role IDs from which the
// users and/or groups will be removed. If either ID is missing, malformed, or
// references a non-existing org, an error is returned. It is not an error to
// have duplicate user/group IDs.
// grants will be removed. If either ID is missing, malformed, or
// references a non-existing scope, an error is returned. It is not an error to
// have duplicate grants.
rpc RemoveRoleGrants(RemoveRoleGrantsRequest) returns (RemoveRoleGrantsResponse) {
option (google.api.http) = {
post: "/v1/scopes/*/roles/{role_id}:remove-grants"
@@ -26,7 +26,7 @@ service UserService {
}
// ListUsers returns a list of stored users which exist inside the org
// referenced inside the request. The request must include the org ID for
// referenced inside the request. The request must include the scope ID for
// the users being retrieved. If the scope ID is missing, malformed, or
// reference a non existing scope, an error is returned.
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) {
@@ -39,10 +39,10 @@ service UserService {
}
// CreateUser creates and stores a user in boundary. The provided
// request must include the org id in which the user will be created.
// If the org id is missing, malformed or references a non existing
// org, an error is returned. If a name is provided that is in
// use in another user in the same org, an error is returned.
// request must include the scope id in which the user will be created.
// If the scope id is missing, malformed or references a non existing
// scope, an error is returned. If a name is provided that is in
// use in another user in the same scope, an error is returned.
rpc CreateUser(CreateUserRequest) returns (CreateUserResponse) {
option (google.api.http) = {
post: "/v1/scopes/*/users"
@@ -58,10 +58,10 @@ service UserService {
// user must not have any read only fields set. The update mask must be
// included in the request and contain at least 1 mutable field. To unset
// a field's value, include the field in the update mask and don't set it
// in the provided user. An error is returned if either the org
// in the provided user. An error is returned if either the scope
// or user ids are missing or reference a non existing resource. An error
// is also returned if the request attempts to update the name to one that is
// already in use in this org.
// already in use in this scope.
rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse) {
option (google.api.http) = {
patch: "/v1/scopes/*/users/{id}"
@@ -73,7 +73,7 @@ service UserService {
};
}
// DeleteUser removes a user from Boundary. If the provided org or user ids
// DeleteUser removes a user from Boundary. If the provided scope or user ids
// are malformed or not provided an error is returned. No error is returned
// if either ids reference resources that do not exist as the response itself
// specifies if the resource existed before the DeleteUser request was
@@ -54,11 +54,11 @@ message Host {
// name is optional. If set, it must be unique within
// catalog_id.
// @inject_tag: `gorm:"default:null"`
string name = 4;
string name = 4 [(custom_options.v1.mask_mapping) = {this:"name" that: "name"}];
// description is optional.
// @inject_tag: `gorm:"default:null"`
string description = 5;
string description = 5 [(custom_options.v1.mask_mapping) = {this:"description" that: "description"}];
// catalog_id is the public_id of the owning
// static_host_catalog and must be set.
@@ -68,7 +68,7 @@ message Host {
// address is the IP Address or DNS name of the host. It must be set and
// it must be unique within catalog_id.
// @inject_tag: `gorm:"default:null"`
string address = 7;
string address = 7 [(custom_options.v1.mask_mapping) = {this:"address" that: "attributes.address"}];
// version allows optimistic locking of the resource
// @inject_tag: `gorm:"default:null"`
@@ -91,11 +91,11 @@ message HostSet {
// name is optional. If set, it must be unique within
// catalog_id.
// @inject_tag: `gorm:"default:null"`
string name = 4;
string name = 4 [(custom_options.v1.mask_mapping) = {this:"name" that: "name"}];
// description is optional.
// @inject_tag: `gorm:"default:null"`
string description = 5;
string description = 5 [(custom_options.v1.mask_mapping) = {this:"description" that: "description"}];
// catalog_id is the public_id of the owning
// static_host_catalog and must be set.
+8
View File
@@ -24,6 +24,7 @@ import (
"github.com/hashicorp/boundary/internal/servers/controller/handlers/authtokens"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/groups"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/host_catalogs"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/hosts"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/roles"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/scopes"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/users"
@@ -83,6 +84,13 @@ func handleGrpcGateway(c *Controller, props HandlerProperties) (http.Handler, er
if err := services.RegisterHostCatalogServiceHandlerServer(ctx, mux, hcs); err != nil {
return nil, fmt.Errorf("failed to register host catalog service handler: %w", err)
}
hs, err := hosts.NewService(c.StaticHostRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create host handler service: %w", err)
}
if err := services.RegisterHostServiceHandlerServer(ctx, mux, hs); err != nil {
return nil, fmt.Errorf("failed to register host service handler: %w", err)
}
accts, err := accounts.NewService(c.PasswordAuthRepoFn)
if err != nil {
return nil, fmt.Errorf("failed to create account handler service: %w", err)
@@ -59,6 +59,8 @@ func TestHandleImplementedPaths(t *testing.T) {
"v1/scopes/someid/groups/someid",
"v1/scopes/someid/host-catalogs",
"v1/scopes/someid/host-catalogs/someid",
"v1/scopes/someid/host-catalogs/someid/hosts",
"v1/scopes/someid/host-catalogs/someid/hosts/someid",
"v1/scopes/someid/roles",
"v1/scopes/someid/roles/someid",
"v1/scopes/someid/users",
@@ -73,6 +75,7 @@ func TestHandleImplementedPaths(t *testing.T) {
"v1/scopes/someid/auth-methods",
"v1/scopes/someid/auth-methods/someid/accounts",
"v1/scopes/someid/host-catalogs",
"v1/scopes/someid/host-catalogs/someid/hosts",
// custom methods
"v1/scopes/someid/auth-methods/someid:authenticate",
@@ -97,6 +100,7 @@ func TestHandleImplementedPaths(t *testing.T) {
"v1/scopes/someid/auth-methods/someid",
"v1/scopes/someid/auth-methods/someid/accounts/someid",
"v1/scopes/someid/host-catalogs/someid",
"v1/scopes/someid/host-catalogs/someid/hosts/someid",
},
"PATCH": {
"v1/scopes/someid",
@@ -105,6 +109,7 @@ func TestHandleImplementedPaths(t *testing.T) {
"v1/scopes/someid/groups/someid",
"v1/scopes/someid/auth-methods/someid",
"v1/scopes/someid/host-catalogs/someid",
"v1/scopes/someid/host-catalogs/someid/hosts/someid",
},
} {
for _, p := range paths {
@@ -0,0 +1,436 @@
package hosts
import (
"context"
"fmt"
"regexp"
"strings"
"github.com/hashicorp/boundary/internal/auth"
pb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/hosts"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
"github.com/hashicorp/boundary/internal/host"
"github.com/hashicorp/boundary/internal/host/static"
"github.com/hashicorp/boundary/internal/host/static/store"
"github.com/hashicorp/boundary/internal/servers/controller/common"
"github.com/hashicorp/boundary/internal/servers/controller/handlers"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/wrapperspb"
)
var (
maskManager handlers.MaskManager
reInvalidID = regexp.MustCompile("[^A-Za-z0-9]")
)
func init() {
var err error
if maskManager, err = handlers.NewMaskManager(&store.Host{}, &pb.Host{}, &pb.StaticHostAttributes{}); err != nil {
panic(err)
}
}
type Service struct {
staticRepoFn common.StaticRepoFactory
}
var _ pbs.HostServiceServer = Service{}
// NewService returns a host catalog Service which handles host catalog related requests to boundary and uses the provided
// repositories for storage and retrieval.
func NewService(repoFn common.StaticRepoFactory) (Service, error) {
if repoFn == nil {
return Service{}, fmt.Errorf("nil static repository provided")
}
return Service{staticRepoFn: repoFn}, nil
}
func (s Service) ListHosts(ctx context.Context, req *pbs.ListHostsRequest) (*pbs.ListHostsResponse, error) {
authResults := auth.Verify(ctx)
if authResults.Error != nil {
return nil, authResults.Error
}
if err := validateListRequest(req); err != nil {
return nil, err
}
hl, err := s.listFromRepo(ctx, req.GetHostCatalogId())
if err != nil {
return nil, err
}
for _, item := range hl {
item.Scope = authResults.Scope
}
return &pbs.ListHostsResponse{Items: hl}, nil
}
// GetHost implements the interface pbs.HostServiceServer.
func (s Service) GetHost(ctx context.Context, req *pbs.GetHostRequest) (*pbs.GetHostResponse, error) {
authResults := auth.Verify(ctx)
if authResults.Error != nil {
return nil, authResults.Error
}
ct := host.SubtypeFromId(req.GetId())
if ct == host.UnknownSubtype {
return nil, handlers.InvalidArgumentErrorf("Invalid argument provided.", map[string]string{"id": "Improperly formatted identifier used."})
}
if err := validateGetRequest(req); err != nil {
return nil, err
}
hc, err := s.getFromRepo(ctx, req.GetId())
if err != nil {
return nil, err
}
hc.Scope = authResults.Scope
return &pbs.GetHostResponse{Item: hc}, nil
}
// CreateHost implements the interface pbs.HostServiceServer.
func (s Service) CreateHost(ctx context.Context, req *pbs.CreateHostRequest) (*pbs.CreateHostResponse, error) {
authResults := auth.Verify(ctx)
if authResults.Error != nil {
return nil, authResults.Error
}
if err := validateCreateRequest(req); err != nil {
return nil, err
}
h, err := s.createInRepo(ctx, authResults.Scope.GetId(), req.GetHostCatalogId(), req.GetItem())
if err != nil {
return nil, err
}
h.Scope = authResults.Scope
return &pbs.CreateHostResponse{
Item: h,
Uri: fmt.Sprintf("scopes/%s/host-catalogs/%s/hosts/%s", authResults.Scope.GetId(), req.GetHostCatalogId(), h.GetId()),
}, nil
}
// UpdateHost implements the interface pbs.HostServiceServer.
func (s Service) UpdateHost(ctx context.Context, req *pbs.UpdateHostRequest) (*pbs.UpdateHostResponse, error) {
authResults := auth.Verify(ctx)
if authResults.Error != nil {
return nil, authResults.Error
}
ct := host.SubtypeFromId(req.GetId())
if ct == host.UnknownSubtype {
return nil, handlers.InvalidArgumentErrorf("Invalid argument provided.", map[string]string{"id": "Improperly formatted identifier used."})
}
if err := validateUpdateRequest(req); err != nil {
return nil, err
}
hc, err := s.updateInRepo(ctx, authResults.Scope.GetId(), req.GetHostCatalogId(), req.GetId(), req.GetUpdateMask().GetPaths(), req.GetItem())
if err != nil {
return nil, err
}
hc.Scope = authResults.Scope
return &pbs.UpdateHostResponse{Item: hc}, nil
}
// DeleteHost implements the interface pbs.HostServiceServer.
func (s Service) DeleteHost(ctx context.Context, req *pbs.DeleteHostRequest) (*pbs.DeleteHostResponse, error) {
authResults := auth.Verify(ctx)
if authResults.Error != nil {
return nil, authResults.Error
}
if err := validateDeleteRequest(req); err != nil {
return nil, err
}
existed, err := s.deleteFromRepo(ctx, authResults.Scope.GetId(), req.GetId())
if err != nil {
return nil, err
}
return &pbs.DeleteHostResponse{Existed: existed}, nil
}
func (s Service) getFromRepo(ctx context.Context, id string) (*pb.Host, error) {
repo, err := s.staticRepoFn()
if err != nil {
return nil, err
}
h, err := repo.LookupHost(ctx, id)
if err != nil {
return nil, err
}
if h == nil {
return nil, handlers.NotFoundErrorf("Host %q doesn't exist.", id)
}
return toProto(h, nil)
}
func (s Service) createInRepo(ctx context.Context, scopeId, catalogId string, item *pb.Host) (*pb.Host, error) {
ha := &pb.StaticHostAttributes{}
if err := handlers.StructToProto(item.GetAttributes(), ha); err != nil {
return nil, status.Errorf(codes.Internal, "Failed converting attributes to subtype proto: %s", err)
}
var opts []static.Option
if ha.GetAddress() != nil {
opts = append(opts, static.WithAddress(ha.GetAddress().GetValue()))
}
if item.GetName() != nil {
opts = append(opts, static.WithName(item.GetName().GetValue()))
}
if item.GetDescription() != nil {
opts = append(opts, static.WithDescription(item.GetDescription().GetValue()))
}
h, err := static.NewHost(catalogId, opts...)
if err != nil {
return nil, status.Errorf(codes.Internal, "Unable to build host for creation: %v.", err)
}
repo, err := s.staticRepoFn()
if err != nil {
return nil, err
}
out, err := repo.CreateHost(ctx, scopeId, h)
if err != nil {
return nil, status.Errorf(codes.Internal, "Unable to create host: %v.", err)
}
if out == nil {
return nil, status.Error(codes.Internal, "Unable to create host but no error returned from repository.")
}
return toProto(out, nil)
}
func (s Service) updateInRepo(ctx context.Context, scopeId, catalogId, id string, mask []string, item *pb.Host) (*pb.Host, error) {
ha := &pb.StaticHostAttributes{}
if err := handlers.StructToProto(item.GetAttributes(), ha); err != nil {
return nil, status.Errorf(codes.Internal, "Failed converting attributes to subtype proto: %s", err)
}
var opts []static.Option
if desc := item.GetDescription(); desc != nil {
opts = append(opts, static.WithDescription(desc.GetValue()))
}
if name := item.GetName(); name != nil {
opts = append(opts, static.WithName(name.GetValue()))
}
if addr := ha.GetAddress(); addr != nil {
opts = append(opts, static.WithAddress(addr.GetValue()))
}
h, err := static.NewHost(catalogId, opts...)
if err != nil {
return nil, status.Errorf(codes.Internal, "Unable to build host for update: %v.", err)
}
h.PublicId = id
dbMask := maskManager.Translate(mask)
if len(dbMask) == 0 {
return nil, handlers.InvalidArgumentErrorf("No valid fields included in the update mask.", map[string]string{"update_mask": "No valid paths provided in the update mask."})
}
repo, err := s.staticRepoFn()
if err != nil {
return nil, err
}
out, rowsUpdated, err := repo.UpdateHost(ctx, scopeId, h, item.GetVersion(), dbMask)
if err != nil {
return nil, status.Errorf(codes.Internal, "Unable to update host: %v.", err)
}
if rowsUpdated == 0 {
return nil, handlers.NotFoundErrorf("Host %q doesn't exist.", id)
}
return toProto(out, nil)
}
func (s Service) deleteFromRepo(ctx context.Context, scopeId, id string) (bool, error) {
repo, err := s.staticRepoFn()
if err != nil {
return false, err
}
rows, err := repo.DeleteHost(ctx, scopeId, id)
if err != nil {
return false, status.Errorf(codes.Internal, "Unable to delete host: %v.", err)
}
return rows > 0, nil
}
func (s Service) listFromRepo(ctx context.Context, catalogId string) ([]*pb.Host, error) {
repo, err := s.staticRepoFn()
if err != nil {
return nil, err
}
hl, err := repo.ListHosts(ctx, catalogId)
if err != nil {
return nil, err
}
var outHl []*pb.Host
for _, h := range hl {
p, err := toProto(h, nil)
if err != nil {
return nil, err
}
outHl = append(outHl, p)
}
return outHl, nil
}
func toProto(in *static.Host, members []*static.HostSetMember) (*pb.Host, error) {
out := pb.Host{
Id: in.GetPublicId(),
HostCatalogId: in.GetCatalogId(),
Type: host.StaticSubtype.String(),
CreatedTime: in.GetCreateTime().GetTimestamp(),
UpdatedTime: in.GetUpdateTime().GetTimestamp(),
Version: in.GetVersion(),
}
if in.GetDescription() != "" {
out.Description = wrapperspb.String(in.GetDescription())
}
if in.GetName() != "" {
out.Name = wrapperspb.String(in.GetName())
}
for _, m := range members {
out.HostSetIds = append(out.HostSetIds, m.GetSetId())
}
st, err := handlers.ProtoToStruct(&pb.StaticHostAttributes{Address: wrapperspb.String(in.GetAddress())})
if err != nil {
return nil, status.Errorf(codes.Internal, "Unable to convert static attribute to struct: %s", err)
}
out.Attributes = st
return &out, nil
}
// A validateX method should exist for each method above. These methods do not make calls to any backing service but enforce
// requirements on the structure of the request. They verify that:
// * The path passed in is correctly formatted
// * All required parameters are set
// * There are no conflicting parameters provided
// * The type asserted by the ID and/or field is known
// * If relevant, the type derived from the id prefix matches what is claimed by the type field
func validateGetRequest(req *pbs.GetHostRequest) error {
badFields := map[string]string{}
if !validId(req.GetHostCatalogId(), static.HostCatalogPrefix+"_") {
badFields["host_catalog_id"] = "The field is incorrectly formatted."
}
if !validId(req.GetId(), static.HostPrefix+"_") {
badFields["id"] = "Invalid formatted identifier."
}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Invalid arguments provided.", badFields)
}
return nil
}
func validateCreateRequest(req *pbs.CreateHostRequest) error {
badFields := map[string]string{}
if !validId(req.GetHostCatalogId(), static.HostCatalogPrefix+"_") {
badFields["host_catalog_id"] = "The field is incorrectly formatted."
}
item := req.GetItem()
if item == nil {
return handlers.InvalidArgumentErrorf("Invalid arguments provided.", map[string]string{"item": "this field is required."})
}
ha := &pb.StaticHostAttributes{}
if err := handlers.StructToProto(item.GetAttributes(), ha); err != nil {
badFields["attributes"] = "Incorrectly formatted attribute for this type."
}
if ha.GetAddress() == nil {
badFields["attributes.address"] = "This field is required."
}
switch host.SubtypeFromId(req.GetHostCatalogId()) {
case host.StaticSubtype:
if item.GetType() != "" && item.GetType() != host.StaticSubtype.String() {
badFields["type"] = "Doesn't match the parent resource's type."
}
attrs := &pb.StaticHostAttributes{}
if err := handlers.StructToProto(item.GetAttributes(), attrs); err != nil {
badFields["attributes"] = "Attribute fields do not match the expected format."
}
if attrs.GetAddress() == nil {
badFields["attributes.address"] = "This is a required field for this type."
}
}
if item.GetId() != "" {
badFields["id"] = "This field is read only."
}
if item.GetHostCatalogId() != "" {
badFields["host_catalog_id"] = "This field is read only."
}
if item.GetCreatedTime() != nil {
badFields["created_time"] = "This field is read only."
}
if item.GetUpdatedTime() != nil {
badFields["updated_time"] = "This field is read only."
}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Invalid arguments provided.", badFields)
}
return nil
}
func validateUpdateRequest(req *pbs.UpdateHostRequest) error {
badFields := map[string]string{}
if !validId(req.GetId(), static.HostPrefix+"_") {
badFields["id"] = "The field is incorrectly formatted."
}
if !validId(req.GetHostCatalogId(), static.HostCatalogPrefix+"_") {
badFields["host_catalog_id"] = "The field is incorrectly formatted."
}
if req.GetUpdateMask() == nil {
badFields["update_mask"] = "This field is required."
}
item := req.GetItem()
if item == nil {
// It is legitimate for no item to be specified in an update request as it indicates all fields provided in
// the mask will be marked as unset.
return nil
}
if item.GetVersion() == 0 {
badFields["version"] = "Existing resource version is required for an update."
}
if item.GetType() != "" {
badFields["type"] = "This is a read only field and cannot be specified in an update request."
}
if item.GetHostCatalogId() != "" {
badFields["host_catalog_id"] = "This is a read only field and cannot be specified in an update request."
}
if item.GetId() != "" {
badFields["id"] = "This is a read only field and cannot be specified in an update request."
}
if item.GetCreatedTime() != nil {
badFields["created_time"] = "This is a read only field and cannot be specified in an update request."
}
if item.GetUpdatedTime() != nil {
badFields["updated_time"] = "This is a read only field and cannot be specified in an update request."
}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Errors in provided fields.", badFields)
}
return nil
}
func validateListRequest(req *pbs.ListHostsRequest) error {
badFields := map[string]string{}
if !validId(req.GetHostCatalogId(), static.HostCatalogPrefix+"_") {
badFields["host_catalog_id"] = "The field is incorrectly formatted."
}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Improperly formatted identifier.", badFields)
}
return nil
}
func validateDeleteRequest(req *pbs.DeleteHostRequest) error {
badFields := map[string]string{}
if !validId(req.GetHostCatalogId(), static.HostCatalogPrefix+"_") {
badFields["host_catalog_id"] = "The field is incorrectly formatted."
}
if !validId(req.GetId(), static.HostPrefix+"_") {
badFields["id"] = "The field is incorrectly formatted."
}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Invalid arguments provided.", badFields)
}
return nil
}
func validId(id, prefix string) bool {
if !strings.HasPrefix(id, prefix) {
return false
}
id = strings.TrimPrefix(id, prefix)
return !reInvalidID.Match([]byte(id))
}
@@ -0,0 +1,778 @@
package hosts_test
import (
"context"
"fmt"
"strings"
"testing"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/wrappers"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/boundary/internal/auth"
"github.com/hashicorp/boundary/internal/db"
pb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/hosts"
"github.com/hashicorp/boundary/internal/gen/controller/api/resources/scopes"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
"github.com/hashicorp/boundary/internal/host"
"github.com/hashicorp/boundary/internal/host/static"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/servers/controller/handlers/hosts"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/genproto/protobuf/field_mask"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protocmp"
"google.golang.org/protobuf/types/known/structpb"
)
// TODO: Uncomment all the valid test cases.
func TestGet(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
_, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
rw := db.New(conn)
repoFn := func() (*static.Repository, error) {
return static.NewRepository(rw, rw, kms)
}
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
toMerge := &pbs.GetHostRequest{
HostCatalogId: hc.GetPublicId(),
}
pHost := &pb.Host{
HostCatalogId: hc.GetPublicId(),
Id: h.GetPublicId(),
CreatedTime: h.CreateTime.GetTimestamp(),
UpdatedTime: h.UpdateTime.GetTimestamp(),
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
Type: "static",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"address": structpb.NewStringValue(h.GetAddress()),
}},
}
cases := []struct {
name string
req *pbs.GetHostRequest
res *pbs.GetHostResponse
errCode codes.Code
}{
{
name: "Get an Existing Host",
req: &pbs.GetHostRequest{Id: h.GetPublicId()},
res: &pbs.GetHostResponse{Item: pHost},
errCode: codes.OK,
},
{
name: "Get a non existing Host Set",
req: &pbs.GetHostRequest{Id: static.HostPrefix + "_DoesntExis"},
res: nil,
errCode: codes.NotFound,
},
{
name: "Wrong id prefix",
req: &pbs.GetHostRequest{Id: "j_1234567890"},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "space in id",
req: &pbs.GetHostRequest{Id: static.HostPrefix + "_1 23456789"},
res: nil,
errCode: codes.InvalidArgument,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
assert := assert.New(t)
req := proto.Clone(toMerge).(*pbs.GetHostRequest)
proto.Merge(req, tc.req)
s, err := hosts.NewService(repoFn)
require.NoError(t, err, "Couldn't create a new host set service.")
got, gErr := s.GetHost(auth.DisabledAuthTestContext(auth.WithScopeId(proj.GetPublicId())), req)
assert.Equal(tc.errCode, status.Code(gErr), "GetHost(%+v) got error %v, wanted %v", req, gErr, tc.errCode)
if tc.res != nil {
tc.res.Item.Version = 1
}
assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "GetHost(%q) got response %q, wanted %q", req, got, tc.res)
})
}
}
func TestList(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
_, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
rw := db.New(conn)
repoFn := func() (*static.Repository, error) {
return static.NewRepository(rw, rw, kms)
}
hcs := static.TestCatalogs(t, conn, proj.GetPublicId(), 2)
hc, hcNoHosts := hcs[0], hcs[1]
var wantHs []*pb.Host
for _, h := range static.TestHosts(t, conn, hc.GetPublicId(), 10) {
wantHs = append(wantHs, &pb.Host{
Id: h.GetPublicId(),
HostCatalogId: h.GetCatalogId(),
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
CreatedTime: h.GetCreateTime().GetTimestamp(),
UpdatedTime: h.GetUpdateTime().GetTimestamp(),
Version: h.GetVersion(),
Type: host.StaticSubtype.String(), Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"address": structpb.NewStringValue(h.GetAddress()),
}},
})
}
cases := []struct {
name string
hostCatalogId string
res *pbs.ListHostsResponse
errCode codes.Code
}{
{
name: "List Many Hosts",
hostCatalogId: hc.GetPublicId(),
res: &pbs.ListHostsResponse{Items: wantHs},
errCode: codes.OK,
},
{
name: "List No Hosts",
hostCatalogId: hcNoHosts.GetPublicId(),
res: &pbs.ListHostsResponse{},
errCode: codes.OK,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
s, err := hosts.NewService(repoFn)
require.NoError(err, "Couldn't create new host set service.")
got, gErr := s.ListHosts(auth.DisabledAuthTestContext(auth.WithScopeId(proj.GetPublicId())), &pbs.ListHostsRequest{HostCatalogId: tc.hostCatalogId})
assert.Equal(tc.errCode, status.Code(gErr), "ListHosts(%q) got error %v, wanted %v", tc.hostCatalogId, gErr, tc.errCode)
assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "ListHosts(%q) got response %q, wanted %q", tc.hostCatalogId, got, tc.res)
})
}
}
func TestDelete(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
_, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
rw := db.New(conn)
repoFn := func() (*static.Repository, error) {
return static.NewRepository(rw, rw, kms)
}
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
s, err := hosts.NewService(repoFn)
require.NoError(t, err, "Couldn't create a new host set service.")
cases := []struct {
name string
scopeId string
req *pbs.DeleteHostRequest
res *pbs.DeleteHostResponse
errCode codes.Code
}{
{
name: "Delete an Existing Host",
scopeId: proj.GetPublicId(),
req: &pbs.DeleteHostRequest{
HostCatalogId: hc.GetPublicId(),
Id: h.GetPublicId(),
},
res: &pbs.DeleteHostResponse{
Existed: true,
},
errCode: codes.OK,
},
{
name: "Delete bad id Host",
scopeId: proj.GetPublicId(),
req: &pbs.DeleteHostRequest{
HostCatalogId: hc.GetPublicId(),
Id: static.HostPrefix + "_doesntexis",
},
res: &pbs.DeleteHostResponse{
Existed: false,
},
errCode: codes.OK,
},
{
name: "Delete bad host catalog id in Host",
scopeId: proj.GetPublicId(),
req: &pbs.DeleteHostRequest{
HostCatalogId: static.HostCatalogPrefix + "_doesntexis",
Id: h.GetPublicId(),
},
res: &pbs.DeleteHostResponse{
Existed: false,
},
errCode: codes.OK,
},
{
name: "Bad Host Id formatting",
scopeId: proj.GetPublicId(),
req: &pbs.DeleteHostRequest{
HostCatalogId: hc.GetPublicId(),
Id: static.HostPrefix + "_bad_format",
},
res: nil,
errCode: codes.InvalidArgument,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
assert := assert.New(t)
got, gErr := s.DeleteHost(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), tc.req)
assert.Equal(tc.errCode, status.Code(gErr), "DeleteHost(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode)
assert.Empty(cmp.Diff(tc.res, got, protocmp.Transform()), "DeleteHost(%q) got response %q, wanted %q", tc.req, got, tc.res)
})
}
}
func TestDelete_twice(t *testing.T) {
t.Parallel()
assert := assert.New(t)
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
_, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
rw := db.New(conn)
repoFn := func() (*static.Repository, error) {
return static.NewRepository(rw, rw, kms)
}
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0]
s, err := hosts.NewService(repoFn)
require.NoError(t, err, "Couldn't create a new host set service.")
req := &pbs.DeleteHostRequest{
HostCatalogId: hc.GetPublicId(),
Id: h.GetPublicId(),
}
ctx := auth.DisabledAuthTestContext(auth.WithScopeId(proj.GetPublicId()))
got, gErr := s.DeleteHost(ctx, req)
assert.NoError(gErr, "First attempt")
assert.True(got.GetExisted(), "Expected existed to be true for the first delete.")
got, gErr = s.DeleteHost(ctx, req)
assert.NoError(gErr, "Second attempt")
assert.False(got.GetExisted(), "Expected existed to be false for the second delete.")
}
func TestCreate(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
_, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
rw := db.New(conn)
repoFn := func() (*static.Repository, error) {
return static.NewRepository(rw, rw, kms)
}
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
toMerge := &pbs.CreateHostRequest{
HostCatalogId: hc.GetPublicId(),
}
defaultHcCreated, err := ptypes.Timestamp(hc.GetCreateTime().GetTimestamp())
require.NoError(t, err)
cases := []struct {
name string
req *pbs.CreateHostRequest
res *pbs.CreateHostResponse
errCode codes.Code
}{
{
name: "Create a valid Host",
req: &pbs.CreateHostRequest{Item: &pb.Host{
Name: &wrappers.StringValue{Value: "name"},
Description: &wrappers.StringValue{Value: "desc"},
Type: "static",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"address": structpb.NewStringValue("123.456.789"),
}},
}},
res: &pbs.CreateHostResponse{
Uri: fmt.Sprintf("scopes/%s/host-catalogs/%s/hosts/%s_", proj.GetPublicId(), hc.GetPublicId(), static.HostPrefix),
Item: &pb.Host{
HostCatalogId: hc.GetPublicId(),
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
Name: &wrappers.StringValue{Value: "name"},
Description: &wrappers.StringValue{Value: "desc"},
Type: "static",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"address": structpb.NewStringValue("123.456.789"),
}},
},
},
errCode: codes.OK,
},
{
name: "Create without address",
req: &pbs.CreateHostRequest{Item: &pb.Host{
Name: &wrappers.StringValue{Value: "name"},
Description: &wrappers.StringValue{Value: "desc"},
Type: "static",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{}},
}},
errCode: codes.InvalidArgument,
},
{
name: "Create with unknown type",
req: &pbs.CreateHostRequest{Item: &pb.Host{
Name: &wrappers.StringValue{Value: "name"},
Description: &wrappers.StringValue{Value: "desc"},
Type: "ThisIsMadeUp",
}},
errCode: codes.InvalidArgument,
},
{
name: "Create with no type",
req: &pbs.CreateHostRequest{Item: &pb.Host{
Name: &wrappers.StringValue{Value: "name"},
Description: &wrappers.StringValue{Value: "desc"},
}},
errCode: codes.InvalidArgument,
},
{
name: "Can't specify Id",
req: &pbs.CreateHostRequest{Item: &pb.Host{
Id: "not allowed to be set",
}},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "Can't specify Created Time",
req: &pbs.CreateHostRequest{Item: &pb.Host{
CreatedTime: ptypes.TimestampNow(),
}},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "Can't specify Update Time",
req: &pbs.CreateHostRequest{Item: &pb.Host{
UpdatedTime: ptypes.TimestampNow(),
}},
res: nil,
errCode: codes.InvalidArgument,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
req := proto.Clone(toMerge).(*pbs.CreateHostRequest)
proto.Merge(req, tc.req)
s, err := hosts.NewService(repoFn)
require.NoError(err, "Failed to create a new host set service.")
got, gErr := s.CreateHost(auth.DisabledAuthTestContext(auth.WithScopeId(proj.GetPublicId())), req)
assert.Equal(tc.errCode, status.Code(gErr), "CreateHost(%+v) got error %v, wanted %v", req, gErr, tc.errCode)
if got != nil {
assert.Contains(got.GetUri(), tc.res.GetUri())
assert.True(strings.HasPrefix(got.GetItem().GetId(), static.HostPrefix))
gotCreateTime, err := ptypes.Timestamp(got.GetItem().GetCreatedTime())
require.NoError(err, "Error converting proto to timestamp.")
gotUpdateTime, err := ptypes.Timestamp(got.GetItem().GetUpdatedTime())
require.NoError(err, "Error converting proto to timestamp")
// Verify it is a set created after the test setup's default set
assert.True(gotCreateTime.After(defaultHcCreated), "New set should have been created after default set. Was created %v, which is after %v", gotCreateTime, defaultHcCreated)
assert.True(gotUpdateTime.After(defaultHcCreated), "New set should have been updated after default set. Was updated %v, which is after %v", gotUpdateTime, defaultHcCreated)
// Clear all values which are hard to compare against.
got.Uri, tc.res.Uri = "", ""
got.Item.Id, tc.res.Item.Id = "", ""
got.Item.CreatedTime, got.Item.UpdatedTime, tc.res.Item.CreatedTime, tc.res.Item.UpdatedTime = nil, nil, nil, nil
}
if tc.res != nil {
tc.res.Item.Version = 1
}
assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "CreateHost(%q) got response %q, wanted %q", req, got, tc.res)
})
}
}
func TestUpdate(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
_, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
rw := db.New(conn)
repoFn := func() (*static.Repository, error) {
return static.NewRepository(rw, rw, kms)
}
repo, err := repoFn()
require.NoError(t, err, "Couldn't create new static repo.")
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
h, err := static.NewHost(hc.GetPublicId(), static.WithName("default"), static.WithDescription("default"), static.WithAddress("defaultaddress"))
require.NoError(t, err)
h, err = repo.CreateHost(context.Background(), proj.GetPublicId(), h)
require.NoError(t, err)
var version uint32 = 1
resetHost := func() {
version++
_, _, err = repo.UpdateHost(context.Background(), proj.GetPublicId(), h, version, []string{"Name", "Description", "Address"})
require.NoError(t, err, "Failed to reset host.")
version++
}
hCreated, err := ptypes.Timestamp(h.GetCreateTime().GetTimestamp())
require.NoError(t, err, "Failed to convert proto to timestamp")
toMerge := &pbs.UpdateHostRequest{
HostCatalogId: hc.GetPublicId(),
Id: h.GetPublicId(),
}
tested, err := hosts.NewService(repoFn)
require.NoError(t, err, "Failed to create a new host set service.")
cases := []struct {
name string
req *pbs.UpdateHostRequest
res *pbs.UpdateHostResponse
errCode codes.Code
}{
{
name: "Update an Existing Host",
req: &pbs.UpdateHostRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"name", "description"},
},
Item: &pb.Host{
Name: &wrappers.StringValue{Value: "new"},
Description: &wrappers.StringValue{Value: "desc"},
},
},
res: &pbs.UpdateHostResponse{
Item: &pb.Host{
HostCatalogId: hc.GetPublicId(),
Id: h.GetPublicId(),
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
Name: &wrappers.StringValue{Value: "new"},
Description: &wrappers.StringValue{Value: "desc"},
CreatedTime: h.GetCreateTime().GetTimestamp(),
Type: "static",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"address": structpb.NewStringValue("defaultaddress"),
}},
},
},
errCode: codes.OK,
},
{
name: "Multiple Paths in single string",
req: &pbs.UpdateHostRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"name,description"},
},
Item: &pb.Host{
Name: &wrappers.StringValue{Value: "new"},
Description: &wrappers.StringValue{Value: "desc"},
},
},
res: &pbs.UpdateHostResponse{
Item: &pb.Host{
HostCatalogId: hc.GetPublicId(),
Id: h.GetPublicId(),
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
Name: &wrappers.StringValue{Value: "new"},
Description: &wrappers.StringValue{Value: "desc"},
CreatedTime: h.GetCreateTime().GetTimestamp(),
Type: "static",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"address": structpb.NewStringValue("defaultaddress"),
}},
},
},
errCode: codes.OK,
},
{
name: "No Update Mask",
req: &pbs.UpdateHostRequest{
Item: &pb.Host{
Name: &wrappers.StringValue{Value: "updated name"},
Description: &wrappers.StringValue{Value: "updated desc"},
},
},
errCode: codes.InvalidArgument,
},
{
name: "Empty Path",
req: &pbs.UpdateHostRequest{
UpdateMask: &field_mask.FieldMask{Paths: []string{}},
Item: &pb.Host{
Name: &wrappers.StringValue{Value: "updated name"},
Description: &wrappers.StringValue{Value: "updated desc"},
},
},
errCode: codes.InvalidArgument,
},
{
name: "Only non-existant paths in Mask",
req: &pbs.UpdateHostRequest{
UpdateMask: &field_mask.FieldMask{Paths: []string{"nonexistant_field"}},
Item: &pb.Host{
Name: &wrappers.StringValue{Value: "updated name"},
Description: &wrappers.StringValue{Value: "updated desc"},
},
},
errCode: codes.InvalidArgument,
},
{
name: "Unset Name",
req: &pbs.UpdateHostRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"name"},
},
Item: &pb.Host{
Description: &wrappers.StringValue{Value: "ignored"},
},
},
res: &pbs.UpdateHostResponse{
Item: &pb.Host{
HostCatalogId: hc.GetPublicId(),
Id: h.GetPublicId(),
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
Description: &wrappers.StringValue{Value: "default"},
CreatedTime: h.GetCreateTime().GetTimestamp(),
Type: "static",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"address": structpb.NewStringValue("defaultaddress"),
}},
},
},
errCode: codes.OK,
},
{
name: "Unset Description",
req: &pbs.UpdateHostRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"description"},
},
Item: &pb.Host{
Name: &wrappers.StringValue{Value: "ignored"},
},
},
res: &pbs.UpdateHostResponse{
Item: &pb.Host{
HostCatalogId: hc.GetPublicId(),
Id: h.GetPublicId(),
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
Name: &wrappers.StringValue{Value: "default"},
CreatedTime: h.GetCreateTime().GetTimestamp(),
Type: "static",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"address": structpb.NewStringValue("defaultaddress"),
}},
},
},
errCode: codes.OK,
},
{
name: "Update Only Name",
req: &pbs.UpdateHostRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"name"},
},
Item: &pb.Host{
Name: &wrappers.StringValue{Value: "updated"},
Description: &wrappers.StringValue{Value: "ignored"},
},
},
res: &pbs.UpdateHostResponse{
Item: &pb.Host{
HostCatalogId: hc.GetPublicId(),
Id: h.GetPublicId(),
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
Name: &wrappers.StringValue{Value: "updated"},
Description: &wrappers.StringValue{Value: "default"},
CreatedTime: h.GetCreateTime().GetTimestamp(),
Type: "static",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"address": structpb.NewStringValue("defaultaddress"),
}},
},
},
errCode: codes.OK,
},
{
name: "Update Only Description",
req: &pbs.UpdateHostRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"description"},
},
Item: &pb.Host{
Name: &wrappers.StringValue{Value: "ignored"},
Description: &wrappers.StringValue{Value: "notignored"},
},
},
res: &pbs.UpdateHostResponse{
Item: &pb.Host{
HostCatalogId: hc.GetPublicId(),
Id: h.GetPublicId(),
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
Name: &wrappers.StringValue{Value: "default"},
Description: &wrappers.StringValue{Value: "notignored"},
CreatedTime: h.GetCreateTime().GetTimestamp(),
Type: "static",
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{
"address": structpb.NewStringValue("defaultaddress"),
}},
},
},
errCode: codes.OK,
},
{
name: "Update a Non Existing Host",
req: &pbs.UpdateHostRequest{
Id: static.HostPrefix + "_DoesntExis",
UpdateMask: &field_mask.FieldMask{
Paths: []string{"description"},
},
Item: &pb.Host{
Name: &wrappers.StringValue{Value: "new"},
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
Description: &wrappers.StringValue{Value: "desc"},
},
},
errCode: codes.Internal,
},
{
name: "Cant change Id",
req: &pbs.UpdateHostRequest{
Id: hc.GetPublicId(),
UpdateMask: &field_mask.FieldMask{
Paths: []string{"id"},
},
Item: &pb.Host{
Id: "p_somethinge",
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
Name: &wrappers.StringValue{Value: "new"},
Description: &wrappers.StringValue{Value: "new desc"},
}},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "Cant specify Created Time",
req: &pbs.UpdateHostRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"created_time"},
},
Item: &pb.Host{
CreatedTime: ptypes.TimestampNow(),
},
},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "Cant specify Updated Time",
req: &pbs.UpdateHostRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"updated_time"},
},
Item: &pb.Host{
UpdatedTime: ptypes.TimestampNow(),
},
},
res: nil,
errCode: codes.InvalidArgument,
},
{
name: "Valid mask, cant specify type",
req: &pbs.UpdateHostRequest{
UpdateMask: &field_mask.FieldMask{
Paths: []string{"name"},
},
Item: &pb.Host{
Type: "Unknown",
},
},
res: nil,
errCode: codes.InvalidArgument,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tc.req.Item.Version = version
req := proto.Clone(toMerge).(*pbs.UpdateHostRequest)
proto.Merge(req, tc.req)
// Test some bad versions
req.Item.Version = version + 2
_, gErr := tested.UpdateHost(auth.DisabledAuthTestContext(auth.WithScopeId(proj.GetPublicId())), req)
require.Error(gErr)
req.Item.Version = version - 1
_, gErr = tested.UpdateHost(auth.DisabledAuthTestContext(auth.WithScopeId(proj.GetPublicId())), req)
require.Error(gErr)
req.Item.Version = version
got, gErr := tested.UpdateHost(auth.DisabledAuthTestContext(auth.WithScopeId(proj.GetPublicId())), req)
assert.Equal(tc.errCode, status.Code(gErr), "UpdateHost(%+v) got error %v, wanted %v", req, gErr, tc.errCode)
if tc.errCode == codes.OK {
defer resetHost()
}
if got != nil {
assert.NotNilf(tc.res, "Expected UpdateHost response to be nil, but was %v", got)
gotUpdateTime, err := ptypes.Timestamp(got.GetItem().GetUpdatedTime())
require.NoError(err, "Failed to convert proto to timestamp")
// Verify it is a set updated after it was created
// TODO: This is currently failing.
assert.True(gotUpdateTime.After(hCreated), "Updated set should have been updated after it's creation. Was updated %v, which is after %v", gotUpdateTime, hCreated)
// Clear all values which are hard to compare against.
got.Item.UpdatedTime, tc.res.Item.UpdatedTime = nil, nil
}
if tc.res != nil {
tc.res.Item.Version = version + 1
}
assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "UpdateHost(%q) got response %q, wanted %q", req, got, tc.res)
})
}
}