Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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