Skip to content

Commit

Permalink
Merge pull request #527 from uber/class_config
Browse files Browse the repository at this point in the history
Class config
  • Loading branch information
l-w-2017 committed Dec 13, 2018
2 parents 75794a3 + afbee02 commit 89d81e8
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 69 deletions.
25 changes: 10 additions & 15 deletions codegen/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,6 @@ import (
yaml "gopkg.in/yaml.v2"
)

// ClientConfigBase is the struct for client-config.yaml. It is the base for
// specific type of client.
type ClientConfigBase struct {
Name string `yaml:"name" json:"name"`
Type string `yaml:"type" json:"type"`
Dependencies Dependencies `yaml:"dependencies" json:"dependencies"`
}

type clientConfig interface {
NewClientSpec(
instance *ModuleInstance,
Expand Down Expand Up @@ -92,8 +84,9 @@ func validateExposedMethods(v interface{}, param string) error {

// HTTPClientConfig represents the "config" field for a HTTP client-config.yaml
type HTTPClientConfig struct {
ClientConfigBase `yaml:",inline" json:",inline"`
Config *ClientThriftConfig `yaml:"config" json:"config" validate:"nonzero"`
ClassConfigBase `yaml:",inline" json:",inline"`
Dependencies Dependencies `yaml:"dependencies" json:"dependencies"`
Config *ClientThriftConfig `yaml:"config" json:"config" validate:"nonzero"`
}

func newHTTPClientConfig(raw []byte) (*HTTPClientConfig, error) {
Expand Down Expand Up @@ -157,8 +150,9 @@ func (c *HTTPClientConfig) NewClientSpec(

// TChannelClientConfig represents the "config" field for a TChannel client-config.yaml
type TChannelClientConfig struct {
ClientConfigBase `yaml:",inline" json:",inline"`
Config *ClientThriftConfig `yaml:"config" json:"config" validate:"nonzero"`
ClassConfigBase `yaml:",inline" json:",inline"`
Dependencies Dependencies `yaml:"dependencies" json:"dependencies"`
Config *ClientThriftConfig `yaml:"config" json:"config" validate:"nonzero"`
}

func newTChannelClientConfig(raw []byte) (*TChannelClientConfig, error) {
Expand Down Expand Up @@ -186,8 +180,9 @@ func (c *TChannelClientConfig) NewClientSpec(

// CustomClientConfig represents the config for a custom client.
type CustomClientConfig struct {
ClientConfigBase `yaml:",inline" json:",inline"`
Config *struct {
ClassConfigBase `yaml:",inline" json:",inline"`
Dependencies Dependencies `yaml:"dependencies" json:"dependencies"`
Config *struct {
Fixture *Fixture `yaml:"fixture" json:"fixture"`
CustomImportPath string `yaml:"customImportPath" json:"customImportPath" validate:"nonzero"`
} `yaml:"config" json:"config" validate:"nonzero"`
Expand Down Expand Up @@ -230,7 +225,7 @@ func (c *CustomClientConfig) NewClientSpec(
}

func clientType(raw []byte) (string, error) {
clientConfig := ClientConfigBase{}
clientConfig := ClassConfigBase{}
if err := yaml.Unmarshal(raw, &clientConfig); err != nil {
return "", errors.Wrap(
err, "Could not parse client config data to determine client type")
Expand Down
26 changes: 13 additions & 13 deletions codegen/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,12 @@ config:
func TestNewClientConfigGetHTTPClient(t *testing.T) {
client, err := newClientConfig([]byte(httpClientYAML))
expectedClient := HTTPClientConfig{
ClientConfigBase: ClientConfigBase{
ClassConfigBase: ClassConfigBase{
Name: "test",
Type: "http",
Dependencies: Dependencies{
Client: []string{"a", "b"},
},
},
Dependencies: Dependencies{
Client: []string{"a", "b"},
},
Config: &ClientThriftConfig{
ExposedMethods: map[string]string{
Expand All @@ -299,12 +299,12 @@ func TestNewClientConfigGetHTTPClient(t *testing.T) {
func TestNewClientConfigGetTChannelClient(t *testing.T) {
client, err := newClientConfig([]byte(tchannelClientYAML))
expectedClient := TChannelClientConfig{
ClientConfigBase: ClientConfigBase{
ClassConfigBase: ClassConfigBase{
Name: "test",
Type: "tchannel",
Dependencies: Dependencies{
Client: []string{"a", "b"},
},
},
Dependencies: Dependencies{
Client: []string{"a", "b"},
},
Config: &ClientThriftConfig{
ExposedMethods: map[string]string{
Expand All @@ -328,12 +328,12 @@ func TestNewClientConfigGetTChannelClient(t *testing.T) {
func TestNewClientConfigGetCustomClient(t *testing.T) {
client, err := newClientConfig([]byte(customClientYAML))
expectedClient := CustomClientConfig{
ClientConfigBase: ClientConfigBase{
ClassConfigBase: ClassConfigBase{
Name: "test",
Type: "custom",
Dependencies: Dependencies{
Client: []string{"a", "b"},
},
},
Dependencies: Dependencies{
Client: []string{"a", "b"},
},
Config: &struct {
Fixture *Fixture `yaml:"fixture" json:"fixture"`
Expand Down Expand Up @@ -484,7 +484,7 @@ config:
client, err := newMockableClient([]byte(configYAML))
assert.NoError(t, err)
expectedClient := &mockableClient{
ClientConfigBase: ClientConfigBase{
ClassConfigBase: ClassConfigBase{
Name: "test",
Type: "testable",
},
Expand Down
65 changes: 34 additions & 31 deletions codegen/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,8 @@ type ClientSpec struct {
// ModuleClassConfig represents the generic YAML config for
// all modules. This will be provided by the module package.
type ModuleClassConfig struct {
Name string `yaml:"name" json:"name"`
Type string `yaml:"type" json:"type"`
Config interface{} `yaml:"config" json:"config"`
ClassConfigBase `yaml:",inline" json:",inline"`
Config interface{} `yaml:"config" json:"config"`
}

// Dependencies lists all dependencies of a module
Expand All @@ -121,9 +120,9 @@ type MiddlewareConfigConfig struct {

// MiddlewareConfig represents configuration for a middleware as is written in the yaml file
type MiddlewareConfig struct {
Name string `yaml:"name" json:"name"`
Dependencies *Dependencies `yaml:"dependencies,omitempty" json:"dependencies,omitempty"`
Config *MiddlewareConfigConfig `yaml:"config" json:"config"`
ClassConfigBase `yaml:",inline" json:",inline"`
Dependencies *Dependencies `yaml:"dependencies,omitempty" json:"dependencies,omitempty"`
Config *MiddlewareConfigConfig `yaml:"config" json:"config"`
}

// Validate the config spec attributes
Expand Down Expand Up @@ -224,62 +223,64 @@ type TypedHeader struct {
// gateway including its thriftFile and meta data
type EndpointSpec struct {
// ModuleSpec holds the thrift module info
ModuleSpec *ModuleSpec
ModuleSpec *ModuleSpec `yaml:"-"`
// YAMLFile for this endpoint spec
YAMLFile string
YAMLFile string `yaml:"-"`
// GoStructsFileName is where structs are generated
GoStructsFileName string
GoStructsFileName string `yaml:"-"`
// GoFolderName is the folder where all the endpoints
// are generated.
GoFolderName string
GoFolderName string `yaml:"-"`
// GoPackageName is the package import path.
GoPackageName string
GoPackageName string `yaml:"-"`

// EndpointType, currently only "http"
EndpointType string `yaml:"endpointType"`
EndpointType string `yaml:"endpointType" validate:"nonzero"`
// EndpointID, used in metrics and logging, lower case.
EndpointID string `yaml:"endpointId"`
EndpointID string `yaml:"endpointId" validate:"nonzero"`
// HandleID, used in metrics and logging, lowercase.
HandleID string `yaml:"handleId"`
HandleID string `yaml:"handleId" validate:"nonzero"`
// ThriftFile, the thrift file for this endpoint
ThriftFile string `yaml:"thriftFile"`
ThriftFile string `yaml:"thriftFile" validate:"nonzero"`
// ThriftFileSha, the SHA of the thrift file for this endpoint
ThriftFileSha string `yaml:"thriftFileSha" validate:"nonzero"`
// ThriftMethodName, which thrift method to use.
ThriftMethodName string `yaml:"thriftMethodName"`
ThriftMethodName string `yaml:"thriftMethodName" validate:"nonzero"`
// ThriftServiceName, which thrift service to use.
ThriftServiceName string
ThriftServiceName string `yaml:"-"`
// TestFixtures, meta data to generate tests,
TestFixtures map[string]*EndpointTestFixture `yaml:"testFixtures"`
// Middlewares, meta data to add middlewares,
Middlewares []MiddlewareSpec `yaml:"middlewares"`
// HeadersPropagate, a map from endpoint request headers to
// client request fields.
HeadersPropagate map[string]FieldMapperEntry
HeadersPropagate map[string]FieldMapperEntry `yaml:"-"`
// ReqTransforms, a map from client request fields to endpoint
// request fields that should override their values.
ReqTransforms map[string]FieldMapperEntry
ReqTransforms map[string]FieldMapperEntry `yaml:"-"`
// RespTransforms, a map from endpoint response fields to client
// response fields that should override their values.
RespTransforms map[string]FieldMapperEntry
RespTransforms map[string]FieldMapperEntry `yaml:"-"`
// ErrTransforms is a map from endpoint exception fields to client exception fields
// that should override their values
// Note that this feature is not yet fully implemented in the stand-alone Zanzibar codebase
ErrTransforms map[string]FieldMapperEntry
ErrTransforms map[string]FieldMapperEntry `yaml:"-"`
// ReqHeaders maps headers from server to client
ReqHeaders map[string]*TypedHeader `yaml:"reqHeaderMap"`
// ResHeaders maps headers from client to server
ResHeaders map[string]*TypedHeader `yaml:"resHeaderMap"`
// WorkflowType, either "httpClient" or "custom".
// A httpClient workflow generates a http client Caller
// A custom workflow just imports the custom code
WorkflowType string `yaml:"workflowType"`
WorkflowType string `yaml:"workflowType" validate:"nonzero"`
// If "custom" then where to import custom code from
WorkflowImportPath string `yaml:"workflowImportPath"`
// if "httpClient", which client to call.
ClientID string `yaml:"clientId"`
// if "httpClient", which client method to call.
ClientMethod string `yaml:"clientMethod"`
// The client for this endpoint if httpClient or tchannelClient
ClientSpec *ClientSpec
ClientSpec *ClientSpec `yaml:"-"`
}

func ensureFields(config map[interface{}]interface{}, mandatoryFields []string, yamlFile string) error {
Expand Down Expand Up @@ -876,16 +877,18 @@ func (e *EndpointSpec) SetDownstream(
return e.ModuleSpec.SetDownstream(e, h)
}

// EndpointConfig represent the "config" field of endpoint-config.yaml
type EndpointConfig struct {
Ratelimit int32 `yaml:"rateLimit" json:"rateLimit"`
Endpoints []string `yaml:"endpoints" json:"endpoints"`
}

// EndpointClassConfig represents the specific config for
// an endpoint group. This is a downcast of the moduleClassConfig.
type EndpointClassConfig struct {
Name string `yaml:"name" json:"name"`
Type string `yaml:"type" json:"type"`
Config struct {
Ratelimit int32 `yaml:"rateLimit" json:"rateLimit"`
Endpoints []string `yaml:"endpoints" json:"endpoints"`
} `yaml:"config" json:"config"`
Dependencies map[string][]string `yaml:"dependencies" json:"dependencies"`
ClassConfigBase `yaml:",inline" json:",inline"`
Dependencies map[string][]string `yaml:"dependencies" json:"dependencies"`
Config *EndpointConfig `yaml:"config" json:"config" validate:"nonzero"`
}

func parseEndpointYamls(
Expand Down Expand Up @@ -976,7 +979,7 @@ func parseMiddlewareConfig(
err = mid.Validate(configDirName)
if err != nil {
return nil, errors.Wrapf(
err, "Cannot validate middleware: %s",
err, "Cannot validate middleware: %v",
mid,
)
}
Expand Down
25 changes: 17 additions & 8 deletions codegen/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -1375,23 +1375,32 @@ type ModuleDependency struct {
InstanceName string
}

// ClassConfig maps onto a YAML configuration for a class type
type ClassConfig struct {
// ClassConfigBase defines the shared data fields for all class configs.
// Configs of different classes can derive from this base struct by add a
// specific "config" field and "dependencies" field
type ClassConfigBase struct {
// Name is the class instance name used to identify the module as a
// dependency. The combination of the class Name and this instance name
// is unique.
Name string `yaml:"name" json:"name"`
// The configuration map for this class instance. This depends on the
// class name and class type, and is interpreted by each module generator.
Config map[string]interface{} `yaml:"config" json:"config"`
// Dependencies is a map of class name to a list of instance names. This
// infers the dependencies struct generated for the initializer
Dependencies map[string][]string `yaml:"dependencies" json:"dependencies"`
// Type refers to the class type used to generate the dependency
Type string `yaml:"type" json:"type"`
// IsExportGenerated determines whether or not the export lives in
// IsExportGenerated defaults to true if not set.
IsExportGenerated *bool `yaml:"IsExportGenerated" json:"IsExportGenerated"`
// Owner is the Name of the class instance owner
Owner string `yaml:"owner"`
}

// ClassConfig maps onto a YAML configuration for a class type
type ClassConfig struct {
ClassConfigBase `yaml:",inline" json:",inline"`
// Dependencies is a map of class name to a list of instance names. This
// infers the dependencies struct generated for the initializer
Dependencies map[string][]string `yaml:"dependencies" json:"dependencies"`
// The configuration map for this class instance. This depends on the
// class name and class type, and is interpreted by each module generator.
Config map[string]interface{} `yaml:"config" json:"config"`
}

// NewClassConfig unmarshals raw bytes into a ClassConfig struct
Expand Down
5 changes: 3 additions & 2 deletions codegen/post_gen_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ const (
)

type mockableClient struct {
ClientConfigBase `yaml:",inline" json:",inline"`
Config *struct {
ClassConfigBase `yaml:",inline" json:",inline"`
Dependencies Dependencies `yaml:"dependencies" json:"dependencies"`
Config *struct {
Fixture *Fixture `yaml:"fixture" json:"fixture"`
CustomImportPath string `yaml:"customImportPath" json:"customImportPath"`
} `yaml:"config" json:"config" validate:"nonzero"`
Expand Down

0 comments on commit 89d81e8

Please sign in to comment.