Skip to content

Commit

Permalink
Merge pull request #8 from Avarei/refactor/packages
Browse files Browse the repository at this point in the history
Restructure packages
  • Loading branch information
Avarei authored Jun 20, 2024
2 parents 2698982 + e13a389 commit 3b608da
Show file tree
Hide file tree
Showing 36 changed files with 1,362 additions and 315 deletions.
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 @@ -38,11 +38,22 @@ type Pkl struct {
}

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,6 +16,7 @@ package function

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)
Expand Down Expand Up @@ -49,56 +50,86 @@ func (f *Function) RunFunction(ctx context.Context, req *fnv1beta1.RunFunctionRe
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 @@ func getModuleSource(pklSpec v1beta1.PklSpec) (*pkl.ModuleSource, error) {
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,6 +16,8 @@ package function

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

"github.com/apple/pkl-go/pkl"
Expand All @@ -28,11 +30,11 @@ import (
"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 @@ func TestRunFunction(t *testing.T) {
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 @@ func TestRunFunction(t *testing.T) {
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 @@ package helper
import fnv1beta1 "github.com/crossplane/function-sdk-go/proto/v1beta1"

type CompositionRequest struct {

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

View workflow job for this annotation

GitHub Actions / lint

exported: exported type CompositionRequest should have comment or be unexported (revive)
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 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

0 comments on commit 3b608da

Please sign in to comment.