View Source CRD Versions
Mix.install([:bonny])
Application.put_env(:bonny, :operator_name, "livebook-operator")
crd-definition-and-versions
CRD Definition and Versions
When defining your operator (use Bonny.Operator
), you have to implement the callback crds/0
where you define your custom resources. A custom resource definition (CRD) is represented by a %Bonny.API.CRD{}
struct which defines 4 fields:
:scope
- either:Namespaced
or:Cluster
:group
- The API group of your controller / this resource:names
- A map with 3-4 keys defining the names of this resource.plural
: name to be used in the URL:/apis/<group>/<version>/<plural>
- e.g. crontabssingular
: singular name to be used as an alias on the CLI and for display - e.g. crontabkind
: is normally the CamelCased singular type. Your resource manifests use this. - e.g. CronTabshortnames
: allow shorter string to match your resource on the CLI - e.g. [ct]
versions
: list of API Version modules for this Resource, defaults to the versions in config.exs
defmodule MyOperator.Operator do
use Bonny.Operator, default_watch_namespace: "default"
step :delegate_to_controller
def controllers(_watching_namespace, _opts), do: []
def crds() do
[
%Bonny.API.CRD{
names: %{kind: "CronTab", plural: "crontabs", shortNames: ["ct"], singular: "crontab"},
group: "example.com",
versions: [MyOperator.API.V1.CronTab],
scope: :Namespaces
}
]
end
end
We're going to look at version manifest declaration in more detail in just a moment. For now, let's just define a simple API version v1
for the CronTab
custom resource with just defaults for all the fields. You do this by defining a module that starts with the API declared in the application configuration (YourOperator.API.V1
), followed by the CRD name (CronTab
). The module must use Bonny.API.Version
which expects you to implement manifest/0
.
defmodule MyOperator.API.V1.CronTab do
use Bonny.API.Version
@impl Bonny.API.Version
def manifest() do
defaults()
|> struct!(name: "v1", storage: true)
end
end
YourOperator.API.V1.CronTab.manifest()
Now, if we define a CronTabController
, Bonny finds this version and add it to the CRD manifest.
crds =
[MyOperator.Operator]
|> Bonny.Mix.Operator.crds()
|> Ymlr.documents!()
IO.puts(crds)
version-manifest-declaration
Version Manifest Declaration
Our V1.CronTab
module called the defaults/0
macro from manifest/0
. This macro helps initializing a generic version with no schema, subresources or additional printer columns. The storage
flag is set to false (see Multi-Version APIs further down). For the other flags :served
and :deprecated
such as the field :deprecatedWarning
, assumptions are made.
An operator run in production might want to define at least a :schema
, probably :additionalPrinterColumns
and maybe :subresources
. All these fields such as flags can be overriden in manifest/0
.
defmodule YourOperator.API.V1Alpha1.Widget do
use Bonny.API.Version
@impl true
def manifest() do
struct!(
defaults(),
storage: true,
schema: %{
openAPIV3Schema: %{
type: :object,
properties: %{
spec: %{
type: :object,
properties: %{
foos_requested: %{type: :integer}
}
},
status: %{
type: :object,
properties: %{
foos_implemented: %{type: :integer}
}
}
}
}
},
additionalPrinterColumns: [
%{
name: "requested_foos",
type: :integer,
description: "Number of foos requested",
jsonPath: ".spec.foos_requested"
},
%{
name: "implemented_foos",
type: :integer,
description: "Number of foos implemented",
jsonPath: ".status.foos_implemented"
}
],
subresources: %{
status: %{}
}
)
end
end
YourOperator.API.V1Alpha1.Widget.manifest()
Note that the usage of Bonny.API.Version
imports the helper add_observed_generation_status/1
to your module. Use it to add the fields to your manifest required by the Bonny.Pluggable.SkipObservedGeneartions
pluggable step. See the controllers guide for further information on this.
multi-version-apis
Multi-Version APIs
There is some documentation about multi-version apis for the kubebuilder. Obviousely, that one is for creating a kubernetes controller in Go, but it's a good read nontheless. This is how it begins:
Most projects start out with an alpha API that changes release to release. However, eventually, most projects will need to move to a more stable API. Once your API is stable though, you can't make breaking changes to it. That's where API versions come into play.
conversion
Conversion
Webhooks are currently not implemented in Bonny. There is the module bonny_plug
that can be used to implement them. There might be a neater integration of the two in the future, though.
Bonny already lets you define a version as the hub
. The only thing this does right now is it sets the storage
flag to true
in the generated manifest.
defmodule YourOperator.API.V1.CronTab do
use Bonny.API.Version,
hub: true
@impl Bonny.API.Version
# storage: true not needed here.
def manifest(), do: defaults(name: "v1")
end
YourOperator.API.V1.CronTab.manifest()
storage-versions
Storage Versions
Even if you define multiple versions for the same resource, Kubernetes is only going to store the data in one version - the storage version.
Note that multiple versions may exist in storage if they were written before the storage version changes -- changing the storage version only affects how objects are created/updated after the change.
As mentioned above, there are to ways to define the storage version, by passing hub: true
as an option to use Bonny.API.Version
or by setting storage: true
in manifest/0
.