Skip to content

Commit

Permalink
Add an example manifest converter for conversion of singleton lists t…
Browse files Browse the repository at this point in the history
…o embedded object

Signed-off-by: Sergen Yalçın <[email protected]>
  • Loading branch information
sergenyalcin committed May 6, 2024
1 parent 9a463d5 commit 6d6afab
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 20 deletions.
139 changes: 139 additions & 0 deletions pkg/config/example_conversions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// SPDX-FileCopyrightText: 2024 The Crossplane Authors <https://crossplane.io>
//
// SPDX-License-Identifier: Apache-2.0

package config

import (
"bytes"
"fmt"
"io"
"log"
"os"
"path/filepath"
"sigs.k8s.io/yaml"
"strings"

"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
k8sschema "k8s.io/apimachinery/pkg/runtime/schema"
kyaml "k8s.io/apimachinery/pkg/util/yaml"

"github.com/crossplane/upjet/pkg/config/conversion"
)

func ConvertSingletonListToEmbeddedObject(pc *Provider, startPath string) error {
resourceRegistry := prepareResourceRegistry(pc)
err := filepath.Walk(startPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return errors.Wrap(err, "walk failed")
}

var convertedFileContent string
if !info.IsDir() && strings.HasSuffix(info.Name(), ".yaml") {
log.Printf("Converting: %s\n", path)
content, err := os.ReadFile(path)
if err != nil {
return errors.Wrap(err, "failed to read file")
}

examples, err := decodeExamples(string(content))
if err != nil {
return errors.Wrap(err, "failed to decode examples")
}

rootResource := resourceRegistry[fmt.Sprintf("%s/%s", examples[0].GroupVersionKind().Kind, examples[0].GroupVersionKind().Group)]
if rootResource == nil {
return nil
}

newPath := strings.Replace(path, examples[0].GroupVersionKind().Version, rootResource.Version, -1)
if path == newPath {
return nil
}
annotationValue := strings.ToLower(fmt.Sprintf("%s/%s/%s", rootResource.ShortGroup, rootResource.Version, rootResource.Kind))
for _, e := range examples {
if resource, ok := resourceRegistry[fmt.Sprintf("%s/%s", e.GroupVersionKind().Kind, e.GroupVersionKind().Group)]; ok {
conversionPaths := resource.CRDListConversionPaths()
if conversionPaths != nil && e.GroupVersionKind().Version != resource.Version {
for i, cp := range conversionPaths {
conversionPaths[i] = "spec.forProvider." + cp
}
converted, err := conversion.Convert(e.Object, conversionPaths, conversion.ToEmbeddedObject)
if err != nil {
return errors.Wrap(err, "failed to convert example to embedded object")
}
e.Object = converted
e.SetGroupVersionKind(k8sschema.GroupVersionKind{
Group: e.GroupVersionKind().Group,
Version: resource.Version,
Kind: e.GetKind(),
})
}
annotations := e.GetAnnotations()
annotations["meta.upbound.io/example-id"] = annotationValue
e.SetAnnotations(annotations)
}
}
convertedFileContent = "# SPDX-FileCopyrightText: 2024 The Crossplane Authors <https://crossplane.io>\n#\n# SPDX-License-Identifier: CC0-1.0\n\n"
for i, e := range examples {
var convertedData []byte
convertedData, err := yaml.Marshal(&e)
if err != nil {
return errors.Wrap(err, "failed to marshal example to yaml")
}
if i == len(examples)-1 {
convertedFileContent += string(convertedData)
} else {
convertedFileContent += string(convertedData) + "\n---\n\n"
}
}
dir := filepath.Dir(newPath)

// Create all necessary directories if they do not exist
err = os.MkdirAll(dir, os.ModePerm)
if err != nil {
return errors.Wrap(err, "failed to create directory")
}
f, err := os.Create(newPath)
if err != nil {
return errors.Wrap(err, "failed to create file")
}
if _, err := f.Write([]byte(convertedFileContent)); err != nil {
return errors.Wrap(err, "failed to write to file")
}
log.Printf("Converted: %s\n", path)
}
return nil
})
if err != nil {
log.Printf("Error walking the path %q: %v\n", startPath, err)
}
return nil
}

func prepareResourceRegistry(pc *Provider) map[string]*Resource {
reg := map[string]*Resource{}
for _, r := range pc.Resources {
reg[fmt.Sprintf("%s/%s.%s", r.Kind, r.ShortGroup, pc.RootGroup)] = r
}
return reg
}

func decodeExamples(content string) ([]*unstructured.Unstructured, error) {
var manifests []*unstructured.Unstructured
decoder := kyaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(content), 1024)
for {
u := &unstructured.Unstructured{}
if err := decoder.Decode(&u); err != nil {
if errors.Is(err, io.EOF) {
break
}
return nil, errors.Wrap(err, "cannot decode manifest")
}
if u != nil {
manifests = append(manifests, u)
}
}
return manifests, nil
}
40 changes: 20 additions & 20 deletions pkg/config/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,26 @@
package config

import (
"context"
"fmt"
"strings"
"time"

xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
fwresource "github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/crossplane/upjet/pkg/config/conversion"
"github.com/crossplane/upjet/pkg/registry"
"context"
"fmt"
"strings"
"time"

xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
fwresource "github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/crossplane/upjet/pkg/config/conversion"
"github.com/crossplane/upjet/pkg/registry"
)

// A ListType is a type of list.
Expand Down

0 comments on commit 6d6afab

Please sign in to comment.