Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
33 changes: 14 additions & 19 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,23 @@ require (
github.com/davecgh/go-spew v1.1.1
github.com/evanphx/json-patch v4.5.0+incompatible // indirect
github.com/ghodss/yaml v1.0.0
github.com/golang/groupcache v0.0.0-20191002201903-404acd9df4cc // indirect
github.com/google/uuid v1.1.1
github.com/googleapis/gnostic v0.3.1 // indirect
github.com/hashicorp/golang-lru v0.5.3 // indirect
github.com/imdario/mergo v0.3.8 // indirect
github.com/openshift/api v0.0.0-20200623075207-eb651a5bb0ad
github.com/openshift/client-go v0.0.0-20200623090625-83993cebb5ae
github.com/openshift/library-go v0.0.0-20200709151624-cc498c355c99
github.com/pkg/errors v0.8.1
github.com/prometheus/client_golang v1.1.0
github.com/openshift/api v0.0.0-20200723134351-89de68875e7c
github.com/openshift/client-go v0.0.0-20200723130357-94e1065ab1f8
github.com/openshift/library-go v0.0.0-20200724192307-1ed21c4fa86c
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.7.1
github.com/prometheus/client_model v0.2.0
github.com/prometheus/common v0.7.0 // indirect
github.com/prometheus/procfs v0.0.5 // indirect
github.com/spf13/cobra v0.0.5
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0
google.golang.org/appengine v1.6.4 // indirect
k8s.io/api v0.18.4
k8s.io/apiextensions-apiserver v0.18.3
k8s.io/apimachinery v0.18.4
k8s.io/client-go v0.18.3
github.com/spf13/cobra v1.0.0
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
k8s.io/api v0.19.0-rc.2
k8s.io/apiextensions-apiserver v0.19.0-rc.2
k8s.io/apimachinery v0.19.0-rc.2
k8s.io/client-go v0.19.0-rc.2
k8s.io/klog v1.0.0
k8s.io/kube-aggregator v0.18.3
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89
k8s.io/kube-aggregator v0.19.0-rc.2
k8s.io/utils v0.0.0-20200720150651-0bdb4ca86cbc
)
310 changes: 224 additions & 86 deletions go.sum

Large diffs are not rendered by default.

300 changes: 300 additions & 0 deletions hack/generate-lib-resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
#!/usr/bin/env python

import os.path


def generate_lib_resources(directory, types, clients, modifiers, health_checks):
generate_resourceread(directory=os.path.join(directory, 'resourceread'), types=types)
generate_resourcebuilder(directory=os.path.join(directory, 'resourcebuilder'), types=types, clients=clients, modifiers=modifiers, health_checks=health_checks)


def generate_resourceread(directory, types):
package_name = os.path.basename(directory)
path = os.path.join(directory, package_name + '.go')
lines = [
'// auto-generated with generate-lib-resources.py',
'',
'// Package {} reads supported objects from bytes.'.format(package_name),
'package {}'.format(package_name),
'',
'import (',
]

imports = {}
for import_name in [
'k8s.io/apimachinery/pkg/runtime',
'k8s.io/apimachinery/pkg/runtime/serializer',
]:
imports[import_name] = '\t"{}"'.format(import_name)

for package in sorted(types.keys()):
base, version = os.path.split(package) # FIXME: should be using network path operations on package names
short_name = os.path.basename(base)
imports[package] = '\t{}{} "{}"'.format(short_name, version, package)

lines.extend([import_line for _, import_line in sorted(imports.items(), key=lambda package_line: package_line[0])])
lines.extend([
')',
'',
'var (',
'\tscheme = runtime.NewScheme()',
'\tcodecs = serializer.NewCodecFactory(scheme)',
'\tdecoder runtime.Decoder',
')',
'',
'func init() {',
])

sgvs = scheme_group_versions(types=types)
for _, data in sorted(sgvs.items()):
lines.extend([
'\tif err := {0}{1}.AddToScheme(scheme); err != nil {{'.format(data['short_name'], data['version']),
'\t\tpanic(err)',
'\t}',
])

lines.append('\tdecoder = codecs.UniversalDecoder(')
lines.extend(['\t\t{},'.format(sgv) for sgv in sorted(sgvs.keys())])
lines.extend([
'\t)',
'}',
'',
'// Read reads an object from bytes.',
'func Read(objBytes []byte) (runtime.Object, error) {',
'\treturn runtime.Decode(decoder, objBytes)',
'}',
'',
'// ReadOrDie reads an object from bytes. Panics on error.',
'func ReadOrDie(objBytes []byte) runtime.Object {',
'\trequiredObj, err := runtime.Decode(decoder, objBytes)',
'\tif err != nil {',
'\t\tpanic(err)',
'\t}',
'\treturn requiredObj',
'}',
'', # trailing newline
])
with open(path, 'w') as f:
f.write('\n'.join(lines))


def generate_resourcebuilder(directory, types, clients, modifiers, health_checks):
package_name = os.path.basename(directory)
path = os.path.join(directory, package_name + '.go')
lines = [
'// auto-generated with generate-lib-resources.py',
'',
'// Package {} reads supported objects from bytes.'.format(package_name),
'package {}'.format(package_name),
'',
'import (',
'\t"context"',
'\t"fmt"',
'',
]

imports = {}
for import_name in [
'github.com/openshift/cluster-version-operator/lib',
'github.com/openshift/cluster-version-operator/lib/resourceapply',
'github.com/openshift/cluster-version-operator/lib/resourceread',
'k8s.io/client-go/rest',
]:
imports[import_name] = '\t"{}"'.format(import_name)

ignored_packages = set()

for package in types.keys():
if not clients.get(package):
ignored_packages.add(package)
continue
base, version = os.path.split(package)
short_name = os.path.basename(base)
imports[package] = '\t{}{} "{}"'.format(short_name, version, package)

client_properties = {}
for package, client in clients.items():
if package in ignored_packages:
continue
base, version = os.path.split(client['package'])
short_name = os.path.basename(base)
client_short_name = '{}client{}'.format(short_name, version)
imports[client['package']] = '\t{} "{}"'.format(client_short_name, client['package'])
client_properties['{}Client{}'.format(short_name, version)] = {
'package': package,
'client_short_name': client_short_name,
'type': '*{}.{}'.format(client_short_name, client['type']),
'protobuf': client['package'].startswith('k8s.io/') and 'kube-aggregator' not in client['package'],
}

lines.extend([import_line for _, import_line in sorted(imports.items(), key=lambda package_line: package_line[0])])

longest_property = max(len(prop_name) for prop_name in client_properties.keys())

lines.extend([
')',
'',
'// builder manages single-manifest cluster reconciliation and monitoring.',
'type builder struct {',
'\traw []byte',
'\tmode Mode',
'\tmodifier MetaV1ObjectModifierFunc',
'',
])
lines.extend([
'\t{:{width}} {}'.format(prop_name, data['type'], width=longest_property)
for prop_name, data in sorted(client_properties.items())
])

lines.extend([
'}',
'',
'func newBuilder(config *rest.Config, m lib.Manifest) Interface {',
'\treturn &builder{',
'\t\traw: m.Raw,',
'',
])
for prop_name, data in sorted(client_properties.items()):
new_client_arg = 'config'
if data.get('protobuf'):
new_client_arg = 'withProtobuf({})'.format(new_client_arg)
lines.append('\t\t{:{width}} {}.NewForConfigOrDie({}),'.format(prop_name + ':', data['client_short_name'], new_client_arg, width=longest_property+1))

lines.extend([
'\t}',
'}',
'',
'func (b *builder) WithMode(m Mode) Interface {',
'\tb.mode = m',
'\treturn b',
'}',
'',
'func (b *builder) WithModifier(f MetaV1ObjectModifierFunc) Interface {',
'\tb.modifier = f',
'\treturn b',
'}',
'',
'func (b *builder) Do(ctx context.Context) error {',
'\tobj := resourceread.ReadOrDie(b.raw)',
'',
'\tswitch typedObject := obj.(type) {'
])

for package, type_names in sorted(types.items()):
if package in ignored_packages:
continue
base, version = os.path.split(package)
short_name = os.path.basename(base)
try:
client_prop_name = [key for key, data in client_properties.items() if data['package'] == package][0]
except IndexError as error:
raise ValueError('no client property found for {}'.format(package))
for type_name in sorted(type_names):
lines.extend([
'\tcase *{}{}.{}:'.format(short_name, version, type_name),
'\t\tif b.modifier != nil {',
'\t\t\tb.modifier(typedObject)',
'\t\t}',
])
type_key = (package, type_name)
modifier = modifiers.get(type_key)
if modifier:
lines.extend([
'\t\tif err := {}(ctx, typedObject); err != nil {{'.format(modifier),
'\t\t\treturn err',
'\t\t}',
])
lines.extend([
'\t\tif _, _, err := resourceapply.Apply{}{}(ctx, b.{}, typedObject); err != nil {{'.format(type_name, version, client_prop_name),
'\t\t\treturn err',
'\t\t}',
])
health_check = health_checks.get(type_key)
if health_check:
lines.append('\t\treturn {}(ctx, typedObject)'.format(health_check))

lines.extend([
'\tdefault:',
'\t\treturn fmt.Errorf("unrecognized manifest type: %T", obj)',
'\t}',
'',
'\treturn nil',
'}',
'',
'func init() {',
'\trm := NewResourceMapper()',
])

for sgv, data in sorted(scheme_group_versions(types=types).items()):
if data['package'] in ignored_packages:
continue
for type_name in sorted(data['types']):
lines.append('\trm.RegisterGVK({}.WithKind("{}"), newBuilder)'.format(sgv, type_name))

lines.extend([
'\trm.AddToMap(Mapper)',
'}',
'', # trailing newline
])

with open(path, 'w') as f:
f.write('\n'.join(lines))


def scheme_group_versions(types):
sgvs = {}
for package, type_names in types.items():
base, version = os.path.split(package)
short_name = os.path.basename(base)
sgv = '{}{}.SchemeGroupVersion'.format(short_name, version)
sgvs[sgv] = {
'package': package,
'short_name': short_name,
'types': type_names,
'version': version,
}
return sgvs


if __name__ == '__main__':
types = {
'github.com/openshift/api/image/v1': {'ImageStream'}, # for payload loading
'github.com/openshift/api/security/v1': {'SecurityContextConstraints'},
'k8s.io/api/apps/v1': {'DaemonSet', 'Deployment'},
'k8s.io/api/batch/v1': {'Job'},
'k8s.io/api/core/v1': {'ConfigMap', 'Namespace', 'Service', 'ServiceAccount'},
'k8s.io/api/rbac/v1': {'ClusterRole', 'ClusterRoleBinding', 'Role', 'RoleBinding'},
'k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1': {'CustomResourceDefinition'},
'k8s.io/kube-aggregator/pkg/apis/apiregistration/v1': {'APIService'},
}

types['k8s.io/api/rbac/v1beta1'] = types['k8s.io/api/rbac/v1']
types['k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1'] = types['k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1']
types['k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1'] = types['k8s.io/kube-aggregator/pkg/apis/apiregistration/v1']

clients = {
'github.com/openshift/api/security/v1': {'package': 'github.com/openshift/client-go/security/clientset/versioned/typed/security/v1', 'type': 'SecurityV1Client'},
'github.com/openshift/api/config/v1': {'package': 'github.com/openshift/client-go/config/clientset/versioned/typed/config/v1', 'type': 'ConfigV1Client'},
'k8s.io/api/apps/v1': {'package': 'k8s.io/client-go/kubernetes/typed/apps/v1', 'type': 'AppsV1Client'},
'k8s.io/api/batch/v1': {'package': 'k8s.io/client-go/kubernetes/typed/batch/v1', 'type': 'BatchV1Client'},
'k8s.io/api/core/v1': {'package': 'k8s.io/client-go/kubernetes/typed/core/v1', 'type': 'CoreV1Client'},
'k8s.io/api/rbac/v1': {'package': 'k8s.io/client-go/kubernetes/typed/rbac/v1', 'type': 'RbacV1Client'},
'k8s.io/api/rbac/v1beta1': {'package': 'k8s.io/client-go/kubernetes/typed/rbac/v1beta1', 'type': 'RbacV1beta1Client'},
'k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1': {'package': 'k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1', 'type': 'ApiextensionsV1Client'},
'k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1': {'package': 'k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1', 'type': 'ApiextensionsV1beta1Client'},
'k8s.io/kube-aggregator/pkg/apis/apiregistration/v1': {'package': 'k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/typed/apiregistration/v1', 'type': 'ApiregistrationV1Client'},
'k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1': {'package': 'k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/typed/apiregistration/v1beta1', 'type': 'ApiregistrationV1beta1Client'},
}

modifiers = {
('k8s.io/api/apps/v1', 'Deployment'): 'b.modifyDeployment',
('k8s.io/api/apps/v1', 'DaemonSet'): 'b.modifyDaemonSet',
}

health_checks = {
('k8s.io/api/apps/v1', 'Deployment'): 'b.checkDeploymentHealth',
('k8s.io/api/apps/v1', 'DaemonSet'): 'b.checkDaemonSetHealth',
('k8s.io/api/batch/v1', 'Job'): 'b.checkJobHealth',
}

generate_lib_resources(directory='lib', types=types, clients=clients, modifiers=modifiers, health_checks=health_checks)
7 changes: 7 additions & 0 deletions lib/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Package lib defines a Manifest type.
//
// It also contains subpackages for reconciling in-cluster resources
// with local state. The entrypoint is resourcebuilder, which consumes
// resourceread and resourceapply. resourceapply in turn consumer
// resourcemerge.
package lib
4 changes: 2 additions & 2 deletions lib/resourceapply/apiext.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"k8s.io/utils/pointer"
)

func ApplyCustomResourceDefinitionV1beta1(ctx context.Context, client apiextclientv1beta1.CustomResourceDefinitionsGetter, required *apiextv1beta1.CustomResourceDefinition) (*apiextv1beta1.CustomResourceDefinition, bool, error) {
func ApplyCustomResourceDefinitionv1beta1(ctx context.Context, client apiextclientv1beta1.CustomResourceDefinitionsGetter, required *apiextv1beta1.CustomResourceDefinition) (*apiextv1beta1.CustomResourceDefinition, bool, error) {
existing, err := client.CustomResourceDefinitions().Get(ctx, required.Name, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
actual, err := client.CustomResourceDefinitions().Create(ctx, required, metav1.CreateOptions{})
Expand All @@ -40,7 +40,7 @@ func ApplyCustomResourceDefinitionV1beta1(ctx context.Context, client apiextclie
return actual, true, err
}

func ApplyCustomResourceDefinitionV1(ctx context.Context, client apiextclientv1.CustomResourceDefinitionsGetter, required *apiextv1.CustomResourceDefinition) (*apiextv1.CustomResourceDefinition, bool, error) {
func ApplyCustomResourceDefinitionv1(ctx context.Context, client apiextclientv1.CustomResourceDefinitionsGetter, required *apiextv1.CustomResourceDefinition) (*apiextv1.CustomResourceDefinition, bool, error) {
existing, err := client.CustomResourceDefinitions().Get(ctx, required.Name, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
actual, err := client.CustomResourceDefinitions().Create(ctx, required, metav1.CreateOptions{})
Expand Down
2 changes: 1 addition & 1 deletion lib/resourceapply/apireg.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"k8s.io/utils/pointer"
)

func ApplyAPIService(ctx context.Context, client apiregclientv1.APIServicesGetter, required *apiregv1.APIService) (*apiregv1.APIService, bool, error) {
func ApplyAPIServicev1(ctx context.Context, client apiregclientv1.APIServicesGetter, required *apiregv1.APIService) (*apiregv1.APIService, bool, error) {
existing, err := client.APIServices().Get(ctx, required.Name, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
actual, err := client.APIServices().Create(ctx, required, metav1.CreateOptions{})
Expand Down
Loading