Skip to content

Commit

Permalink
Add support for service account annotations for operator (#396)
Browse files Browse the repository at this point in the history
* Add support for operator annotations

* Add changelog

* Move changelog

* codegen

* Fixup codegen -- older go version

Co-authored-by: Aidan Carson <[email protected]>
  • Loading branch information
SirNexus and SirNexus authored Dec 2, 2022
1 parent 193aae5 commit a8ae26d
Show file tree
Hide file tree
Showing 17 changed files with 114 additions and 82 deletions.
4 changes: 4 additions & 0 deletions changelog/v0.24.1/add-service-account-extra-annotations.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
changelog:
- type: NEW_FEATURE
description: Add serviceAccount.extraAnnotations to operator deployment.
issueLink: https://github.com/solo-io/gloo-mesh-enterprise/issues/5989
10 changes: 5 additions & 5 deletions codegen/collector/extractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ type ImportsExtractor interface {
// thread-safe
// The synchronizedImportsExtractor provides synchronized access to imports for a given proto file.
// It provides 2 useful features for tree traversal:
// 1. Imports for each file are cached, ensuring that if we attempt to access that file
// during traversal again, we do not need to duplicate work.
// 2. If imports for a file are unknown, and simultaneous go routines attempt to load
// the imports, only 1 will execute and the other will block, waiting for the result.
// This reduces the number of times we open and parse files.
// 1. Imports for each file are cached, ensuring that if we attempt to access that file
// during traversal again, we do not need to duplicate work.
// 2. If imports for a file are unknown, and simultaneous go routines attempt to load
// the imports, only 1 will execute and the other will block, waiting for the result.
// This reduces the number of times we open and parse files.
type synchronizedImportsExtractor struct {
// cachedImports contains a map of fileImports, each indexed by their file name
cachedImports sync.Map
Expand Down
1 change: 1 addition & 0 deletions codegen/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func Flush(writer io.Writer) error {

// This is a primitive implementation for compiling performance measurements of code-gen
// If we need it, we could substitute this with something more heavy handed like:
//
// https://github.com/armon/go-metrics
type metricAggregator struct {
metricsMu sync.Mutex
Expand Down
24 changes: 13 additions & 11 deletions codegen/proto/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,23 @@ import (
// a representation of set of parsed options for a given File's descriptor
type Options []FileOptions

/* GetUnstructuredFields gets the full list of unstructured fields contained within a given message. This function returns each field as an array of path elements, which is the fully expanded index of the field as measured from the root message. For example, given a message with the given structure:
/*
GetUnstructuredFields gets the full list of unstructured fields contained within a given message. This function returns each field as an array of path elements, which is the fully expanded index of the field as measured from the root message. For example, given a message with the given structure:
// root level message
message MyCRDSpec {
Options options = 1;
}
message Options {
UnstructuredType unstructured_option = 1;
}
message MyCRDSpec {
Options options = 1;
}
message RecursiveType {
RecursiveType recursive_field = 1 [(solo.io.cue.opt).disable_openapi_validation = true];
repeated RecursiveType repeated_recursive_field = 2 [(solo.io.cue.opt).disable_openapi_validation = true];
}
message Options {
UnstructuredType unstructured_option = 1;
}
message RecursiveType {
RecursiveType recursive_field = 1 [(solo.io.cue.opt).disable_openapi_validation = true];
repeated RecursiveType repeated_recursive_field = 2 [(solo.io.cue.opt).disable_openapi_validation = true];
}
The unstructured fields of `MyCRDSpec` would be returned as:
- ["MyCRDSpec", "options", "recursiveField"]
Expand Down
14 changes: 7 additions & 7 deletions codegen/render/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ func containerConfigs(op model.Operator) []containerConfig {
}

/*
Find the proto messages for a given set of descriptors which need proto_deepcopoy funcs and whose types are not in
the API root package
Find the proto messages for a given set of descriptors which need proto_deepcopoy funcs and whose types are not in
the API root package
return true if the descriptor corresponds to the Spec or the Status field
return true if the descriptor corresponds to the Spec or the Status field
*/
func shouldDeepCopyExternalMessage(resources []model.Resource, desc *descriptor.DescriptorProto) bool {
for _, resource := range resources {
Expand All @@ -131,11 +131,11 @@ func shouldDeepCopyExternalMessage(resources []model.Resource, desc *descriptor.
}

/*
Find the proto messages for a given set of descriptors which need proto_deepcopoy funcs.
The two cases are as follows:
Find the proto messages for a given set of descriptors which need proto_deepcopoy funcs.
The two cases are as follows:
1. One of the subfields has an external type
2. There is a oneof present
1. One of the subfields has an external type
2. There is a oneof present
*/
func shouldDeepCopyInternalMessage(packageName string, desc *descriptor.DescriptorProto) bool {
var shouldGenerate bool
Expand Down
14 changes: 7 additions & 7 deletions codegen/render/proto_types_renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ type descriptorsWithGopath struct {
}

/*
Get the relevant descriptors for a group of descriptors with a go package to match against.
A unique object is initialized for each external go package to the group package
Get the relevant descriptors for a group of descriptors with a go package to match against.
A unique object is initialized for each external go package to the group package
*/
func (grp descriptorsWithGopath) getUniqueDescriptorsWithPath() []*collector.DescriptorWithPath {
result := make(map[string]*collector.DescriptorWithPath)
Expand Down Expand Up @@ -141,11 +141,11 @@ func (r ProtoCodeRenderer) deepCopyGenTemplate(grp Group) ([]OutFile, error) {
}

/*
Create and render the templates for protobuf to json marshalling/unmarshalling.
Create and render the templates for protobuf to json marshalling/unmarshalling.
The empty string package name is treated as local, and so it it computed the same way as before
# The empty string package name is treated as local, and so it it computed the same way as before
Any other package name is than rendered to the relative path supplied.
Any other package name is than rendered to the relative path supplied.
*/
func (r ProtoCodeRenderer) jsonGenTemplate(grp Group) ([]OutFile, error) {
var result []OutFile
Expand Down Expand Up @@ -180,8 +180,8 @@ func (r ProtoCodeRenderer) jsonGenTemplate(grp Group) ([]OutFile, error) {
}

/*
Get all of the unique paths for a group by checking the packages of the resources
This list can include an empty string ("") which corresponds to the local group
Get all of the unique paths for a group by checking the packages of the resources
This list can include an empty string ("") which corresponds to the local group
*/
func uniqueGoImportPathsForGroup(grp Group) []string {
resultMap := make(map[string]struct{})
Expand Down
8 changes: 8 additions & 0 deletions codegen/templates/chart/operator-deployment.yamltmpl
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,14 @@ kind: ServiceAccount
metadata:
labels:
app: [[ $operator.Name ]]
{{- if $[[ $operatorVar ]].serviceAccount}}
{{- if $[[ $operatorVar ]].serviceAccount.extraAnnotations }}
annotations:
{{- range $key, $value := $[[ $operatorVar ]].serviceAccount.extraAnnotations }}
{{ $key }}: {{ $value }}
{{- end }}
{{- end }}
{{- end}}
name: [[ $operator.Name ]]
namespace: {{ $.Release.Namespace }}
{{- end }}
Expand Down
8 changes: 8 additions & 0 deletions codegen/test/chart-no-desc/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ kind: ServiceAccount
metadata:
labels:
app: painter
{{- if $painter.serviceAccount}}
{{- if $painter.serviceAccount.extraAnnotations }}
annotations:
{{- range $key, $value := $painter.serviceAccount.extraAnnotations }}
{{ $key }}: {{ $value }}
{{- end }}
{{- end }}
{{- end}}
name: painter
namespace: {{ $.Release.Namespace }}
{{- end }}
Expand Down
8 changes: 8 additions & 0 deletions codegen/test/chart/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ kind: ServiceAccount
metadata:
labels:
app: painter
{{- if $painter.serviceAccount}}
{{- if $painter.serviceAccount.extraAnnotations }}
annotations:
{{- range $key, $value := $painter.serviceAccount.extraAnnotations }}
{{ $key }}: {{ $value }}
{{- end }}
{{- end }}
{{- end}}
name: painter
namespace: {{ $.Release.Namespace }}
{{- end }}
Expand Down
1 change: 1 addition & 0 deletions codegen/util/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ func (opts GoCmdOptions) setCmdFields(c *exec.Cmd) {
}

// From https://github.com/golang/go/wiki/Modules:
//
// You can activate module support in one of two ways:
// - Invoke the go command in a directory outside of the $GOPATH/src tree,
// with a valid go.mod file in the current directory or any parent of it and
Expand Down
1 change: 0 additions & 1 deletion pkg/handler/enqueue_static_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ func (e *BroadcastRequests) Generic(evt event.GenericEvent, q workqueue.RateLimi
e.enqueueRequestsAllClusters()
}

//
func (e *BroadcastRequests) enqueueRequestsAllClusters() {
e.RequestsToEnqueue.Each(func(cluster string, i reconcile.Request) {
q := e.WorkQueues.Get(cluster)
Expand Down
1 change: 1 addition & 0 deletions pkg/kube_jsonpb/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type Marshaler struct {
// implement JSONPBUnmarshaler so that the custom format can be parsed.
//
// The JSON marshaling must follow the proto to JSON specification:
//
// https://developers.google.com/protocol-buffers/docs/proto3#json
//
// Deprecated: Custom types should implement protobuf reflection instead.
Expand Down
20 changes: 10 additions & 10 deletions pkg/multicluster/kubeconfig/kubeconfig_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,16 @@ func SecretObjMeta(namespace string, cluster string, resourceLabels map[string]s
}

/*
https://github.com/solo-io/service-mesh-hub/issues/590
If the user has a cert authority file set instead of the raw bytes in their kubeconfig, then
we'll fail later when the pods in-cluster try to read that file path.
We need to read the file right now, in a CLI context, and manually shuffle the bytes over to the CA data field
This is necessary if we are reading a kubeconfig on a user's local machine which has it's CertificateAuthority
set to a file, rather than the raw bytes. When a KubeConfig file is built it will first attempt to use the bytes,
but if they are missing, it will use the file instead. Since we are copying this kubeconfig into the cluster,
the file will no longer be available, therefore we have to read the contents of the file, and store them instead
as bytes.
https://github.com/solo-io/service-mesh-hub/issues/590
If the user has a cert authority file set instead of the raw bytes in their kubeconfig, then
we'll fail later when the pods in-cluster try to read that file path.
We need to read the file right now, in a CLI context, and manually shuffle the bytes over to the CA data field
This is necessary if we are reading a kubeconfig on a user's local machine which has it's CertificateAuthority
set to a file, rather than the raw bytes. When a KubeConfig file is built it will first attempt to use the bytes,
but if they are missing, it will use the file instead. Since we are copying this kubeconfig into the cluster,
the file will no longer be available, therefore we have to read the contents of the file, and store them instead
as bytes.
*/
func convertCertFilesToInline(cfg api.Config) error {
currentCluster := cfg.Clusters[cfg.Contexts[cfg.CurrentContext].Cluster]
Expand Down
44 changes: 22 additions & 22 deletions pkg/multicluster/register/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,11 @@ type RegistrationOptions struct {
}

/*
RegisterCluster is meant to be a helper function to easily "register" a remote cluster.
Currently this entails:
1. Creating a `ServiceAccount` on the remote cluster.
2. Binding RBAC `Roles/ClusterRoles` to said `ServiceAccount`
3. And finally creating a kubeconfig `Secret` with the BearerToken of the remote `ServiceAccount`
RegisterCluster is meant to be a helper function to easily "register" a remote cluster.
Currently this entails:
1. Creating a `ServiceAccount` on the remote cluster.
2. Binding RBAC `Roles/ClusterRoles` to said `ServiceAccount`
3. And finally creating a kubeconfig `Secret` with the BearerToken of the remote `ServiceAccount`
*/
func (opts RegistrationOptions) RegisterCluster(
ctx context.Context,
Expand All @@ -94,9 +94,9 @@ func (opts RegistrationOptions) RegisterCluster(
}

/*
RegisterProviderCluster augments RegisterCluster functionality
with additional metadata to persist to the resulting KubernetesCluster object.
ProviderInfo contains cloud provider metadata.
RegisterProviderCluster augments RegisterCluster functionality
with additional metadata to persist to the resulting KubernetesCluster object.
ProviderInfo contains cloud provider metadata.
*/
func (opts RegistrationOptions) RegisterProviderCluster(
ctx context.Context,
Expand All @@ -117,11 +117,11 @@ func (opts RegistrationOptions) RegisterProviderCluster(
}

/*
DeregisterCluster deregisters a cluster by cleaning up the resources created when RegisterCluster is invoked.
This entails:
1. Deleting the ServiceAccount on the remote cluster.
2. Deleting the remote Roles, RoleBindings, ClusterRoles, and ClusterRoleBindings associated with the ServiceAccount.
3. Deletes the secret containing the kubeconfig for the remote cluster.
DeregisterCluster deregisters a cluster by cleaning up the resources created when RegisterCluster is invoked.
This entails:
1. Deleting the ServiceAccount on the remote cluster.
2. Deleting the remote Roles, RoleBindings, ClusterRoles, and ClusterRoleBindings associated with the ServiceAccount.
3. Deletes the secret containing the kubeconfig for the remote cluster.
*/
func (opts RegistrationOptions) DeregisterCluster(
ctx context.Context,
Expand Down Expand Up @@ -280,17 +280,17 @@ func DeregisterClusterFromConfig(
}

/*
DefaultRegistrant provider function. This function will create a `ClusterRegistrant` using the
current kubeconfig, and the specified context. It will build all of the dependencies from the
available `ClientConfig`.
DefaultRegistrant provider function. This function will create a `ClusterRegistrant` using the
current kubeconfig, and the specified context. It will build all of the dependencies from the
available `ClientConfig`.
The apiServerAddress parameter is optional. When passed in, it will overwrite the Api Server
endpoint in the kubeconfig before it is written. This is primarily useful when running multi cluster
KinD environments on a mac as the local IP needs to be re-written to `host.docker.internal` so
that the local instance knows to hit localhost.
The apiServerAddress parameter is optional. When passed in, it will overwrite the Api Server
endpoint in the kubeconfig before it is written. This is primarily useful when running multi cluster
KinD environments on a mac as the local IP needs to be re-written to `host.docker.internal` so
that the local instance knows to hit localhost.
Meant to be used in tandem with RegisterClusterFromConfig above.
They are exposed separately so the `Registrant` may be mocked for the function above.
Meant to be used in tandem with RegisterClusterFromConfig above.
They are exposed separately so the `Registrant` may be mocked for the function above.
*/
func DefaultRegistrant(context, apiServerAddress string) (ClusterRegistrant, error) {
cfg, err := config.GetConfigWithContext(context)
Expand Down
8 changes: 4 additions & 4 deletions pkg/multicluster/register/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,11 @@ func (o *Options) validate() error {
}

/*
Standard Cluster Registrant (one who registers) interface.
Standard Cluster Registrant (one who registers) interface.
This component is responsible for registering a "remote" kubernetes cluster to a "management" cluster.
As the "management" cluster is not present in the interface itself, it is defined by the config used to build
the registrant instance.
This component is responsible for registering a "remote" kubernetes cluster to a "management" cluster.
As the "management" cluster is not present in the interface itself, it is defined by the config used to build
the registrant instance.
*/
type ClusterRegistrant interface {
/*
Expand Down
14 changes: 7 additions & 7 deletions pkg/multicluster/register/internal/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import (
//go:generate mockgen -source ./interfaces.go -destination ./mocks/mock_interfaces.go

/*
ClusterRBACBinder is a helper interface for the registrant, meant to create, and bind RBAC objects to
ServiceAccounts in a remote cluster.
ClusterRBACBinder is a helper interface for the registrant, meant to create, and bind RBAC objects to
ServiceAccounts in a remote cluster.
This interface supports both `Roles` and `ClusterRoles`.
All resources being referenced must already exist, or the operations will fail.
This interface supports both `Roles` and `ClusterRoles`.
All resources being referenced must already exist, or the operations will fail.
*/
type ClusterRBACBinder interface {
/*
Expand Down Expand Up @@ -50,8 +50,8 @@ type ClusterRBACBinder interface {
}

/*
Factory function to build a ClusterRBACBinder from a `ClientConfig`
This is useful because an the operations performed by the `RbacBinder` require access to a cluster
which will be determined by the caller.
Factory function to build a ClusterRBACBinder from a `ClientConfig`
This is useful because an the operations performed by the `RbacBinder` require access to a cluster
which will be determined by the caller.
*/
type ClusterRBACBinderFactory func(cfg clientcmd.ClientConfig) (ClusterRBACBinder, error)
16 changes: 8 additions & 8 deletions pkg/multicluster/register/registrant.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ var (
)

/*
NewClusterRegistrant returns an implementation of ClusterRegistrant.
NewClusterRegistrant returns an implementation of ClusterRegistrant.
localAPIServerAddress is optional. When passed in, it will overwrite the Api Server endpoint in
the kubeconfig before it is written. This is primarily useful when running multi cluster KinD environments
on a mac as the local IP needs to be re-written to `host.docker.internal` so that the local instance
knows to hit localhost.
localAPIServerAddress is optional. When passed in, it will overwrite the Api Server endpoint in
the kubeconfig before it is written. This is primarily useful when running multi cluster KinD environments
on a mac as the local IP needs to be re-written to `host.docker.internal` so that the local instance
knows to hit localhost.
*/
func NewClusterRegistrant(
localAPIServerAddress string,
Expand Down Expand Up @@ -628,8 +628,8 @@ func (c *clusterRegistrant) getTokenForSa(
}

// if:
// * the server appears to point to localhost, AND
// * the --local-cluster-domain-override flag is populated with a value
// - the server appears to point to localhost, AND
// - the --local-cluster-domain-override flag is populated with a value
//
// then we need to skip TLS verification and zero-out the cert data, because the cert
// on the remote cluster's API server wasn't issued for the domain contained in the
Expand All @@ -649,7 +649,7 @@ func (c *clusterRegistrant) skipTLSVerificationForLocalTesting(
}

// if:
// * the --local-cluster-domain-override flag is populated with a value
// - the --local-cluster-domain-override flag is populated with a value
//
// then rewrite the server config to communicate over the value of
// `--local-cluster-domain-override`, which resolves to the host machine of docker.
Expand Down

0 comments on commit a8ae26d

Please sign in to comment.