Skip to content
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
1 change: 1 addition & 0 deletions create/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type Cmd struct {
Postgres postgresCmd `cmd:"" group:"storage.nine.ch" name:"postgres" help:"Create a new PostgreSQL instance."`
PostgresDatabase postgresDatabaseCmd `cmd:"" group:"storage.nine.ch" name:"postgresdatabase" help:"Create a new PostgreSQL database."`
KeyValueStore keyValueStoreCmd `cmd:"" group:"storage.nine.ch" name:"keyvaluestore" aliases:"kvs" help:"Create a new KeyValueStore instance."`
OpenSearch openSearchCmd `cmd:"" group:"storage.nine.ch" name:"opensearch" aliases:"os" help:"Create a new OpenSearch cluster."`
CloudVirtualMachine cloudVMCmd `cmd:"" group:"infrastructure.nine.ch" name:"cloudvirtualmachine" aliases:"cloudvm" help:"Create a new CloudVM."`
ServiceConnection serviceConnectionCmd `cmd:"" group:"networking.nine.ch" name:"serviceconnection" aliases:"sc" help:"Create a new ServiceConnection."`
}
Expand Down
6 changes: 2 additions & 4 deletions create/keyvaluestore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package create

import (
"context"
"reflect"
"testing"
"time"

"github.com/google/go-cmp/cmp"
meta "github.com/ninech/apis/meta/v1alpha1"
storage "github.com/ninech/apis/storage/v1alpha1"
"github.com/ninech/nctl/api"
Expand Down Expand Up @@ -91,9 +91,7 @@ func TestKeyValueStore(t *testing.T) {
return
}

if !reflect.DeepEqual(created.Spec.ForProvider, tt.want) {
t.Fatalf("expected KeyValueStore.Spec.ForProvider = %v, got: %v", created.Spec.ForProvider, tt.want)
}
require.True(t, cmp.Equal(tt.want, created.Spec.ForProvider))
})
}
}
77 changes: 77 additions & 0 deletions create/opensearch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package create

import (
"context"

runtimev1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
infra "github.com/ninech/apis/infrastructure/v1alpha1"
meta "github.com/ninech/apis/meta/v1alpha1"
storage "github.com/ninech/apis/storage/v1alpha1"
"github.com/ninech/nctl/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
)

type openSearchCmd struct {
resourceCmd
Location string `help:"Location where the OpenSearch cluster is created." placeholder:"nine-es34"`
MachineType string `help:"MachineType specifies the type of machine to use for the OpenSearch cluster." placeholder:"nine-search-s"`
ClusterType storage.OpenSearchClusterType `help:"ClusterType specifies the type of OpenSearch cluster to create. Options: single, multi" placeholder:"single"`
AllowedCidrs []meta.IPv4CIDR `help:"AllowedCIDRs specify the allowed IP addresses, connecting to the cluster." placeholder:"203.0.113.1/32"`
}

func (cmd *openSearchCmd) Run(ctx context.Context, client *api.Client) error {
openSearch, err := cmd.newOpenSearch(client.Project)
if err != nil {
return err
}

c := newCreator(client, openSearch, "opensearch")
ctx, cancel := context.WithTimeout(ctx, cmd.WaitTimeout)
defer cancel()

if err := c.createResource(ctx); err != nil {
return err
}

if !cmd.Wait {
return nil
}

return c.wait(ctx, waitStage{
objectList: &storage.OpenSearchList{},
onResult: func(event watch.Event) (bool, error) {
if c, ok := event.Object.(*storage.OpenSearch); ok {
return isAvailable(c), nil
}
return false, nil
},
})
}

func (cmd *openSearchCmd) newOpenSearch(namespace string) (*storage.OpenSearch, error) {
name := getName(cmd.Name)

openSearch := &storage.OpenSearch{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Spec: storage.OpenSearchSpec{
ResourceSpec: runtimev1.ResourceSpec{
WriteConnectionSecretToReference: &runtimev1.SecretReference{
Name: "opensearch-" + name,
Namespace: namespace,
},
},
ForProvider: storage.OpenSearchParameters{
Location: meta.LocationName(cmd.Location),
MachineType: infra.NewMachineType(cmd.MachineType),
ClusterType: cmd.ClusterType,
AllowedCIDRs: cmd.AllowedCidrs,
},
},
}

return openSearch, nil
}
85 changes: 85 additions & 0 deletions create/opensearch_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package create

import (
"context"
"testing"
"time"

"github.com/google/go-cmp/cmp"
infra "github.com/ninech/apis/infrastructure/v1alpha1"
meta "github.com/ninech/apis/meta/v1alpha1"
storage "github.com/ninech/apis/storage/v1alpha1"
"github.com/ninech/nctl/api"
"github.com/ninech/nctl/internal/test"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestOpenSearch(t *testing.T) {
ctx := context.Background()
tests := []struct {
name string
create openSearchCmd
want storage.OpenSearchParameters
wantErr bool
}{
{
name: "default",
want: storage.OpenSearchParameters{},
},
{
name: "customLocation",
create: openSearchCmd{Location: "nine-cz41"},
want: storage.OpenSearchParameters{
Location: meta.LocationNineCZ41,
},
},
{
name: "multiClusterType",
create: openSearchCmd{ClusterType: storage.OpenSearchClusterTypeMulti},
want: storage.OpenSearchParameters{
ClusterType: storage.OpenSearchClusterTypeMulti,
},
},
{
name: "customMachineType",
create: openSearchCmd{MachineType: infra.MachineTypeNineSearchL.String()},
want: storage.OpenSearchParameters{
MachineType: infra.MachineTypeNineSearchL,
},
},
{
name: "allowedCIDRs",
create: openSearchCmd{
AllowedCidrs: []meta.IPv4CIDR{meta.IPv4CIDR("192.168.1.0/24")},
},
want: storage.OpenSearchParameters{
AllowedCIDRs: []meta.IPv4CIDR{meta.IPv4CIDR("192.168.1.0/24")},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.create.Name = "test-" + t.Name()
tt.create.Wait = false
tt.create.WaitTimeout = time.Second

apiClient, err := test.SetupClient()
require.NoError(t, err)

if err := tt.create.Run(ctx, apiClient); (err != nil) != tt.wantErr {
t.Errorf("openSearchCmd.Run() error = %v, wantErr %v", err, tt.wantErr)
}

created := &storage.OpenSearch{ObjectMeta: metav1.ObjectMeta{Name: tt.create.Name, Namespace: apiClient.Project}}
if err := apiClient.Get(ctx, api.ObjectName(created), created); (err != nil) != tt.wantErr {
t.Fatalf("expected opensearch to exist, got: %s", err)
}
if tt.wantErr {
return
}

require.True(t, cmp.Equal(tt.want, created.Spec.ForProvider))
})
}
}
1 change: 1 addition & 0 deletions delete/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type Cmd struct {
Postgres postgresCmd `cmd:"" group:"storage.nine.ch" name:"postgres" help:"Delete a PostgreSQL instance."`
PostgresDatabase postgresDatabaseCmd `cmd:"" group:"storage.nine.ch" name:"postgresdatabase" help:"Delete a PostgreSQL database."`
KeyValueStore keyValueStoreCmd `cmd:"" group:"storage.nine.ch" name:"keyvaluestore" aliases:"kvs" help:"Delete a KeyValueStore instance."`
OpenSearch openSearchCmd `cmd:"" group:"storage.nine.ch" name:"opensearch" aliases:"os" help:"Delete an OpenSearch cluster."`
CloudVirtualMachine cloudVMCmd `cmd:"" group:"infrastructure.nine.ch" name:"cloudvirtualmachine" aliases:"cloudvm" help:"Delete a CloudVM."`
ServiceConnection serviceConnectionCmd `cmd:"" group:"networking.nine.ch" name:"serviceconnection" aliases:"sc" help:"Delete a ServiceConnection."`
}
Expand Down
21 changes: 21 additions & 0 deletions delete/opensearch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package delete

import (
"context"

storage "github.com/ninech/apis/storage/v1alpha1"
"github.com/ninech/nctl/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type openSearchCmd struct {
resourceCmd
}

func (cmd *openSearchCmd) Run(ctx context.Context, client *api.Client) error {
ctx, cancel := context.WithTimeout(ctx, cmd.WaitTimeout)
defer cancel()

openSearch := &storage.OpenSearch{ObjectMeta: metav1.ObjectMeta{Name: cmd.Name, Namespace: client.Project}}
return newDeleter(openSearch, storage.OpenSearchKind).deleteResource(ctx, client, cmd.WaitTimeout, cmd.Wait, cmd.Force)
}
46 changes: 46 additions & 0 deletions delete/opensearch_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package delete

import (
"context"
"testing"
"time"

"github.com/ninech/nctl/api"
"github.com/ninech/nctl/internal/test"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/api/errors"
)

func TestOpenSearch(t *testing.T) {
ctx := context.Background()
cmd := openSearchCmd{
resourceCmd: resourceCmd{
Name: "test",
Force: true,
Wait: false,
WaitTimeout: time.Second,
},
}

opensearch := test.OpenSearch("test", test.DefaultProject, "nine-es34")

apiClient, err := test.SetupClient()
require.NoError(t, err)

if err := apiClient.Create(ctx, opensearch); err != nil {
t.Fatalf("opensearch create error, got: %s", err)
}
if err := apiClient.Get(ctx, api.ObjectName(opensearch), opensearch); err != nil {
t.Fatalf("expected opensearch to exist, got: %s", err)
}
if err := cmd.Run(ctx, apiClient); err != nil {
t.Fatal(err)
}
err = apiClient.Get(ctx, api.ObjectName(opensearch), opensearch)
if err == nil {
t.Fatalf("expected opensearch to be deleted, but exists")
}
if !errors.IsNotFound(err) {
t.Fatalf("expected opensearch to be deleted, got: %s", err.Error())
}
}
1 change: 1 addition & 0 deletions edit/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type Cmd struct {
Postgres resourceCmd `cmd:"" group:"storage.nine.ch" name:"postgres" help:"Edit a PostgreSQL instance."`
PostgresDatabase resourceCmd `cmd:"" group:"storage.nine.ch" name:"postgresdatabase" help:"Edit a PostgreSQL database."`
KeyValueStore resourceCmd `cmd:"" group:"storage.nine.ch" name:"keyvaluestore" aliases:"kvs" help:"Edit a KeyValueStore instance"`
OpenSearch resourceCmd `cmd:"" group:"storage.nine.ch" name:"opensearch" aliases:"os" help:"Edit an OpenSearch cluster."`
CloudVirtualMachine resourceCmd `cmd:"" group:"infrastructure.nine.ch" name:"cloudvirtualmachine" aliases:"cloudvm" help:"Edit a CloudVM."`
}

Expand Down
1 change: 1 addition & 0 deletions get/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type Cmd struct {
Configs configsCmd `cmd:"" group:"deplo.io" name:"configs" aliases:"config" help:"Get deplo.io Project Configuration."`
MySQL mySQLCmd `cmd:"" group:"storage.nine.ch" name:"mysql" help:"Get MySQL instances."`
MySQLDatabases mysqlDatabaseCmd `cmd:"" group:"storage.nine.ch" name:"mysqldatabases" aliases:"mysqldatabase" help:"Get MySQL databases."`
OpenSearch openSearchCmd `cmd:"" group:"storage.nine.ch" name:"opensearch" aliases:"os" help:"Get OpenSearch clusters."`
Postgres postgresCmd `cmd:"" group:"storage.nine.ch" name:"postgres" help:"Get PostgreSQL instances."`
PostgresDatabases postgresDatabaseCmd `cmd:"" group:"storage.nine.ch" name:"postgresdatabases" aliases:"postgresdatabase" help:"Get PostgreSQL databases."`
KeyValueStore keyValueStoreCmd `cmd:"" group:"storage.nine.ch" name:"keyvaluestore" aliases:"kvs" help:"Get KeyValueStore instances."`
Expand Down
108 changes: 108 additions & 0 deletions get/opensearch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package get

import (
"context"
"fmt"

storage "github.com/ninech/apis/storage/v1alpha1"
"github.com/ninech/nctl/api"
"github.com/ninech/nctl/internal/format"
"sigs.k8s.io/controller-runtime/pkg/client"
)

type openSearchCmd struct {
resourceCmd
PrintPassword bool `help:"Print the password of the OpenSearch BasicAuth User. Requires name to be set." xor:"print"`
PrintUser bool `help:"Print the name of the OpenSearch BasicAuth User. Requires name to be set." xor:"print"`
PrintCACert bool `help:"Print the ca certificate. Requires name to be set." xor:"print"`
}

func (cmd *openSearchCmd) Run(ctx context.Context, client *api.Client, get *Cmd) error {
return get.listPrint(ctx, client, cmd, api.MatchName(cmd.Name))
}

func (cmd *openSearchCmd) list() client.ObjectList {
return &storage.OpenSearchList{}
}

func (cmd *openSearchCmd) print(ctx context.Context, client *api.Client, list client.ObjectList, out *output) error {
openSearchList, ok := list.(*storage.OpenSearchList)
if !ok {
return fmt.Errorf("expected %T, got %T", &storage.OpenSearchList{}, list)
}
if len(openSearchList.Items) == 0 {
return out.printEmptyMessage(storage.OpenSearchKind, client.Project)
}

if cmd.Name != "" && cmd.PrintUser {
return cmd.printSecret(out.writer, ctx, client, &openSearchList.Items[0], func(user, _ string) string { return user })
}

if cmd.Name != "" && cmd.PrintPassword {
return cmd.printSecret(out.writer, ctx, client, &openSearchList.Items[0], func(_, pw string) string { return pw })
}

if cmd.Name != "" && cmd.PrintCACert {
return printBase64(out.writer, openSearchList.Items[0].Status.AtProvider.CACert)
}

switch out.Format {
case full:
return cmd.printOpenSearchInstances(openSearchList.Items, out, true)
case noHeader:
return cmd.printOpenSearchInstances(openSearchList.Items, out, false)
case yamlOut:
return format.PrettyPrintObjects(openSearchList.GetItems(), format.PrintOpts{})
case jsonOut:
return format.PrettyPrintObjects(
openSearchList.GetItems(),
format.PrintOpts{
Format: format.OutputFormatTypeJSON,
JSONOpts: format.JSONOutputOptions{
PrintSingleItem: cmd.Name != "",
},
})
}

return nil
}

func (cmd *openSearchCmd) printOpenSearchInstances(list []storage.OpenSearch, out *output, header bool) error {
if header {
out.writeHeader("NAME", "FQDN", "MACHINE TYPE", "CLUSTER TYPE", "DISK SIZE", "HEALTH")
}

for _, openSearch := range list {
out.writeTabRow(
openSearch.Namespace,
openSearch.Name,
openSearch.Status.AtProvider.FQDN,
openSearch.Spec.ForProvider.MachineType.String(),
string(openSearch.Spec.ForProvider.ClusterType),
openSearch.Status.AtProvider.DiskSize.String(),
string(cmd.getClusterHealth(openSearch.Status.AtProvider.ClusterHealth)),
)
}

return out.tabWriter.Flush()
}

func (cmd *openSearchCmd) getClusterHealth(clusterHealth storage.OpenSearchClusterHealth) storage.OpenSearchHealthStatus {
worstStatus := storage.OpenSearchHealthStatusGreen

// If no indices, assume healthy
if len(clusterHealth.Indices) == 0 {
return worstStatus
}
// Determine the worst status of all indices
for _, idx := range clusterHealth.Indices {
switch idx.Status {
case storage.OpenSearchHealthStatusRed:
return idx.Status
case storage.OpenSearchHealthStatusYellow:
worstStatus = idx.Status
}
}

return worstStatus
}
Loading
Loading