Skip to content

Commit

Permalink
Merge pull request #129 from erikgb/conversion-gen
Browse files Browse the repository at this point in the history
chore: introduce conversion-gen to generate conversion functions
  • Loading branch information
zoetrope authored May 24, 2024
2 parents 8b60897 + 453777e commit ba1a6a6
Show file tree
Hide file tree
Showing 8 changed files with 239 additions and 68 deletions.
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ manifests: setup ## Generate WebhookConfiguration, ClusterRole and CustomResourc
kustomize build config/kustomize-to-helm/overlays/templates | yq e "." -p yaml - > charts/accurate/templates/generated/generated.yaml

.PHONY: generate
generate: setup generate-applyconfigurations ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
generate: setup generate-applyconfigurations generate-conversion ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
controller-gen object:headerFile="hack/boilerplate.go.txt" paths="{./api/...}"

GO_MODULE = $(shell go list -m)
API_DIRS = $(shell find api -mindepth 2 -type d | sed "s|^|$(shell go list -m)/|" | paste -sd " ")
AC_PKG = internal/applyconfigurations

.PHONY: generate-applyconfigurations
generate-applyconfigurations: setup ## Generate applyconfigurations to support typesafe SSA.
@echo ">> generating $(AC_PKG)..."
Expand All @@ -67,6 +68,13 @@ generate-applyconfigurations: setup ## Generate applyconfigurations to support t
--output-pkg "$(GO_MODULE)/$(AC_PKG)" \
$(API_DIRS)

.PHONY: generate-conversion
generate-conversion: setup ## Generate conversion functions to support API conversion.
@echo ">> generating $(AC_PKG)..."
conversion-gen \
--output-file zz_generated.conversion.go \
$(API_DIRS)

.PHONY: apidoc
apidoc: setup $(wildcard api/*/*_types.go)
crd-to-markdown --links docs/links.csv -f api/accurate/v1/subnamespace_types.go -n SubNamespace > docs/crd_subnamespace.md
Expand Down
79 changes: 79 additions & 0 deletions api/accurate/v1/conversion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package v1

import (
"encoding/json"
"fmt"
"strconv"

accuratev2alpha1 "github.com/cybozu-go/accurate/api/accurate/v2alpha1"
"github.com/cybozu-go/accurate/pkg/constants"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/conversion"
kstatus "sigs.k8s.io/cli-utils/pkg/kstatus/status"
)

// Convert_v1_SubNamespace_To_v2alpha1_SubNamespace complements the generated conversion functions since status needs special handling
func Convert_v1_SubNamespace_To_v2alpha1_SubNamespace(in *SubNamespace, out *accuratev2alpha1.SubNamespace, s conversion.Scope) error {
if err := autoConvert_v1_SubNamespace_To_v2alpha1_SubNamespace(in, out, s); err != nil {
return err
}

// Restore info from annotations to ensure conversions are lossy-less.
// Delete annotation after processing it to avoid polluting converted resource.
if v, ok := out.Annotations[constants.AnnObservedGeneration]; ok {
obsGen, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return fmt.Errorf("error converting %q to int64 from annotation %s", v, constants.AnnObservedGeneration)
}
out.Status.ObservedGeneration = obsGen

delete(out.Annotations, constants.AnnObservedGeneration)
}
if conds, ok := out.Annotations[constants.AnnConditions]; ok {
err := json.Unmarshal([]byte(conds), &out.Status.Conditions)
if err != nil {
return fmt.Errorf("error unmarshalling JSON from annotation %s", constants.AnnConditions)
}

delete(out.Annotations, constants.AnnConditions)
}
return nil
}

// Convert_v2alpha1_SubNamespace_To_v1_SubNamespace complements the generated conversion functions since status needs special handling
func Convert_v2alpha1_SubNamespace_To_v1_SubNamespace(in *accuratev2alpha1.SubNamespace, out *SubNamespace, s conversion.Scope) error {
if err := autoConvert_v2alpha1_SubNamespace_To_v1_SubNamespace(in, out, s); err != nil {
return err
}

switch {
case meta.IsStatusConditionTrue(in.Status.Conditions, string(kstatus.ConditionStalled)):
out.Status = SubNamespaceConflict
case in.Status.ObservedGeneration == 0:
// SubNamespace has never been reconciled.
case in.Status.ObservedGeneration == in.Generation && len(in.Status.Conditions) == 0:
out.Status = SubNamespaceOK
default:
// SubNamespace is in some transitional state, not possible to represent in v1 status.
// An unset value is probably our best option.
}

// Store info in annotations to ensure conversions are lossy-less.
if out.Annotations == nil {
out.Annotations = make(map[string]string)
}
if in.Status.ObservedGeneration != 0 {
out.Annotations[constants.AnnObservedGeneration] = strconv.FormatInt(in.Status.ObservedGeneration, 10)
}
if len(in.Status.Conditions) > 0 {
buf, err := json.Marshal(in.Status.Conditions)
if err != nil {
return fmt.Errorf("error marshalling conditions to JSON")
}
out.Annotations[constants.AnnConditions] = string(buf)
}
if len(out.Annotations) == 0 {
out.Annotations = nil
}
return nil
}
1 change: 1 addition & 0 deletions api/accurate/v1/doc.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// +kubebuilder:object:generate=true
// +groupName=accurate.cybozu.com
// +k8s:conversion-gen=github.com/cybozu-go/accurate/api/accurate/v2alpha1
package v1
2 changes: 2 additions & 0 deletions api/accurate/v1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ var (

// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme

localSchemeBuilder = SchemeBuilder.SchemeBuilder
)
69 changes: 2 additions & 67 deletions api/accurate/v1/subnamespace_conversion.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
package v1

import (
"encoding/json"
"fmt"
"strconv"

accuratev2alpha1 "github.com/cybozu-go/accurate/api/accurate/v2alpha1"
"github.com/cybozu-go/accurate/pkg/constants"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/api/meta"
kstatus "sigs.k8s.io/cli-utils/pkg/kstatus/status"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/conversion"
Expand All @@ -25,31 +18,7 @@ func (src *SubNamespace) ConvertTo(dstRaw conversion.Hub) error {
)
logger.V(5).Info("converting")

dst.ObjectMeta = src.ObjectMeta
dst.Spec.Annotations = src.Spec.Annotations
dst.Spec.Labels = src.Spec.Labels

// Restore info from annotations to ensure conversions are lossy-less.
// Delete annotation after processing it to avoid polluting converted resource.
if v, ok := dst.Annotations[constants.AnnObservedGeneration]; ok {
obsGen, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return fmt.Errorf("error converting %q to int64 from annotation %s", v, constants.AnnObservedGeneration)
}
dst.Status.ObservedGeneration = obsGen

delete(dst.Annotations, constants.AnnObservedGeneration)
}
if conds, ok := dst.Annotations[constants.AnnConditions]; ok {
err := json.Unmarshal([]byte(conds), &dst.Status.Conditions)
if err != nil {
return fmt.Errorf("error unmarshalling JSON from annotation %s", constants.AnnConditions)
}

delete(dst.Annotations, constants.AnnConditions)
}

return nil
return Convert_v1_SubNamespace_To_v2alpha1_SubNamespace(src, dst, nil)
}

// ConvertFrom converts from the Hub version (v2alpha1) to this version.
Expand All @@ -62,41 +31,7 @@ func (dst *SubNamespace) ConvertFrom(srcRaw conversion.Hub) error {
)
logger.V(5).Info("converting")

dst.ObjectMeta = src.ObjectMeta
dst.Spec.Annotations = src.Spec.Annotations
dst.Spec.Labels = src.Spec.Labels

switch {
case meta.IsStatusConditionTrue(src.Status.Conditions, string(kstatus.ConditionStalled)):
dst.Status = SubNamespaceConflict
case src.Status.ObservedGeneration == 0:
// SubNamespace has never been reconciled.
case src.Status.ObservedGeneration == src.Generation && len(src.Status.Conditions) == 0:
dst.Status = SubNamespaceOK
default:
// SubNamespace is in some transitional state, not possible to represent in v1 status.
// An unset value is probably our best option.
}

// Store info in annotations to ensure conversions are lossy-less.
if dst.Annotations == nil {
dst.Annotations = make(map[string]string)
}
if src.Status.ObservedGeneration != 0 {
dst.Annotations[constants.AnnObservedGeneration] = strconv.FormatInt(src.Status.ObservedGeneration, 10)
}
if len(src.Status.Conditions) > 0 {
buf, err := json.Marshal(src.Status.Conditions)
if err != nil {
return fmt.Errorf("error marshalling conditions to JSON")
}
dst.Annotations[constants.AnnConditions] = string(buf)
}
if len(dst.Annotations) == 0 {
dst.Annotations = nil
}

return nil
return Convert_v2alpha1_SubNamespace_To_v1_SubNamespace(src, dst, nil)
}

func getConversionLogger(obj client.Object) logr.Logger {
Expand Down
136 changes: 136 additions & 0 deletions api/accurate/v1/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions aqua.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ packages:
- name: goreleaser/goreleaser@v1.19.1
- name: kubernetes/code-generator/applyconfiguration-gen@v0.30.0
registry: local
- name: kubernetes/code-generator/conversion-gen@v0.30.0
registry: local
8 changes: 8 additions & 0 deletions registry.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,11 @@ packages:
description: applyconfiguration-gen is a tool for auto-generating apply configuration functions.
files:
- name: applyconfiguration-gen
- type: go_install
name: kubernetes/code-generator/conversion-gen
path: k8s.io/code-generator/cmd/conversion-gen
repo_owner: kubernetes
repo_name: code-generator
description: conversion-gen is a tool for auto-generating API conversion functions.
files:
- name: conversion-gen

0 comments on commit ba1a6a6

Please sign in to comment.