Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructure packages #8

Merged
merged 7 commits into from
Jun 20, 2024
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ BRANCH := $(shell git branch --show-current)
PKL_BASE_URI := package://pkg.pkl-lang.org

PKL_CORE_NAME := crossplane
PKL_CORE_VERSION := 0.0.29
PKL_CORE_VERSION := 1.0.0
PKL_CORE_REF := ${PKL_CORE_NAME}@${PKL_CORE_VERSION}
PKL_CORE_URI := ${PKL_BASE_URI}/${REPO}/${PKL_CORE_REF}

PKL_EXAMPLE_NAME := crossplane-example
PKL_EXAMPLE_VERSION := 0.1.19
PKL_EXAMPLE_VERSION := 1.0.0
PKL_EXAMPLE_REF := ${PKL_EXAMPLE_NAME}@${PKL_EXAMPLE_VERSION}
PKL_EXAMPLE_URI := ${PKL_BASE_URI}/${REPO}/${PKL_CORE_REF}

Expand Down
53 changes: 3 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,61 +35,14 @@ spec:
spec:
type: uri
# This pkl file is at `pkl/crossplane-example/full.pkl` in this repo
uri: "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/crossplane-example@0.1.19#/full.pkl"
uri: "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/crossplane-example@1.0.0#/full.pkl"
```

### Example
see [examples](./example/)

## Building a Pkl Package
A Pkl Package can be built in the following steps:
1. Create Pkl files in a directory
> Note: you can [convert CRDs and Manifests](#generating-pkl-files-and-modules-from-manifests) to Pkl
1. Create a PklProject file (take a look at pkl/crossplane-example/PklProject for reference)
* Make sure that `\(baseUri)@\(version)` is the url where the package metadata can be downloaded from
* Likewise `\(baseUri)@\(version).zip` is the path where the content will be expected.
> Note: The PklProjects in this repository use pkg.pkl-lang.org, as they redirect to the download
* the path https://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/[email protected]
* redirects to https://github.com/crossplane-contrib/function-pkl/releases/download/[email protected]/[email protected]
1. Run `pkl project resolve` to resolve the dependencies of the PklProject
1. Run `pkl project package` to package the Project into the files and make them ready for the upload.
1. Publish the Package
* This can be done by uploading the files created by the previous command to the place defined in step 2.
* in github this can be done by creating a release and uploading the files to it.

## Basic Pkl File
Pkl Files used in this Function **must** amend CompositionRequest.pkl.
see [here](example/inline/composition.yaml) and [here](pkl/crossplane-example/full.pkl)

### Generating Pkl Files and Modules from Manifests
There are some package to make it easier to convert existing CRDs or Manifests into the Pkl format.
> [!NOTE]
> There is currently no module to convert from CompositeResourceDefinitions (XRDs) to Pkl.
> Crossplane Creates CRDs from the XRDs. These CRDs can be converted instead.
> If direct conversion would be useful to you - please create an issue.

In this example we'll implement the [Object][provider-kubernetes-object] resource from [provider-kubernetes][provider-kubernetes].

1. First we will generate a Pkl Module from the Object CRD.
```bash
pkl eval "package://pkg.pkl-lang.org/pkl-pantry/[email protected]#/generate.pkl" -m . -p source="https://raw.githubusercontent.com/crossplane-contrib/provider-kubernetes/main/package/crds/kubernetes.crossplane.io_objects.yaml"
```
This should create a `Object.pkl` file.

1. Create a small Pkl file which adds context for the converter about the CRDs.
```pkl
amends "package://pkg.pkl-lang.org/pkl-pantry/[email protected]#/convert.pkl"
customResourceTemplates {
["Object"] {
["kubernetes.crossplane.io/v1alpha2"] = import("Object.pkl")
}
}
```

1. Convert a object manifest to pkl
```bash
pkl eval -p "input=https://raw.githubusercontent.com/crossplane-contrib/provider-kubernetes/main/examples/object/object.yaml" -o example-object.pkl <CONVERT-FILE-FROM-PREVIOUS-STEP>.pkl
```
## Creating a new Composition Function
see [pkl/crossplane.contrib.example/README.md](pkl/crossplane.contrib.example/README.md)

## Development
This function uses [Go][go], [Docker][docker], the [Crossplane CLI][cli], and the [Pkl CLI][pkl cli] to build functions
Expand Down
2 changes: 1 addition & 1 deletion example/full/composition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ spec:
spec:
type: uri
# This pkl file is at `pkl/crossplane-example/full.pkl` in this repo
uri: "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/crossplane-example@0.1.19#/full.pkl"
uri: "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/crossplane-example@1.0.0#/full.pkl"
10 changes: 5 additions & 5 deletions example/inline/composition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ spec:
type: inline
# This pkl file is at `pkl/crossplane-example/full.pkl` in this repo
inline: |
amends "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/crossplane@0.0.29#/CompositionResponse.pkl"
import "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/crossplane@0.0.29#/Resource.pkl"
import "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/crossplane@0.0.29#/Crossplane.pkl"
amends "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/crossplane@1.0.0#/CompositionResponse.pkl"
import "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/crossplane@1.0.0#/Resource.pkl"
import "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/crossplane@1.0.0#/Crossplane.pkl"

import "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/crossplane-example@0.1.19#/crds/XR.pkl"
import "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/crossplane-example@0.1.19#/crds/Object.pkl"
import "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/crossplane-example@1.0.0#/crds/XR.pkl"
import "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/crossplane-example@1.0.0#/crds/Object.pkl"

import "package://pkg.pkl-lang.org/pkl-k8s/[email protected]#/api/core/v1/ConfigMap.pkl"

Expand Down
13 changes: 12 additions & 1 deletion input/v1beta1/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
// This isn't a custom resource, in the sense that we never install its CRD.
// It is a KRM-like object, so we generate a CRD to describe its schema.

// Input can be used to provide input to this Function.

Check warning on line 28 in input/v1beta1/input.go

View workflow job for this annotation

GitHub Actions / lint

exported: comment on exported type Pkl should be of the form "Pkl ..." (with optional leading article) (revive)
// +kubebuilder:object:root=true
// +kubebuilder:storageversion
// +kubebuilder:resource:categories=crossplane
Expand All @@ -37,12 +37,23 @@
Spec PklSpec `json:"spec,omitempty"`
}

type PklSpec struct {

Check warning on line 40 in input/v1beta1/input.go

View workflow job for this annotation

GitHub Actions / lint

exported: exported type PklSpec should have comment or be unexported (revive)
// +kubebuilder:validation:Enum=uri;inline
// +kubebuilder:validation:Enum=uri;inline;local
Type string `json:"type,omitempty"`

// Use URI Scheme to load Project/Package
Uri string `json:"uri,omitempty"`

Check warning on line 45 in input/v1beta1/input.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: struct field Uri should be URI (revive)
// Contains a stringified Pkl file
Inline string `json:"inline,omitempty"`

// Reference to a Pklfile and Project
Local *Local `json:"local,omitempty"`
}

// Local contains Reference to a Local Pkl Project and a Pkl file within it
type Local struct {
// Path to file relative from the Project Dir
File string `json:"file,omitempty"`
// Path to the Project containing a Pklfile
ProjectDir string `json:"projectDir,omitempty"`
}
22 changes: 21 additions & 1 deletion input/v1beta1/zz_generated.deepcopy.go

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

84 changes: 60 additions & 24 deletions internal/function/fn.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@

import (
"context"
"google.golang.org/protobuf/types/known/durationpb"

Check failure on line 19 in internal/function/fn.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gci`-ed with --skip-generated -s standard -s default -s prefix(github.com/crossplane) -s prefix(github.com/crossplane-contrib) -s blank -s dot --custom-order (gci)

"github.com/apple/pkl-go/pkl"
"github.com/crossplane-contrib/function-pkl/input/v1beta1"

Check failure on line 22 in internal/function/fn.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gci`-ed with --skip-generated -s standard -s default -s prefix(github.com/crossplane) -s prefix(github.com/crossplane-contrib) -s blank -s dot --custom-order (gci)
"github.com/crossplane-contrib/function-pkl/internal/helper"
"github.com/crossplane-contrib/function-pkl/internal/pkl/reader"
"github.com/crossplane/crossplane-runtime/pkg/errors"
Expand All @@ -26,7 +27,7 @@
fnv1beta1 "github.com/crossplane/function-sdk-go/proto/v1beta1"
"github.com/crossplane/function-sdk-go/request"
"github.com/crossplane/function-sdk-go/response"
"sigs.k8s.io/yaml"

Check failure on line 30 in internal/function/fn.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gci`-ed with --skip-generated -s standard -s default -s prefix(github.com/crossplane) -s prefix(github.com/crossplane-contrib) -s blank -s dot --custom-order (gci)
)

// Function returns whatever response you ask it to.
Expand All @@ -49,56 +50,86 @@
return rsp, nil
}

evaluator, err := f.EvaluatorManager.NewEvaluator(ctx,
pkl.PreconfiguredOptions,
reader.WithCrossplane(&reader.CrossplaneReader{
ReaderScheme: "crossplane",
Request: &helper.CompositionRequest{
RunFunctionRequest: *req,
ExtraResources: req.GetExtraResources(),
},
Log: f.Log,
Ctx: ctx,
}),
)

moduleSource, err := getModuleSource(in.Spec)
if err != nil {
response.Fatal(rsp, errors.Wrap(err, "could not create Pkl Evaluater"))
response.Fatal(rsp, errors.Wrap(err, "invalid composition function input"))
return rsp, nil
}
defer evaluator.Close()

moduleSource, err := getModuleSource(in.Spec)
var evaluator pkl.Evaluator

switch in.Spec.Type {
case "local":
evaluator, err = f.EvaluatorManager.NewProjectEvaluator(ctx, in.Spec.Local.ProjectDir,
pkl.PreconfiguredOptions,
reader.WithCrossplane(&reader.CrossplaneReader{
ReaderScheme: "crossplane",
Request: &helper.CompositionRequest{
RunFunctionRequest: req,
ExtraResources: req.GetExtraResources(),
},
Log: f.Log,
Ctx: ctx,
}))
default:
evaluator, err = f.EvaluatorManager.NewEvaluator(ctx,
pkl.PreconfiguredOptions,
reader.WithCrossplane(&reader.CrossplaneReader{
ReaderScheme: "crossplane",
Request: &helper.CompositionRequest{
RunFunctionRequest: req,
ExtraResources: req.GetExtraResources(),
},
Log: f.Log,
Ctx: ctx,
}))
}

if err != nil {
response.Fatal(rsp, errors.Wrap(err, "invalid composition function input"))
response.Fatal(rsp, errors.Wrap(err, "could not create Pkl Evaluator"))
return rsp, nil
}
defer func(evaluator pkl.Evaluator) {
err := evaluator.Close()
if err != nil {
f.Log.Info("evaluator could not be closed correctly:", err)
}
}(evaluator)

renderedManifest, err := evaluator.EvaluateOutputText(ctx, moduleSource)
if err != nil {
response.Fatal(rsp, errors.Wrap(err, "error while parsing the Pkl file"))
return rsp, nil
}

helper := &helper.CompositionResponse{}
err = yaml.Unmarshal([]byte(renderedManifest), helper)
helperResponse := &helper.CompositionResponse{}
err = yaml.Unmarshal([]byte(renderedManifest), helperResponse)
if err != nil {
return nil, errors.Wrapf(err, "rendered Pkl file was not in expected format. did you amend @crossplane/CompositionResponse.pkl?")
}

fixedRequirements := &fnv1beta1.Requirements{
ExtraResources: convertExtraResources(helper.Requirements.ExtraResources),
ExtraResources: convertExtraResources(helperResponse.Requirements.ExtraResources),
}

responseMeta := &fnv1beta1.ResponseMeta{
Tag: req.GetMeta().GetTag(),
Ttl: durationpb.New(response.DefaultTTL),
}

// Note: consider not overwriting rsp and whether it makes a difference.
rsp = &fnv1beta1.RunFunctionResponse{
Meta: helper.Meta,
Desired: helper.Desired,
Results: helper.Results,
Context: helper.Context,
Meta: responseMeta,
Desired: helperResponse.Desired,
Results: helperResponse.Results,
Context: helperResponse.Context,
Requirements: fixedRequirements,
}

if ttl := helperResponse.GetMeta().GetTtl(); ttl != nil {
rsp.Meta.Ttl = ttl
}

return rsp, nil
}

Expand Down Expand Up @@ -138,6 +169,11 @@
return nil, errors.New("manifest type is inline but inline is empty")
}
return pkl.TextSource(pklSpec.Inline), nil
case "local":
if pklSpec.Local == nil {
return nil, errors.New("manifest type is file but uri is empty")
}
return pkl.FileSource(pklSpec.Local.File), nil
default:
return nil, errors.New("unknown pklSpec type")
}
Expand Down
20 changes: 15 additions & 5 deletions internal/function/fn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@

import (
"context"
"fmt"
"os"
"testing"

"github.com/apple/pkl-go/pkl"
"github.com/crossplane-contrib/function-pkl/input/v1beta1"

Check failure on line 24 in internal/function/fn_test.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gci`-ed with --skip-generated -s standard -s default -s prefix(github.com/crossplane) -s prefix(github.com/crossplane-contrib) -s blank -s dot --custom-order (gci)
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"google.golang.org/protobuf/testing/protocmp"
Expand All @@ -27,12 +29,12 @@

"github.com/crossplane/crossplane-runtime/pkg/logging"
fnv1beta1 "github.com/crossplane/function-sdk-go/proto/v1beta1"
"github.com/crossplane/function-sdk-go/resource"

Check failure on line 32 in internal/function/fn_test.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gci`-ed with --skip-generated -s standard -s default -s prefix(github.com/crossplane) -s prefix(github.com/crossplane-contrib) -s blank -s dot --custom-order (gci)
//objectv1alpha2 "github.com/crossplane-contrib/provider-kubernetes/apis/object/v1alpha2"
)

var (
pklPackage = "package://pkg.pkl-lang.org/github.com/crossplane-contrib/function-pkl/[email protected]"
workdir, _ = os.Getwd()
pklPackage = fmt.Sprintf("%s/../../pkl/crossplane.contrib.example", workdir)
)

func TestRunFunction(t *testing.T) {
Expand All @@ -59,8 +61,11 @@
Meta: &fnv1beta1.RequestMeta{Tag: "extra"},
Input: resource.MustStructObject(&v1beta1.Pkl{
Spec: v1beta1.PklSpec{
Type: "uri",
Uri: pklPackage + "#/full.pkl",
Type: "local",
Local: &v1beta1.Local{
ProjectDir: pklPackage,
File: pklPackage + "/full.pkl",
},
},
}),
Context: resource.MustStructJSON(`{
Expand Down Expand Up @@ -175,7 +180,12 @@
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
evaluatorManager := pkl.NewEvaluatorManager()
defer evaluatorManager.Close()
defer func(evaluatorManager pkl.EvaluatorManager) {
err := evaluatorManager.Close()
if err != nil {
t.Error(err)
}
}(evaluatorManager)
f := &Function{Log: logging.NewNopLogger(), EvaluatorManager: evaluatorManager}
rsp, err := f.RunFunction(tc.args.ctx, tc.args.req)

Expand Down
2 changes: 1 addition & 1 deletion internal/helper/composition.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import fnv1beta1 "github.com/crossplane/function-sdk-go/proto/v1beta1"

type CompositionRequest struct {
fnv1beta1.RunFunctionRequest
*fnv1beta1.RunFunctionRequest

ExtraResources map[string]*fnv1beta1.Resources `protobuf:"bytes,6,rep,name=extra_resources,json=extraResources,proto3" json:"extraResources,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
Expand All @@ -29,13 +29,13 @@
}

type Requirements struct {
//fnv1beta1.Requirements

Check failure on line 32 in internal/helper/composition.go

View workflow job for this annotation

GitHub Actions / lint

commentFormatting: put a space between `//` and comment text (gocritic)

ExtraResources map[string]*ResourceSelector `protobuf:"bytes,1,rep,name=extra_resources,json=extraResources,proto3" json:"extraResources,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}

type ResourceSelector struct {
ApiVersion string `protobuf:"bytes,1,opt,name=api_version,json=apiVersion,proto3" json:"apiVersion,omitempty"`

Check warning on line 38 in internal/helper/composition.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: struct field ApiVersion should be APIVersion (revive)
Kind string `protobuf:"bytes,2,opt,name=kind,proto3" json:"kind,omitempty"`
Match Match `json:"match,omitempty"`
}
Expand Down
11 changes: 11 additions & 0 deletions package/input/template.fn.crossplane.io_pkls.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,21 @@ spec:
inline:
description: Contains a stringified Pkl file
type: string
local:
description: Reference to a Pklfile and Project
properties:
file:
description: Path to file relative from the Project Dir
type: string
projectDir:
description: Path to the Project containing a Pklfile
type: string
type: object
type:
enum:
- uri
- inline
- local
type: string
uri:
description: Use URI Scheme to load Project/Package
Expand Down
Loading
Loading