mirror of
https://github.com/arangodb/kube-arangodb.git
synced 2024-12-14 11:57:37 +00:00
[Feature] Helm Client Extension (#1746)
This commit is contained in:
parent
b8d34960c2
commit
ac108d279c
8 changed files with 561 additions and 56 deletions
|
@ -3,6 +3,7 @@
|
|||
## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A)
|
||||
- (Maintenance) Kubernetes 1.31.1 libraries
|
||||
- (Feature) Helm Client Support
|
||||
- (Feature) Helm Client Extension
|
||||
|
||||
## [1.2.43](https://github.com/arangodb/kube-arangodb/tree/1.2.43) (2024-10-14)
|
||||
- (Feature) ArangoRoute CRD
|
||||
|
|
|
@ -22,8 +22,20 @@ package helm
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
apiErrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/discovery/cached/memory"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/kclient"
|
||||
|
@ -43,9 +55,16 @@ func NewClient(cfg Configuration) (Client, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
dClient, err := discovery.NewDiscoveryClientForConfig(cfg.Client.Config())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &client{
|
||||
cfg: cfg,
|
||||
helm: &helm,
|
||||
cfg: cfg,
|
||||
helm: &helm,
|
||||
discovery: memory.NewMemCacheClient(dClient),
|
||||
restClients: map[schema.GroupVersion]rest.Interface{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -55,30 +74,45 @@ type Client interface {
|
|||
|
||||
Alive(ctx context.Context) error
|
||||
|
||||
Invalidate()
|
||||
DiscoverKubernetesApiVersions(gv schema.GroupVersion) (ApiVersions, error)
|
||||
DiscoverKubernetesApiVersionKind(gvk schema.GroupVersionKind) (*meta.APIResource, error)
|
||||
NativeGet(ctx context.Context, reqs ...Resource) ([]ResourceObject, error)
|
||||
|
||||
StatusObjects(ctx context.Context, name string, mods ...util.Mod[action.Status]) (*Release, []ResourceObject, error)
|
||||
|
||||
Status(ctx context.Context, name string, mods ...util.Mod[action.Status]) (*Release, error)
|
||||
List(ctx context.Context, mods ...util.Mod[action.List]) ([]Release, error)
|
||||
Install(ctx context.Context, chart Chart, values Values, mods ...util.Mod[action.Install]) (*Release, error)
|
||||
Upgrade(ctx context.Context, name string, chart Chart, values Values, mods ...util.Mod[action.Upgrade]) (*Release, error)
|
||||
Upgrade(ctx context.Context, name string, chart Chart, values Values, mods ...util.Mod[action.Upgrade]) (*UpgradeResponse, error)
|
||||
Uninstall(ctx context.Context, name string, mods ...util.Mod[action.Uninstall]) (*UninstallRelease, error)
|
||||
Test(ctx context.Context, name string, mods ...util.Mod[action.ReleaseTesting]) (*Release, error)
|
||||
}
|
||||
|
||||
type client struct {
|
||||
lock sync.Mutex
|
||||
|
||||
cfg Configuration
|
||||
helm *action.Configuration
|
||||
|
||||
restClients map[schema.GroupVersion]rest.Interface
|
||||
|
||||
discovery discovery.CachedDiscoveryInterface
|
||||
}
|
||||
|
||||
func (c client) Namespace() string {
|
||||
func (c *client) Namespace() string {
|
||||
return c.cfg.Namespace
|
||||
}
|
||||
|
||||
func (c client) Client() kclient.Client {
|
||||
func (c *client) Client() kclient.Client {
|
||||
return c.cfg.Client
|
||||
}
|
||||
|
||||
func (c client) Status(ctx context.Context, name string, mods ...util.Mod[action.Status]) (*Release, error) {
|
||||
func (c *client) Status(ctx context.Context, name string, mods ...util.Mod[action.Status]) (*Release, error) {
|
||||
act := action.NewStatus(c.helm)
|
||||
|
||||
act.ShowResources = true
|
||||
|
||||
util.ApplyMods(act, mods...)
|
||||
|
||||
result, err := act.Run(name)
|
||||
|
@ -89,12 +123,14 @@ func (c client) Status(ctx context.Context, name string, mods ...util.Mod[action
|
|||
return nil, err
|
||||
}
|
||||
|
||||
r := fromHelmRelease(result)
|
||||
|
||||
return &r, nil
|
||||
if r, err := fromHelmRelease(result); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return &r, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c client) Uninstall(ctx context.Context, name string, mods ...util.Mod[action.Uninstall]) (*UninstallRelease, error) {
|
||||
func (c *client) Uninstall(ctx context.Context, name string, mods ...util.Mod[action.Uninstall]) (*UninstallRelease, error) {
|
||||
act := action.NewUninstall(c.helm)
|
||||
|
||||
util.ApplyMods(act, mods...)
|
||||
|
@ -107,12 +143,17 @@ func (c client) Uninstall(ctx context.Context, name string, mods ...util.Mod[act
|
|||
var res UninstallRelease
|
||||
|
||||
res.Info = result.Info
|
||||
res.Release = fromHelmRelease(result.Release)
|
||||
|
||||
if r, err := fromHelmRelease(result.Release); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
res.Release = r
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (c client) Test(ctx context.Context, name string, mods ...util.Mod[action.ReleaseTesting]) (*Release, error) {
|
||||
func (c *client) Test(ctx context.Context, name string, mods ...util.Mod[action.ReleaseTesting]) (*Release, error) {
|
||||
act := action.NewReleaseTesting(c.helm)
|
||||
|
||||
util.ApplyMods(act, mods...)
|
||||
|
@ -122,12 +163,14 @@ func (c client) Test(ctx context.Context, name string, mods ...util.Mod[action.R
|
|||
return nil, err
|
||||
}
|
||||
|
||||
r := fromHelmRelease(result)
|
||||
|
||||
return &r, nil
|
||||
if r, err := fromHelmRelease(result); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return &r, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c client) Install(ctx context.Context, chart Chart, values Values, mods ...util.Mod[action.Install]) (*Release, error) {
|
||||
func (c *client) Install(ctx context.Context, chart Chart, values Values, mods ...util.Mod[action.Install]) (*Release, error) {
|
||||
act := action.NewInstall(c.helm)
|
||||
|
||||
util.ApplyMods(act, mods...)
|
||||
|
@ -147,16 +190,23 @@ func (c client) Install(ctx context.Context, chart Chart, values Values, mods ..
|
|||
return nil, err
|
||||
}
|
||||
|
||||
r := fromHelmRelease(result)
|
||||
|
||||
return &r, nil
|
||||
if r, err := fromHelmRelease(result); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return &r, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c client) Upgrade(ctx context.Context, name string, chart Chart, values Values, mods ...util.Mod[action.Upgrade]) (*Release, error) {
|
||||
func (c *client) Upgrade(ctx context.Context, name string, chart Chart, values Values, mods ...util.Mod[action.Upgrade]) (*UpgradeResponse, error) {
|
||||
act := action.NewUpgrade(c.helm)
|
||||
|
||||
util.ApplyMods(act, mods...)
|
||||
|
||||
release, err := c.Status(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chartData, err := chart.Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -167,17 +217,41 @@ func (c client) Upgrade(ctx context.Context, name string, chart Chart, values Va
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if release != nil {
|
||||
if meta := chartData.Metadata; meta != nil {
|
||||
if release.GetChart().GetMetadata().GetVersion() == meta.Version {
|
||||
// We are on the same version
|
||||
if release.Values.Equals(values) {
|
||||
// We provide same values
|
||||
return &UpgradeResponse{
|
||||
Before: release,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result, err := act.Run(name, chartData, valuesData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := fromHelmRelease(result)
|
||||
|
||||
return &r, nil
|
||||
if r, err := fromHelmRelease(result); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
if release == nil {
|
||||
return &UpgradeResponse{
|
||||
After: &r,
|
||||
}, nil
|
||||
}
|
||||
return &UpgradeResponse{
|
||||
Before: release,
|
||||
After: &r,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c client) Alive(ctx context.Context) error {
|
||||
func (c *client) Alive(ctx context.Context) error {
|
||||
act := action.NewList(c.helm)
|
||||
|
||||
_, err := act.Run()
|
||||
|
@ -188,7 +262,7 @@ func (c client) Alive(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c client) List(ctx context.Context, mods ...util.Mod[action.List]) ([]Release, error) {
|
||||
func (c *client) List(ctx context.Context, mods ...util.Mod[action.List]) ([]Release, error) {
|
||||
act := action.NewList(c.helm)
|
||||
|
||||
util.ApplyMods(act, mods...)
|
||||
|
@ -201,8 +275,157 @@ func (c client) List(ctx context.Context, mods ...util.Mod[action.List]) ([]Rele
|
|||
releases := make([]Release, len(result))
|
||||
|
||||
for id := range result {
|
||||
releases[id] = fromHelmRelease(result[id])
|
||||
|
||||
if r, err := fromHelmRelease(result[id]); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
releases[id] = r
|
||||
}
|
||||
}
|
||||
|
||||
return releases, nil
|
||||
}
|
||||
|
||||
func (c *client) Invalidate() {
|
||||
c.discovery.Invalidate()
|
||||
}
|
||||
|
||||
func (c *client) DiscoverKubernetesApiVersions(gv schema.GroupVersion) (ApiVersions, error) {
|
||||
resp, err := c.discovery.ServerResourcesForGroupVersion(gv.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := make(ApiVersions, len(resp.APIResources))
|
||||
|
||||
for _, v := range resp.APIResources {
|
||||
v.Group = gv.Group
|
||||
v.Version = gv.Version
|
||||
r[schema.GroupVersionKind{
|
||||
Group: v.Group,
|
||||
Version: v.Version,
|
||||
Kind: v.Kind,
|
||||
}] = v
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (c *client) DiscoverKubernetesApiVersionKind(gvk schema.GroupVersionKind) (*meta.APIResource, error) {
|
||||
v, err := c.DiscoverKubernetesApiVersions(schema.GroupVersion{
|
||||
Group: gvk.Group,
|
||||
Version: gvk.Version,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if z, ok := v[gvk]; ok {
|
||||
return &z, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *client) restClientForApiVersion(gv schema.GroupVersion) (rest.Interface, error) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
if v, ok := c.restClients[gv]; ok {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
configShallowCopy := *c.cfg.Client.Config()
|
||||
if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
|
||||
if configShallowCopy.Burst <= 0 {
|
||||
return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
|
||||
}
|
||||
configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
|
||||
}
|
||||
|
||||
configShallowCopy.GroupVersion = &schema.GroupVersion{
|
||||
Group: gv.Group,
|
||||
Version: gv.Version,
|
||||
}
|
||||
configShallowCopy.APIPath = "/api"
|
||||
configShallowCopy.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
|
||||
|
||||
if configShallowCopy.UserAgent == "" {
|
||||
configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
}
|
||||
|
||||
rc, err := rest.RESTClientFor(&configShallowCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.restClients[gv] = rc
|
||||
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
func (c *client) NativeGet(ctx context.Context, reqs ...Resource) ([]ResourceObject, error) {
|
||||
if len(reqs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
res := make([]ResourceObject, len(reqs))
|
||||
for id := range reqs {
|
||||
res[id].Resource = reqs[id]
|
||||
|
||||
gvk, err := c.DiscoverKubernetesApiVersionKind(reqs[id].GroupVersionKind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gvk == nil {
|
||||
// NotFound
|
||||
continue
|
||||
}
|
||||
|
||||
client, err := c.restClientForApiVersion(schema.GroupVersion{
|
||||
Group: gvk.Group,
|
||||
Version: gvk.Version,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := client.Get().Resource(gvk.Name).
|
||||
NamespaceIfScoped(reqs[id].Namespace, gvk.Namespaced).
|
||||
Name(reqs[id].Name).DoRaw(ctx)
|
||||
if err != nil {
|
||||
var e *apiErrors.StatusError
|
||||
if errors.As(err, &e) {
|
||||
if e.Status().Code == http.StatusNotFound {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res[id].Object = &ResourceObjectData{
|
||||
Data: resp,
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (c *client) StatusObjects(ctx context.Context, name string, mods ...util.Mod[action.Status]) (*Release, []ResourceObject, error) {
|
||||
s, err := c.Status(ctx, name, mods...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if s == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
manifests, err := c.NativeGet(ctx, s.Info.Resources...)
|
||||
if err != nil {
|
||||
return s, nil, err
|
||||
}
|
||||
|
||||
return s, manifests, nil
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/require"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
core "k8s.io/api/core/v1"
|
||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/tests"
|
||||
|
@ -33,7 +34,10 @@ import (
|
|||
|
||||
func cleanup(t *testing.T, c Client) func() {
|
||||
t.Run("Cleanup Pre", func(t *testing.T) {
|
||||
items, err := c.List(context.Background())
|
||||
items, err := c.List(context.Background(), func(in *action.List) {
|
||||
in.All = true
|
||||
in.StateMask = action.ListDeployed | action.ListUninstalled | action.ListUninstalling | action.ListPendingInstall | action.ListPendingUpgrade | action.ListPendingRollback | action.ListSuperseded | action.ListFailed | action.ListUnknown
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, item := range items {
|
||||
|
@ -46,7 +50,10 @@ func cleanup(t *testing.T, c Client) func() {
|
|||
|
||||
return func() {
|
||||
t.Run("Cleanup Post", func(t *testing.T) {
|
||||
items, err := c.List(context.Background())
|
||||
items, err := c.List(context.Background(), func(in *action.List) {
|
||||
in.All = true
|
||||
in.StateMask = action.ListDeployed | action.ListUninstalled | action.ListUninstalling | action.ListPendingInstall | action.ListPendingUpgrade | action.ListPendingRollback | action.ListSuperseded | action.ListFailed | action.ListUnknown
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, item := range items {
|
||||
|
@ -82,14 +89,37 @@ func Test_Connection(t *testing.T) {
|
|||
require.NotNil(t, resp)
|
||||
})
|
||||
|
||||
t.Run("Upgrade", func(t *testing.T) {
|
||||
resp, err := c.Upgrade(context.Background(), "test", example_1_0_0, nil, func(in *action.Upgrade) {
|
||||
in.Install = true
|
||||
in.Wait = true
|
||||
})
|
||||
t.Run("Upgrade With No change", func(t *testing.T) {
|
||||
resp, err := c.Upgrade(context.Background(), "test", example_1_0_0, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, resp)
|
||||
require.NotNil(t, resp.Before)
|
||||
require.Nil(t, resp.After)
|
||||
})
|
||||
|
||||
t.Run("Upgrade With change", func(t *testing.T) {
|
||||
resp, err := c.Upgrade(context.Background(), "test", example_1_0_0, Values(`{"A":"X"}`))
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, resp)
|
||||
require.NotNil(t, resp.Before)
|
||||
require.NotNil(t, resp.After)
|
||||
})
|
||||
|
||||
t.Run("Get all manifests", func(t *testing.T) {
|
||||
resp, mans, err := c.StatusObjects(context.Background(), "test")
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, resp)
|
||||
require.NotNil(t, mans)
|
||||
require.Len(t, mans, 1)
|
||||
|
||||
var d core.ConfigMap
|
||||
|
||||
require.NoError(t, mans[0].Object.Unmarshal(&d))
|
||||
|
||||
t.Logf(string(d.GetUID()))
|
||||
})
|
||||
|
||||
t.Run("Test", func(t *testing.T) {
|
||||
|
|
|
@ -21,51 +21,165 @@
|
|||
package helm
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/release"
|
||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||
)
|
||||
|
||||
func fromHelmRelease(in *release.Release) Release {
|
||||
func fromHelmRelease(in *release.Release) (Release, error) {
|
||||
var r Release
|
||||
|
||||
if in != nil {
|
||||
r.Name = in.Name
|
||||
r.Version = in.Version
|
||||
r.Namespace = in.Namespace
|
||||
r.Labels = in.Labels
|
||||
|
||||
r.Info = fromHelmReleaseInfo(in.Info)
|
||||
if in == nil {
|
||||
return Release{}, errors.Errorf("Nil release not allowed")
|
||||
}
|
||||
|
||||
return r
|
||||
r.Name = in.Name
|
||||
r.Version = in.Version
|
||||
r.Namespace = in.Namespace
|
||||
r.Labels = in.Labels
|
||||
|
||||
r.Chart = fromHelmReleaseChart(in.Chart)
|
||||
|
||||
if d, err := NewValues(in.Config); err != nil {
|
||||
return Release{}, nil
|
||||
} else {
|
||||
r.Values = d
|
||||
}
|
||||
|
||||
if i, err := fromHelmReleaseInfo(in.Info); err != nil {
|
||||
return Release{}, err
|
||||
} else {
|
||||
r.Info = i
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func fromHelmReleaseInfo(in *release.Info) ReleaseInfo {
|
||||
var r ReleaseInfo
|
||||
|
||||
if in != nil {
|
||||
r.FirstDeployed = in.FirstDeployed.Time
|
||||
r.LastDeployed = in.LastDeployed.Time
|
||||
r.Deleted = in.Deleted.Time
|
||||
r.Description = in.Description
|
||||
r.Status = in.Status
|
||||
r.Notes = in.Notes
|
||||
func fromHelmReleaseChart(in *chart.Chart) *ReleaseChart {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return r
|
||||
var r ReleaseChart
|
||||
|
||||
r.Metadata = fromHelmReleaseChartMetadata(in.Metadata)
|
||||
|
||||
return &r
|
||||
}
|
||||
|
||||
func fromHelmReleaseChartMetadata(in *chart.Metadata) *ReleaseChartMetadata {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var r ReleaseChartMetadata
|
||||
|
||||
r.Version = in.Version
|
||||
|
||||
return &r
|
||||
}
|
||||
|
||||
func fromHelmReleaseInfo(in *release.Info) (ReleaseInfo, error) {
|
||||
var r ReleaseInfo
|
||||
|
||||
if in == nil {
|
||||
return ReleaseInfo{}, errors.Errorf("Nil release info not allowed")
|
||||
}
|
||||
|
||||
r.FirstDeployed = in.FirstDeployed.Time
|
||||
r.LastDeployed = in.LastDeployed.Time
|
||||
r.Deleted = in.Deleted.Time
|
||||
r.Description = in.Description
|
||||
r.Status = in.Status
|
||||
r.Notes = in.Notes
|
||||
|
||||
if m, err := fromHelmReleaseInfoResources(in.Resources); err != nil {
|
||||
return ReleaseInfo{}, err
|
||||
} else {
|
||||
r.Resources = m
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func fromHelmReleaseInfoResources(in map[string][]runtime.Object) (Resources, error) {
|
||||
if len(in) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var r Resources
|
||||
|
||||
for _, v := range in {
|
||||
for _, obj := range v {
|
||||
d, err := util.JSONRemarshal[runtime.Object, internalResourceObject](obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r = append(r, Resource{
|
||||
GroupVersionKind: schema.FromAPIVersionAndKind(d.APIVersion, d.Kind),
|
||||
Name: d.GetName(),
|
||||
Namespace: d.GetNamespace(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
type Release struct {
|
||||
Name string
|
||||
|
||||
Info ReleaseInfo
|
||||
Info ReleaseInfo
|
||||
Chart *ReleaseChart
|
||||
|
||||
Values Values
|
||||
|
||||
Version int
|
||||
Namespace string
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
func (r *Release) GetChart() *ReleaseChart {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return r.Chart
|
||||
}
|
||||
|
||||
type ReleaseChart struct {
|
||||
Metadata *ReleaseChartMetadata
|
||||
}
|
||||
|
||||
func (r *ReleaseChart) GetMetadata() *ReleaseChartMetadata {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return r.Metadata
|
||||
}
|
||||
|
||||
type ReleaseChartMetadata struct {
|
||||
Version string
|
||||
}
|
||||
|
||||
func (r *ReleaseChartMetadata) GetVersion() string {
|
||||
if r == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return r.Version
|
||||
}
|
||||
|
||||
type ReleaseInfo struct {
|
||||
FirstDeployed time.Time
|
||||
LastDeployed time.Time
|
||||
|
@ -73,9 +187,46 @@ type ReleaseInfo struct {
|
|||
Description string
|
||||
Status release.Status
|
||||
Notes string
|
||||
Resources Resources
|
||||
}
|
||||
|
||||
type Resources []Resource
|
||||
|
||||
type internalResourceObject struct {
|
||||
meta.TypeMeta `json:",inline"`
|
||||
meta.ObjectMeta `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type Resource struct {
|
||||
schema.GroupVersionKind
|
||||
Name, Namespace string
|
||||
}
|
||||
|
||||
type ResourceObject struct {
|
||||
Resource
|
||||
|
||||
Object *ResourceObjectData
|
||||
}
|
||||
|
||||
func (r *ResourceObjectData) Unmarshal(obj any) error {
|
||||
if r == nil {
|
||||
return errors.Errorf("Object not returned")
|
||||
}
|
||||
|
||||
return json.Unmarshal(r.Data, &obj)
|
||||
}
|
||||
|
||||
type ResourceObjectData struct {
|
||||
Data []byte
|
||||
}
|
||||
|
||||
type UninstallRelease struct {
|
||||
Release Release
|
||||
Info string
|
||||
}
|
||||
|
||||
type UpgradeResponse struct {
|
||||
Before, After *Release
|
||||
}
|
||||
|
||||
type ApiVersions map[schema.GroupVersionKind]meta.APIResource
|
||||
|
|
|
@ -20,7 +20,11 @@
|
|||
|
||||
package helm
|
||||
|
||||
import "encoding/json"
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||
)
|
||||
|
||||
func NewValues(in any) (Values, error) {
|
||||
data, err := json.Marshal(in)
|
||||
|
@ -33,9 +37,41 @@ func NewValues(in any) (Values, error) {
|
|||
|
||||
type Values []byte
|
||||
|
||||
func (v Values) Equals(other Values) bool {
|
||||
a, err := v.Marshal()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(a) == 0 {
|
||||
a = nil
|
||||
}
|
||||
|
||||
ad, err := json.Marshal(a)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
b, err := other.Marshal()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(b) == 0 {
|
||||
b = nil
|
||||
}
|
||||
|
||||
bd, err := json.Marshal(b)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return util.SHA256(ad) == util.SHA256(bd)
|
||||
}
|
||||
|
||||
func (v Values) Marshal() (map[string]interface{}, error) {
|
||||
if len(v) == 0 {
|
||||
return nil, nil
|
||||
return map[string]interface{}{}, nil
|
||||
}
|
||||
|
||||
var q map[string]interface{}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
|
@ -172,3 +173,18 @@ func ApplyMods[T any](in *T, mods ...Mod[T]) {
|
|||
mod(in)
|
||||
}
|
||||
}
|
||||
|
||||
func JSONRemarshal[A, B any](in A) (B, error) {
|
||||
d, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
return Default[B](), err
|
||||
}
|
||||
|
||||
var o B
|
||||
|
||||
if err := json.Unmarshal(d, &o); err != nil {
|
||||
return Default[B](), err
|
||||
}
|
||||
|
||||
return o, nil
|
||||
}
|
||||
|
|
|
@ -185,6 +185,12 @@ func CreateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
|
|||
vl := *v
|
||||
_, err := arango.BackupV1().ArangoBackups(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
case **backupApi.ArangoBackupPolicy:
|
||||
require.NotNil(t, v)
|
||||
|
||||
vl := *v
|
||||
_, err := arango.BackupV1().ArangoBackupPolicies(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
case **mlApi.ArangoMLExtension:
|
||||
require.NotNil(t, v)
|
||||
|
||||
|
@ -386,6 +392,12 @@ func UpdateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
|
|||
vl := *v
|
||||
_, err := arango.BackupV1().ArangoBackups(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
case **backupApi.ArangoBackupPolicy:
|
||||
require.NotNil(t, v)
|
||||
|
||||
vl := *v
|
||||
_, err := arango.BackupV1().ArangoBackupPolicies(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
case **mlApi.ArangoMLExtension:
|
||||
require.NotNil(t, v)
|
||||
|
||||
|
@ -572,6 +584,11 @@ func DeleteObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
|
|||
|
||||
vl := *v
|
||||
require.NoError(t, arango.BackupV1().ArangoBackups(vl.GetNamespace()).Delete(context.Background(), vl.GetName(), meta.DeleteOptions{}))
|
||||
case **backupApi.ArangoBackupPolicy:
|
||||
require.NotNil(t, v)
|
||||
|
||||
vl := *v
|
||||
require.NoError(t, arango.BackupV1().ArangoBackupPolicies(vl.GetNamespace()).Delete(context.Background(), vl.GetName(), meta.DeleteOptions{}))
|
||||
case **mlApi.ArangoMLExtension:
|
||||
require.NotNil(t, v)
|
||||
|
||||
|
@ -868,6 +885,21 @@ func RefreshObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientS
|
|||
} else {
|
||||
*v = vn
|
||||
}
|
||||
case **backupApi.ArangoBackupPolicy:
|
||||
require.NotNil(t, v)
|
||||
|
||||
vl := *v
|
||||
|
||||
vn, err := arango.BackupV1().ArangoBackupPolicies(vl.GetNamespace()).Get(context.Background(), vl.GetName(), meta.GetOptions{})
|
||||
if err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
*v = nil
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
} else {
|
||||
*v = vn
|
||||
}
|
||||
case **mlApi.ArangoMLExtension:
|
||||
require.NotNil(t, v)
|
||||
|
||||
|
@ -1238,6 +1270,14 @@ func SetMetaBasedOnType(t *testing.T, object meta.Object) {
|
|||
backup.ArangoBackupResourcePlural,
|
||||
object.GetNamespace(),
|
||||
object.GetName()))
|
||||
case *backupApi.ArangoBackupPolicy:
|
||||
v.Kind = backup.ArangoBackupPolicyResourceKind
|
||||
v.APIVersion = backupApi.SchemeGroupVersion.String()
|
||||
v.SetSelfLink(fmt.Sprintf("/api/%s/%s/%s/%s",
|
||||
backupApi.SchemeGroupVersion.String(),
|
||||
backup.ArangoBackupPolicyResourcePlural,
|
||||
object.GetNamespace(),
|
||||
object.GetName()))
|
||||
case *mlApi.ArangoMLExtension:
|
||||
v.Kind = ml.ArangoMLExtensionResourceKind
|
||||
v.APIVersion = mlApi.SchemeGroupVersion.String()
|
||||
|
@ -1397,6 +1437,7 @@ func NewMetaObject[T meta.Object](t *testing.T, namespace, name string, mods ...
|
|||
}
|
||||
obj.SetName(name)
|
||||
obj.SetUID(uuid.NewUUID())
|
||||
obj.SetCreationTimestamp(meta.Now())
|
||||
|
||||
SetMetaBasedOnType(t, obj)
|
||||
|
||||
|
@ -1494,6 +1535,12 @@ func GVK(t *testing.T, object meta.Object) schema.GroupVersionKind {
|
|||
Version: backupApi.ArangoBackupVersion,
|
||||
Kind: backup.ArangoBackupResourceKind,
|
||||
}
|
||||
case *backupApi.ArangoBackupPolicy:
|
||||
return schema.GroupVersionKind{
|
||||
Group: backup.ArangoBackupGroupName,
|
||||
Version: backupApi.ArangoBackupVersion,
|
||||
Kind: backup.ArangoBackupPolicyResourceKind,
|
||||
}
|
||||
case *mlApi.ArangoMLExtension:
|
||||
return schema.GroupVersionKind{
|
||||
Group: ml.ArangoMLGroupName,
|
||||
|
|
|
@ -84,6 +84,7 @@ func Test_NewMetaObject(t *testing.T) {
|
|||
NewMetaObjectRun[*api.ArangoDeployment](t)
|
||||
NewMetaObjectRun[*api.ArangoClusterSynchronization](t)
|
||||
NewMetaObjectRun[*backupApi.ArangoBackup](t)
|
||||
NewMetaObjectRun[*backupApi.ArangoBackupPolicy](t)
|
||||
NewMetaObjectRun[*mlApi.ArangoMLExtension](t)
|
||||
NewMetaObjectRun[*mlApi.ArangoMLStorage](t)
|
||||
NewMetaObjectRun[*mlApiv1alpha1.ArangoMLExtension](t)
|
||||
|
|
Loading…
Reference in a new issue