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 Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ vet:
.PHONY: mocks
mocks:
mockgen --source $(GOPATH)/pkg/mod/github.com/mittwald/[email protected]/interface.go -destination internal/helm/mock/mock.go -package mock
mockgen --source internal/http/client.go -destination internal/http/mock/mock.go -package mock

.PHONY: tools
tools:
Expand Down
47 changes: 47 additions & 0 deletions cmd/airbox/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import (
"context"
"os"

"github.com/airbytehq/abctl/internal/cmd/auth"
"github.com/airbytehq/abctl/internal/cmd/config"
"github.com/airbytehq/abctl/internal/k8s"
"github.com/alecthomas/kong"
"github.com/pterm/pterm"
)

// rootCmd represents the airbox command.
type rootCmd struct {
Config config.Cmd `cmd:"" help:"Initialize the configuration."`
Auth auth.Cmd `cmd:"" help:"Authenticate with Airbyte."`
}

func main() {
pterm.Info.Prefix.Text = " INFO "
ctx := context.Background()
var cmd rootCmd

parser, err := kong.New(
&cmd,
kong.Name("airbox"),
kong.Bind(k8s.DefaultProvider, (*k8s.Provider)(nil)),
)
if err != nil {
panic(err)
}

parsed, err := parser.Parse(os.Args[1:])
if err != nil {
parser.FatalIfErrorf(err)
}

parsed.BindToProvider(func() (context.Context, error) {
return ctx, nil
})

err = parsed.Run()
if err != nil {
pterm.Error.Println(err)
}
}
22 changes: 22 additions & 0 deletions internal/api/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package api

import (
"net/http"
)

// Client handles Control Plane API operations
type Client struct {
http HTTPDoer
}

// HTTPDoer interface for making HTTP requests
type HTTPDoer interface {
Do(req *http.Request) (*http.Response, error)
}

// NewClient creates a new API client
func NewClient(http HTTPDoer) *Client {
return &Client{
http: http,
}
}
20 changes: 20 additions & 0 deletions internal/api/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package api

import (
"testing"

"github.com/airbytehq/abctl/internal/http/mock"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
)

func TestNewClient(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

mockDoer := mock.NewMockHTTPDoer(ctrl)
client := NewClient(mockDoer)

assert.NotNil(t, client)
assert.Equal(t, mockDoer, client.http)
}
135 changes: 135 additions & 0 deletions internal/api/dataplanes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package api

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)

const (
dataplanesPath = "/api/v1/dataplanes"
)

// DataplaneSpec represents the input for dataplane operations
type DataplaneSpec struct {
Name string `json:"name"`
Type string `json:"type"`
Config map[string]string `json:"config"`
}

// Dataplane represents a dataplane resource
type Dataplane struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Status string `json:"status"`
Config map[string]string `json:"config"`
}

// GetDataplane retrieves a specific dataplane by ID
func (c *Client) GetDataplane(ctx context.Context, id string) (*Dataplane, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, dataplanesPath+"/"+id, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}

resp, err := c.http.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("API error %d: %s", resp.StatusCode, string(body))
}

var dataplane Dataplane
if err := json.NewDecoder(resp.Body).Decode(&dataplane); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}

return &dataplane, nil
}

// ListDataplanes retrieves all dataplanes
func (c *Client) ListDataplanes(ctx context.Context) ([]Dataplane, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, dataplanesPath, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}

resp, err := c.http.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("API error %d: %s", resp.StatusCode, string(body))
}

var dataplanes []Dataplane
if err := json.NewDecoder(resp.Body).Decode(&dataplanes); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}

return dataplanes, nil
}

// CreateDataplane creates a new dataplane
func (c *Client) CreateDataplane(ctx context.Context, spec DataplaneSpec) (*Dataplane, error) {
reqBody, err := json.Marshal(spec)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %w", err)
}

req, err := http.NewRequestWithContext(ctx, http.MethodPost, dataplanesPath, bytes.NewReader(reqBody))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")

resp, err := c.http.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusCreated {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("API error %d: %s", resp.StatusCode, string(body))
}

var dataplane Dataplane
if err := json.NewDecoder(resp.Body).Decode(&dataplane); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}

return &dataplane, nil
}

// DeleteDataplane deletes a dataplane by ID
func (c *Client) DeleteDataplane(ctx context.Context, id string) error {
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, dataplanesPath+"/"+id, nil)
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}

resp, err := c.http.Do(req)
if err != nil {
return fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("API error %d: %s", resp.StatusCode, string(body))
}

return nil
}
Loading