Xe's Kubernetes custom resources
1package v1
2
3import (
4 "encoding/json"
5 "fmt"
6
7 "k8s.io/apimachinery/pkg/api/resource"
8 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9 "tangled.org/xeiaso.net/crds/internal"
10)
11
12const (
13 APIVersion = "db.x.within.website/v1"
14 KindApp = "Postgres"
15)
16
17// App represents a backend application with opinionated defaults.
18type Postgres struct {
19 metav1.TypeMeta `json:",inline"`
20 metav1.ObjectMeta `json:"metadata,omitempty"`
21 Spec PostgresSpec `json:"spec"`
22}
23
24type PostgresSpec struct {
25 Env []internal.EnvVar `json:"env,omitempty" yaml:"env,omitempty"`
26 Healthcheck bool `json:"healthcheck,omitempty" yaml:"healthcheck,omitempty"`
27
28 Storage Storage `json:"storage,omitempty" yaml:"storage,omitempty"`
29 RuntimeClass *string `json:"runtimeClass,omitempty"`
30 Secrets []Secret `json:"secrets,omitempty" yaml:"secrets,omitempty"`
31}
32
33type Secret struct {
34 Name string `json:"name" yaml:"name"`
35 ItemPath string `json:"itemPath" yaml:"itemPath"`
36}
37
38func (s *Secret) UnmarshalJSON(data []byte) error {
39 type SecretAlt Secret
40 var alt SecretAlt
41 if err := json.Unmarshal(data, &alt); err != nil {
42 return err
43 }
44 if alt.ItemPath == "" {
45 return fmt.Errorf("itemPath is required")
46 }
47 *s = Secret(alt)
48 return nil
49}
50
51type Storage struct {
52 Size string `json:"size" yaml:"size"`
53 StorageClass *string `json:"storageClass,omitempty" yaml:"storageClass,omitempty"`
54}
55
56func (s *Storage) UnmarshalJSON(data []byte) error {
57 type StorageAlt Storage
58 var alt StorageAlt
59 if err := json.Unmarshal(data, &alt); err != nil {
60 return err
61 }
62 if alt.Size == "" {
63 return fmt.Errorf("size is required")
64 }
65
66 _, err := resource.ParseQuantity(alt.Size)
67 if err != nil {
68 return fmt.Errorf("invalid size: %v", err)
69 }
70
71 *s = Storage(alt)
72 return nil
73}
74
75// Custom Marshalling Logic so that users do not need to explicity fill out the Kind and ApiVersion.
76func (v Postgres) MarshalJSON() ([]byte, error) {
77 v.Kind = KindApp
78 v.APIVersion = APIVersion
79
80 type PostgresAlt Postgres
81 return json.Marshal(PostgresAlt(v))
82}
83
84// Custom Unmarshalling to raise an error if the ApiVersion or Kind does not match.
85func (v *Postgres) UnmarshalJSON(data []byte) error {
86 type PostgresAlt Postgres
87 var alt PostgresAlt
88 if err := json.Unmarshal(data, &alt); err != nil {
89 return err
90 }
91 if alt.APIVersion != APIVersion {
92 return fmt.Errorf("unexpected api version: expected %s but got %s", APIVersion, alt.APIVersion)
93 }
94 if alt.Kind != KindApp {
95 return fmt.Errorf("unexpected kind: expected %s but got %s", KindApp, alt.Kind)
96 }
97 *v = Postgres(alt)
98 return nil
99}