Skip to content

Commit c825c90

Browse files
committed
Merge branch 'master' into refactor/controller-runtime-v0.2.0
2 parents 114e0ae + 66e78cc commit c825c90

File tree

11 files changed

+364
-99
lines changed

11 files changed

+364
-99
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
### Added
44

55
- Document new compile-time dependency `mercurial` in user-facing documentation. ([#1683](https://github.com/operator-framework/operator-sdk/pull/1683))
6+
- Adds new flag `--zap-time-encoding` to the flagset provided by `pkg/log/zap`. This flag configures the timestamp format produced by the zap logger. See the [logging doc](https://github.com/operator-framework/operator-sdk/blob/master/doc/user/logging.md) for more information. ([#1529](https://github.com/operator-framework/operator-sdk/pull/1529))
67

78
### Changed
89

OWNERS

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ approvers:
33
- AlexNPavel
44
- estroz
55
- shawn-hurley
6-
- LiliC
76
- joelanford
87
- theishshah
98
reviewers:
109
- hasbro17
1110
- AlexNPavel
1211
- estroz
1312
- shawn-hurley
14-
- LiliC
1513
- joelanford
1614
- theishshah

doc/user-guide.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,17 @@ Follow the steps in the [installation guide][install_guide] to learn how to inst
2424
Use the CLI to create a new memcached-operator project:
2525

2626
```sh
27-
$ mkdir -p $HOME/projects/example.com/
28-
$ cd $HOME/projects/example.com/
29-
$ operator-sdk new memcached-operator
27+
$ mkdir -p $HOME/projects
28+
$ cd $HOME/projects
29+
$ operator-sdk new memcached-operator --repo=github.com/example-inc/memcached-operator
3030
$ cd memcached-operator
3131
```
3232

3333
To learn about the project directory structure, see [project layout][layout_doc] doc.
3434

3535
#### A note on dependency management
3636

37-
By default, `operator-sdk new` generates a `go.mod` file to be used with [Go modules][go_mod_wiki]. If you'd like to use [`dep`][dep_tool], set `--dep-manager=dep` when initializing your project, which will create a `Gopkg.toml` file with the same dependency information.
37+
By default, `operator-sdk new` generates a `go.mod` file to be used with [Go modules][go_mod_wiki]. The `--repo=<path>` flag is required when creating a project outside of `$GOPATH/src`, as scaffolded files require a valid module path. If you'd like to use [`dep`][dep_tool], set `--dep-manager=dep` when initializing your project, which will create a `Gopkg.toml` file with the same dependency information.
3838

3939
##### Go modules
4040

@@ -102,12 +102,12 @@ $ operator-sdk generate k8s
102102
```
103103

104104
### OpenAPI validation
105-
To update the OpenAPI validation section in the CRD `deploy/crds/cache_v1alpha1_memcached_crd.yaml`, run the following command.
105+
To update the OpenAPI validation section in the CRD `deploy/crds/cache_v1alpha1_memcached_crd.yaml`, run the following command.
106106

107107
```console
108108
$ operator-sdk generate openapi
109109
```
110-
This validation section allows Kubernetes to validate the properties in a Memcached Custom Resource when it is created or updated. An example of the generated YAML is as follows:
110+
This validation section allows Kubernetes to validate the properties in a Memcached Custom Resource when it is created or updated. An example of the generated YAML is as follows:
111111

112112
```YAML
113113
spec:

doc/user/logging.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ By default, `zap.Logger()` will return a logger that is ready for production use
1414
* `--zap-encoder` string - Sets the zap log encoding (`json` or `console`)
1515
* `--zap-level` string or integer - Sets the zap log level (`debug`, `info`, `error`, or an integer value greater than 0). If 4 or greater the verbosity of client-go will be set to this level.
1616
* `--zap-sample` - Enables zap's sampling mode. Sampling will be disabled for integer log levels greater than 1.
17+
* `--zap-time-encoding` string - Sets the zap time format (`epoch`, `millis`, `nano`, or `iso8601`)
1718

1819
### A simple example
1920

internal/pkg/scaffold/olm-catalog/csv.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func getCSVFromFSIfExists(fs afero.Fs, path string) (*olmapiv1alpha1.ClusterServ
169169

170170
csv := &olmapiv1alpha1.ClusterServiceVersion{}
171171
if err := yaml.Unmarshal(csvBytes, csv); err != nil {
172-
return nil, false, errors.Wrap(err, path)
172+
return nil, false, errors.Wrapf(err, "error unmarshalling CSV %s", path)
173173
}
174174

175175
return csv, true, nil
@@ -346,28 +346,29 @@ func (s *CSV) updateCSVFromManifestFiles(cfg *CSVConfig, csv *olmapiv1alpha1.Clu
346346
scanner := yamlutil.NewYAMLScanner(yamlData)
347347
for scanner.Scan() {
348348
yamlSpec := scanner.Bytes()
349-
kind, err := k8sutil.GetKindfromYAML(yamlSpec)
349+
typemeta, err := k8sutil.GetTypeMetaFromBytes(yamlSpec)
350350
if err != nil {
351-
return errors.Wrap(err, f)
351+
return errors.Wrapf(err, "error getting type metadata from manifest %s", f)
352352
}
353-
found, err := store.AddToUpdater(yamlSpec, kind)
353+
found, err := store.AddToUpdater(yamlSpec, typemeta.Kind)
354354
if err != nil {
355-
return errors.Wrap(err, f)
355+
return errors.Wrapf(err, "error adding manifest %s to CSV updaters", f)
356356
}
357357
if !found {
358-
if _, ok := otherSpecs[kind]; !ok {
359-
otherSpecs[kind] = make([][]byte, 0)
358+
id := gvkID(typemeta.GroupVersionKind())
359+
if _, ok := otherSpecs[id]; !ok {
360+
otherSpecs[id] = make([][]byte, 0)
360361
}
361-
otherSpecs[kind] = append(otherSpecs[kind], yamlSpec)
362+
otherSpecs[id] = append(otherSpecs[id], yamlSpec)
362363
}
363364
}
364365
if err = scanner.Err(); err != nil {
365366
return err
366367
}
367368
}
368369

369-
for k := range store.crds.crKinds {
370-
if crSpecs, ok := otherSpecs[k]; ok {
370+
for id := range store.crds.crIDs {
371+
if crSpecs, ok := otherSpecs[id]; ok {
371372
for _, spec := range crSpecs {
372373
if err := store.AddCR(spec); err != nil {
373374
return err

internal/pkg/scaffold/olm-catalog/csv_updaters.go

Lines changed: 62 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,20 @@ package catalog
1717
import (
1818
"bytes"
1919
"encoding/json"
20-
"fmt"
2120
"strings"
2221

2322
"github.com/operator-framework/operator-sdk/pkg/k8sutil"
2423

2524
"github.com/ghodss/yaml"
2625
olmapiv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
2726
olminstall "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
27+
"github.com/pkg/errors"
2828
log "github.com/sirupsen/logrus"
2929
appsv1 "k8s.io/api/apps/v1"
3030
corev1 "k8s.io/api/core/v1"
3131
rbacv1 "k8s.io/api/rbac/v1"
3232
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
33+
"k8s.io/apimachinery/pkg/runtime/schema"
3334
)
3435

3536
// CSVUpdater is an interface for any data that can be in a CSV, which will be
@@ -207,7 +208,7 @@ func (u *InstallStrategyUpdate) Apply(csv *olmapiv1alpha1.ClusterServiceVersion)
207208
u.updateClusterPermissions(s)
208209
u.updateDeploymentSpecs(s)
209210
default:
210-
return fmt.Errorf("install strategy (%v) of unknown type", strat)
211+
return errors.Errorf("install strategy (%v) of unknown type", strat)
211212
}
212213

213214
// Re-serialize permissions into csv strategy.
@@ -240,40 +241,82 @@ func (u *InstallStrategyUpdate) updateDeploymentSpecs(strat *olminstall.Strategy
240241

241242
type CustomResourceDefinitionsUpdate struct {
242243
*olmapiv1alpha1.CustomResourceDefinitions
243-
crKinds map[string]struct{}
244+
crIDs map[string]struct{}
244245
}
245246

246247
func (store *updaterStore) AddOwnedCRD(yamlDoc []byte) error {
247248
crd := &apiextv1beta1.CustomResourceDefinition{}
248249
if err := yaml.Unmarshal(yamlDoc, crd); err != nil {
249250
return err
250251
}
251-
store.crds.Owned = append(store.crds.Owned, olmapiv1alpha1.CRDDescription{
252-
Name: crd.ObjectMeta.Name,
253-
Version: crd.Spec.Version,
254-
Kind: crd.Spec.Names.Kind,
255-
})
256-
store.crds.crKinds[crd.Spec.Names.Kind] = struct{}{}
252+
versions, err := getCRDVersions(crd)
253+
if err != nil {
254+
return errors.Wrapf(err, "failed to get owned CRD %s versions", crd.GetName())
255+
}
256+
for _, ver := range versions {
257+
kind := crd.Spec.Names.Kind
258+
crdDesc := olmapiv1alpha1.CRDDescription{
259+
Name: crd.ObjectMeta.Name,
260+
Version: ver,
261+
Kind: kind,
262+
}
263+
store.crds.crIDs[crdDescID(crdDesc)] = struct{}{}
264+
store.crds.Owned = append(store.crds.Owned, crdDesc)
265+
}
257266
return nil
258267
}
259268

269+
func getCRDVersions(crd *apiextv1beta1.CustomResourceDefinition) (versions []string, err error) {
270+
if len(crd.Spec.Versions) != 0 {
271+
for _, ver := range crd.Spec.Versions {
272+
// Only versions served by the API server are relevant to a CSV.
273+
if ver.Served {
274+
versions = append(versions, ver.Name)
275+
}
276+
}
277+
} else if crd.Spec.Version != "" {
278+
versions = append(versions, crd.Spec.Version)
279+
}
280+
if len(versions) == 0 {
281+
return nil, errors.Errorf("no versions in CRD %s", crd.GetName())
282+
}
283+
return versions, nil
284+
}
285+
286+
// crdDescID produces an opaque, unique string identifying a CRDDescription.
287+
func crdDescID(desc olmapiv1alpha1.CRDDescription) string {
288+
// Name should always be <lower kind>.<group>, so this is effectively a GVK.
289+
splitName := strings.Split(desc.Name, ".")
290+
return getGVKID(strings.Join(splitName[1:], "."), desc.Version, desc.Kind)
291+
}
292+
293+
// gvkID produces an opaque, unique string identifying a GVK.
294+
func gvkID(gvk schema.GroupVersionKind) string {
295+
return getGVKID(gvk.Group, gvk.Version, gvk.Kind)
296+
}
297+
298+
func getGVKID(g, v, k string) string {
299+
return g + v + k
300+
}
301+
260302
// Apply updates csv's "owned" CRDDescriptions. "required" CRDDescriptions are
261303
// left as-is, since they are user-defined values.
304+
// Apply will only make a new spec.customresourcedefinitions.owned element if
305+
// the CRD key is not in spec.customresourcedefinitions.owned already.
262306
func (u *CustomResourceDefinitionsUpdate) Apply(csv *olmapiv1alpha1.ClusterServiceVersion) error {
263307
set := make(map[string]olmapiv1alpha1.CRDDescription)
264-
for _, csvDesc := range csv.Spec.CustomResourceDefinitions.Owned {
265-
set[csvDesc.Name] = csvDesc
308+
for _, uDesc := range u.Owned {
309+
set[crdDescID(uDesc)] = uDesc
266310
}
267-
du := u.DeepCopy()
268-
for i, uDesc := range u.Owned {
269-
if csvDesc, ok := set[uDesc.Name]; ok {
270-
csvDesc.Name = uDesc.Name
271-
csvDesc.Version = uDesc.Version
272-
csvDesc.Kind = uDesc.Kind
273-
du.Owned[i] = csvDesc
311+
newDescs := []olmapiv1alpha1.CRDDescription{}
312+
for _, csvDesc := range csv.Spec.CustomResourceDefinitions.Owned {
313+
if uDesc, ok := set[crdDescID(csvDesc)]; !ok {
314+
newDescs = append(newDescs, uDesc)
315+
} else {
316+
newDescs = append(newDescs, csvDesc)
274317
}
275318
}
276-
csv.Spec.CustomResourceDefinitions.Owned = du.Owned
319+
csv.Spec.CustomResourceDefinitions.Owned = newDescs
277320
return nil
278321
}
279322

internal/util/k8sutil/k8sutil.go

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,16 @@
1515
package k8sutil
1616

1717
import (
18+
"bytes"
1819
"fmt"
20+
"io"
1921
"strings"
2022
"unicode"
2123

22-
"github.com/ghodss/yaml"
24+
"github.com/pkg/errors"
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
27+
"k8s.io/apimachinery/pkg/util/yaml"
2328
"k8s.io/client-go/rest"
2429
"k8s.io/client-go/tools/clientcmd"
2530
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
@@ -55,16 +60,6 @@ func GetKubeconfigAndNamespace(configPath string) (*rest.Config, string, error)
5560
return kubeconfig, namespace, nil
5661
}
5762

58-
func GetKindfromYAML(yamlData []byte) (string, error) {
59-
var temp struct {
60-
Kind string
61-
}
62-
if err := yaml.Unmarshal(yamlData, &temp); err != nil {
63-
return "", err
64-
}
65-
return temp.Kind, nil
66-
}
67-
6863
// GetDisplayName turns a project dir name in any of {snake, chain, camel}
6964
// cases, hierarchical dot structure, or space-delimited into a
7065
// space-delimited, title'd display name.
@@ -99,3 +94,22 @@ func GetDisplayName(name string) string {
9994
}
10095
return strings.TrimSpace(strings.Title(strings.Join(splitName, " ")))
10196
}
97+
98+
// GetTypeMetaFromBytes gets the type and object metadata from b. b is assumed
99+
// to be a single Kubernetes resource manifest.
100+
func GetTypeMetaFromBytes(b []byte) (t metav1.TypeMeta, err error) {
101+
u := unstructured.Unstructured{}
102+
r := bytes.NewReader(b)
103+
dec := yaml.NewYAMLOrJSONDecoder(r, 8)
104+
// There is only one YAML doc if there are no more bytes to be read or EOF
105+
// is hit.
106+
if err := dec.Decode(&u); err == nil && r.Len() != 0 {
107+
return t, errors.New("error getting TypeMeta from bytes: more than one manifest in b")
108+
} else if err != nil && err != io.EOF {
109+
return t, errors.Wrap(err, "error getting TypeMeta from bytes")
110+
}
111+
return metav1.TypeMeta{
112+
APIVersion: u.GetAPIVersion(),
113+
Kind: u.GetKind(),
114+
}, nil
115+
}

0 commit comments

Comments
 (0)