Use code-generation for CRD API and deepcopy methods (#369)

Client-go provides a https://github.com/kubernetes/code-generator package in order to provide the API to work with CRDs similar to the one available for built-in types, i.e. Pods, Statefulsets and so on.

Use this package to generate deepcopy methods (required for CRDs), instead of using an external deepcopy package; we also generate APIs used to manipulate both Postgres and OperatorConfiguration CRDs, as well as informers and listers for the Postgres CRD, instead of using generic informers and CRD REST API; by using generated code we can get rid of some custom and obscure CRD-related code and use a better API.

All generated code resides in /pkg/generated, with an exception of zz_deepcopy.go in apis/acid.zalan.do/v1

Rename postgres-operator-configuration CRD to OperatorConfiguration, since the former broke naming convention in the code-generator.

Moved Postgresql, PostgresqlList, OperatorConfiguration and OperatorConfigurationList and other types used by them into

Change the type of  the Error field in the Postgresql crd to a string, so that client-go could generate a deepcopy for it.

Use generated code to set status of CRD objects as well. Right now this is done with patch, however, Kubernetes 1.11 introduces the /status subresources, allowing us to set the status with
the special updateStatus call in the future. For now, we keep the code that is compatible with earlier versions of Kubernetes.

Rename postgresql.go to database.go and status.go to logs_and_api.go to reflect the purpose of each of those files.

Update client-go dependencies.

Minor reformatting and renaming.
This commit is contained in:
Oleksii Kliukin
2018-08-15 17:22:25 +02:00
committed by GitHub
parent 6e8dcabac7
commit e1ed4b847d
66 changed files with 3285 additions and 966 deletions
+4 -4
View File
@@ -42,7 +42,7 @@ type Resources struct {
// Auth describes authentication specific configuration parameters
type Auth struct {
SecretNameTemplate stringTemplate `name:"secret_name_template" default:"{username}.{cluster}.credentials.{tprkind}.{tprgroup}"`
SecretNameTemplate StringTemplate `name:"secret_name_template" default:"{username}.{cluster}.credentials.{tprkind}.{tprgroup}"`
PamRoleName string `name:"pam_role_name" default:"zalandos"`
PamConfiguration string `name:"pam_configuration" default:"https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees"`
TeamsAPIUrl string `name:"teams_api_url" default:"https://teams.example.com/api/"`
@@ -93,9 +93,9 @@ type Config struct {
EnableReplicaLoadBalancer bool `name:"enable_replica_load_balancer" default:"false"`
// deprecated and kept for backward compatibility
EnableLoadBalancer *bool `name:"enable_load_balancer"`
MasterDNSNameFormat stringTemplate `name:"master_dns_name_format" default:"{cluster}.{team}.{hostedzone}"`
ReplicaDNSNameFormat stringTemplate `name:"replica_dns_name_format" default:"{cluster}-repl.{team}.{hostedzone}"`
PDBNameFormat stringTemplate `name:"pdb_name_format" default:"postgres-{cluster}-pdb"`
MasterDNSNameFormat StringTemplate `name:"master_dns_name_format" default:"{cluster}.{team}.{hostedzone}"`
ReplicaDNSNameFormat StringTemplate `name:"replica_dns_name_format" default:"{cluster}-repl.{team}.{hostedzone}"`
PDBNameFormat StringTemplate `name:"pdb_name_format" default:"postgres-{cluster}-pdb"`
Workers uint32 `name:"workers" default:"4"`
APIPort int `name:"api_port" default:"8080"`
RingLogLines int `name:"ring_log_lines" default:"100"`
-209
View File
@@ -1,209 +0,0 @@
package config
import (
"encoding/json"
"github.com/zalando-incubator/postgres-operator/pkg/spec"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"github.com/mohae/deepcopy"
)
type OperatorConfiguration struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata"`
Configuration OperatorConfigurationData `json:"configuration"`
Error error `json:"-"`
}
type OperatorConfigurationList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata"`
Items []OperatorConfiguration `json:"items"`
}
type PostgresUsersConfiguration struct {
SuperUsername string `json:"super_username,omitempty"`
ReplicationUsername string `json:"replication_username,omitempty"`
}
type KubernetesMetaConfiguration struct {
PodServiceAccountName string `json:"pod_service_account_name,omitempty"`
// TODO: change it to the proper json
PodServiceAccountDefinition string `json:"pod_service_account_definition,omitempty"`
PodServiceAccountRoleBindingDefinition string `json:"pod_service_account_role_binding_definition,omitempty"`
PodTerminateGracePeriod spec.Duration `json:"pod_terminate_grace_period,omitempty"`
WatchedNamespace string `json:"watched_namespace,omitempty"`
PDBNameFormat stringTemplate `json:"pdb_name_format,omitempty"`
SecretNameTemplate stringTemplate `json:"secret_name_template,omitempty"`
OAuthTokenSecretName spec.NamespacedName `json:"oauth_token_secret_name,omitempty"`
InfrastructureRolesSecretName spec.NamespacedName `json:"infrastructure_roles_secret_name,omitempty"`
PodRoleLabel string `json:"pod_role_label,omitempty"`
ClusterLabels map[string]string `json:"cluster_labels,omitempty"`
ClusterNameLabel string `json:"cluster_name_label,omitempty"`
NodeReadinessLabel map[string]string `json:"node_readiness_label,omitempty"`
// TODO: use a proper toleration structure?
PodToleration map[string]string `json:"toleration,omitempty"`
// TODO: use namespacedname
PodEnvironmentConfigMap string `json:"pod_environment_configmap,omitempty"`
PodPriorityClassName string `json:"pod_priority_class_name,omitempty"`
}
type PostgresPodResourcesDefaults struct {
DefaultCPURequest string `json:"default_cpu_request,omitempty"`
DefaultMemoryRequest string `json:"default_memory_request,omitempty"`
DefaultCPULimit string `json:"default_cpu_limit,omitempty"`
DefaultMemoryLimit string `json:"default_memory_limit,omitempty"`
}
type OperatorTimeouts struct {
ResourceCheckInterval spec.Duration `json:"resource_check_interval,omitempty"`
ResourceCheckTimeout spec.Duration `json:"resource_check_timeout,omitempty"`
PodLabelWaitTimeout spec.Duration `json:"pod_label_wait_timeout,omitempty"`
PodDeletionWaitTimeout spec.Duration `json:"pod_deletion_wait_timeout,omitempty"`
ReadyWaitInterval spec.Duration `json:"ready_wait_interval,omitempty"`
ReadyWaitTimeout spec.Duration `json:"ready_wait_timeout,omitempty"`
}
type LoadBalancerConfiguration struct {
DbHostedZone string `json:"db_hosted_zone,omitempty"`
EnableMasterLoadBalancer bool `json:"enable_master_load_balancer,omitempty"`
EnableReplicaLoadBalancer bool `json:"enable_replica_load_balancer,omitempty"`
MasterDNSNameFormat stringTemplate `json:"master_dns_name_format,omitempty"`
ReplicaDNSNameFormat stringTemplate `json:"replica_dns_name_format,omitempty"`
}
type AWSGCPConfiguration struct {
WALES3Bucket string `json:"wal_s3_bucket,omitempty"`
AWSRegion string `json:"aws_region,omitempty"`
LogS3Bucket string `json:"log_s3_bucket,omitempty"`
KubeIAMRole string `json:"kube_iam_role,omitempty"`
}
type OperatorDebugConfiguration struct {
DebugLogging bool `json:"debug_logging,omitempty"`
EnableDBAccess bool `json:"enable_database_access,omitempty"`
}
type TeamsAPIConfiguration struct {
EnableTeamsAPI bool `json:"enable_teams_api,omitempty"`
TeamsAPIUrl string `json:"teams_api_url,omitempty"`
TeamAPIRoleConfiguration map[string]string `json:"team_api_role_configuration,omitempty"`
EnableTeamSuperuser bool `json:"enable_team_superuser,omitempty"`
TeamAdminRole string `json:"team_admin_role,omitempty"`
PamRoleName string `json:"pam_role_name,omitempty"`
PamConfiguration string `json:"pam_configuration,omitempty"`
ProtectedRoles []string `json:"protected_role_names,omitempty"`
}
type LoggingRESTAPIConfiguration struct {
APIPort int `json:"api_port,omitempty"`
RingLogLines int `json:"ring_log_lines,omitempty"`
ClusterHistoryEntries int `json:"cluster_history_entries,omitempty"`
}
type ScalyrConfiguration struct {
ScalyrAPIKey string `json:"scalyr_api_key,omitempty"`
ScalyrImage string `json:"scalyr_image,omitempty"`
ScalyrServerURL string `json:"scalyr_server_url,omitempty"`
ScalyrCPURequest string `json:"scalyr_cpu_request,omitempty"`
ScalyrMemoryRequest string `json:"scalyr_memory_request,omitempty"`
ScalyrCPULimit string `json:"scalyr_cpu_limit,omitempty"`
ScalyrMemoryLimit string `json:"scalyr_memory_limit,omitempty"`
}
type OperatorConfigurationData struct {
EtcdHost string `json:"etcd_host,omitempty"`
DockerImage string `json:"docker_image,omitempty"`
Workers uint32 `json:"workers,omitempty"`
MinInstances int32 `json:"min_instances,omitempty"`
MaxInstances int32 `json:"max_instances,omitempty"`
ResyncPeriod spec.Duration `json:"resync_period,omitempty"`
RepairPeriod spec.Duration `json:"repair_period,omitempty"`
Sidecars map[string]string `json:"sidecar_docker_images,omitempty"`
PostgresUsersConfiguration PostgresUsersConfiguration `json:"users"`
Kubernetes KubernetesMetaConfiguration `json:"kubernetes"`
PostgresPodResources PostgresPodResourcesDefaults `json:"postgres_pod_resources"`
Timeouts OperatorTimeouts `json:"timeouts"`
LoadBalancer LoadBalancerConfiguration `json:"load_balancer"`
AWSGCP AWSGCPConfiguration `json:"aws_or_gcp"`
OperatorDebug OperatorDebugConfiguration `json:"debug"`
TeamsAPI TeamsAPIConfiguration `json:"teams_api"`
LoggingRESTAPI LoggingRESTAPIConfiguration `json:"logging_rest_api"`
Scalyr ScalyrConfiguration `json:"scalyr"`
}
type OperatorConfigurationUsers struct {
SuperUserName string `json:"superuser_name,omitempty"`
Replication string `json:"replication_user_name,omitempty"`
ProtectedRoles []string `json:"protected_roles,omitempty"`
TeamAPIRoleConfiguration map[string]string `json:"team_api_role_configuration,omitempty"`
}
type OperatorConfigurationCopy OperatorConfiguration
type OperatorConfigurationListCopy OperatorConfigurationList
func (opc *OperatorConfiguration) UnmarshalJSON(data []byte) error {
var ref OperatorConfigurationCopy
if err := json.Unmarshal(data, &ref); err != nil {
return err
}
*opc = OperatorConfiguration(ref)
return nil
}
func (opc *OperatorConfiguration) DeepCopyInto(out *OperatorConfiguration) {
if opc != nil {
*out = deepcopy.Copy(*opc).(OperatorConfiguration)
}
}
func (opc *OperatorConfiguration) DeepCopy() *OperatorConfiguration {
if opc == nil {
return nil
}
out := new(OperatorConfiguration)
opc.DeepCopyInto(out)
return out
}
func (opc *OperatorConfiguration) DeepCopyObject() runtime.Object {
if c := opc.DeepCopy(); c != nil {
return c
}
return nil
}
func (opcl *OperatorConfigurationList) UnmarshalJSON(data []byte) error {
var ref OperatorConfigurationListCopy
if err := json.Unmarshal(data, &ref); err != nil {
return nil
}
*opcl = OperatorConfigurationList(ref)
return nil
}
func (opcl *OperatorConfigurationList) DeepCopyInto(out *OperatorConfigurationList) {
if opcl != nil {
*out = deepcopy.Copy(*opcl).(OperatorConfigurationList)
}
}
func (opcl *OperatorConfigurationList) DeepCopy() *OperatorConfigurationList {
if opcl == nil {
return nil
}
out := new(OperatorConfigurationList)
opcl.DeepCopyInto(out)
return out
}
func (opcl *OperatorConfigurationList) DeepCopyObject() runtime.Object {
if c := opcl.DeepCopy(); c != nil {
return c
}
return nil
}
+6 -6
View File
@@ -19,7 +19,7 @@ type fieldInfo struct {
Field reflect.Value
}
type stringTemplate string
type StringTemplate string
func decoderFrom(field reflect.Value) (d decoder) {
// it may be impossible for a struct field to fail this check
@@ -172,7 +172,7 @@ func processField(value string, field reflect.Value) error {
type parserState int
const (
plain parserState = iota
plain parserState = iota
doubleQuoted
singleQuoted
)
@@ -221,13 +221,13 @@ func getMapPairsFromString(value string) (pairs []string, err error) {
return
}
func (f *stringTemplate) Decode(value string) error {
*f = stringTemplate(value)
func (f *StringTemplate) Decode(value string) error {
*f = StringTemplate(value)
return nil
}
func (f *stringTemplate) Format(a ...string) string {
func (f *StringTemplate) Format(a ...string) string {
res := string(*f)
for i := 0; i < len(a); i += 2 {
@@ -237,6 +237,6 @@ func (f *stringTemplate) Format(a ...string) string {
return res
}
func (f stringTemplate) MarshalJSON() ([]byte, error) {
func (f StringTemplate) MarshalJSON() ([]byte, error) {
return json.Marshal(string(f))
}
-13
View File
@@ -1,13 +0,0 @@
package constants
// Different properties of the PostgreSQL Custom Resource Definition
const (
PostgresCRDKind = "postgresql"
PostgresCRDResource = "postgresqls"
PostgresCRDShort = "pg"
CRDGroup = "acid.zalan.do"
CRDApiVersion = "v1"
OperatorConfigCRDKind = "postgresql-operator-configuration"
OperatorConfigCRDResource = "postgresql-operator-configurations"
OperatorConfigCRDShort = "pgopconfig"
)
+6 -23
View File
@@ -2,25 +2,22 @@ package k8sutil
import (
"fmt"
"reflect"
"github.com/zalando-incubator/postgres-operator/pkg/util/constants"
"k8s.io/api/core/v1"
policybeta1 "k8s.io/api/policy/v1beta1"
apiextclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
apiextbeta1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/kubernetes/typed/apps/v1beta1"
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
policyv1beta1 "k8s.io/client-go/kubernetes/typed/policy/v1beta1"
rbacv1beta1 "k8s.io/client-go/kubernetes/typed/rbac/v1beta1"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"reflect"
"github.com/zalando-incubator/postgres-operator/pkg/util/constants"
acidv1client "github.com/zalando-incubator/postgres-operator/pkg/generated/clientset/versioned"
)
// KubernetesClient describes getters for Kubernetes objects
@@ -40,8 +37,8 @@ type KubernetesClient struct {
policyv1beta1.PodDisruptionBudgetsGetter
apiextbeta1.CustomResourceDefinitionsGetter
RESTClient rest.Interface
CRDREST rest.Interface
RESTClient rest.Interface
AcidV1ClientSet *acidv1client.Clientset
}
// RestConfig creates REST config
@@ -87,27 +84,13 @@ func NewFromConfig(cfg *rest.Config) (KubernetesClient, error) {
kubeClient.RESTClient = client.CoreV1().RESTClient()
kubeClient.RoleBindingsGetter = client.RbacV1beta1()
cfg2 := *cfg
cfg2.GroupVersion = &schema.GroupVersion{
Group: constants.CRDGroup,
Version: constants.CRDApiVersion,
}
cfg2.APIPath = constants.K8sAPIPath
// MIGRATION: api.codecs -> scheme.Codecs?
cfg2.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
crd, err := rest.RESTClientFor(&cfg2)
if err != nil {
return kubeClient, fmt.Errorf("could not get rest client: %v", err)
}
kubeClient.CRDREST = crd
apiextClient, err := apiextclient.NewForConfig(cfg)
if err != nil {
return kubeClient, fmt.Errorf("could not create api client:%v", err)
}
kubeClient.CustomResourceDefinitionsGetter = apiextClient.ApiextensionsV1beta1()
kubeClient.AcidV1ClientSet = acidv1client.NewForConfigOrDie(cfg)
return kubeClient, nil
}