Skip to content
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
.DS_Store
/build
dist/
abctl
/abctl
34 changes: 17 additions & 17 deletions internal/cmd/local/localerr/localerr.go → internal/abctl/error.go
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
package localerr
package abctl

var _ error = (*LocalError)(nil)
var _ error = (*Error)(nil)

// LocalError adds a user-friendly help message to specific errors.
type LocalError struct {
// Error adds a user-friendly help message to specific errors.
type Error struct {
help string
msg string
}

// Help will displayed to the user if this specific error is ever returned.
func (e *LocalError) Help() string {
func (e *Error) Help() string {
return e.help
}

// Error returns the error message.
func (e *LocalError) Error() string {
func (e *Error) Error() string {
return e.msg
}

var (
// ErrAirbyteDir is returned anytime an there is an issue in accessing the paths.Airbyte directory.
ErrAirbyteDir = &LocalError{
ErrAirbyteDir = &Error{
msg: "airbyte directory is inaccessible",
help: `The ~/.airbyte directory is inaccessible.
You may need to remove this directory before trying your command again.`,
}

// ErrClusterNotFound is returned in the event that no cluster was located.
ErrClusterNotFound = &LocalError{
ErrClusterNotFound = &Error{
msg: "no existing cluster found",
help: `No cluster was found. If this is unexpected,
you may need to run the "local install" command again.`,
}

// ErrDocker is returned anytime an error occurs when attempting to communicate with docker.
ErrDocker = &LocalError{
ErrDocker = &Error{
msg: "error communicating with docker",
help: `An error occurred while communicating with the Docker daemon.
Ensure that Docker is running and is accessible. You may need to upgrade to a newer version of Docker.
Expand All @@ -43,7 +43,7 @@ For additional help please visit https://docs.docker.com/get-docker/`,

// ErrHelmStuck is returned if when running a helm install or upgrade command, a previous install or upgrade
// attempt is already in progress which this tool cannot work around.
ErrHelmStuck = &LocalError{
ErrHelmStuck = &Error{
msg: "another helm operation (install/upgrade/rollback) is in progress",
help: `An error occurred while attempting to run a helm install or upgrade.
If this error persists, you may need to run the "abctl local uninstall" command before attempting to run the
Expand All @@ -53,7 +53,7 @@ Your data will persist between the uninstall and install commands.
}

// ErrKubernetes is returned anytime an error occurs when attempting to communicate with the kubernetes cluster.
ErrKubernetes = &LocalError{
ErrKubernetes = &Error{
msg: "error communicating with kubernetes",
help: `An error occurred while communicating with the Kubernetes cluster.
If this error persists, you may need to run the "abctl local uninstall" command before attempting to run the
Expand All @@ -62,38 +62,38 @@ Your data will persist between the uninstall and install commands.`,
}

// ErrIngress is returned in the event that ingress configuration failed.
ErrIngress = &LocalError{
ErrIngress = &Error{
msg: "error configuring ingress",
help: `An error occurred while configuring ingress.
This could be in indication that the ingress port is already in use by a different application.
The ingress port can be changed by passing the flag --port.`,
}

// ErrPort is returned in the event that the requested port is unavailable.
ErrPort = &LocalError{
ErrPort = &Error{
msg: "error verifying port availability",
help: `An error occurred while verifying if the request port is available.
This could be in indication that the ingress port is already in use by a different application.
The ingress port can be changed by passing the flag --port.`,
}

ErrIpAddressForHostFlag = &LocalError{
ErrIpAddressForHostFlag = &Error{
msg: "invalid host - can't use an IP address",
help: `Looks like you provided an IP address to the --host flag.
This won't work, because Kubernetes ingress rules require a lowercase domain name.

By default, abctl will allow access from any hostname or IP, so you might not need the --host flag.`,
}

ErrInvalidHostFlag = &LocalError{
ErrInvalidHostFlag = &Error{
msg: "invalid host",
help: `The --host flag expects a lowercase domain name, e.g. "example.com".
help: `The --host flag expects a lowercase domain name, e.g. "example.com".
IP addresses won't work. Ports won't work (e.g. example:8000). URLs won't work (e.g. http://example.com).

By default, abctl will allow access from any hostname or IP, so you might not need the --host flag.`,
}

ErrBootloaderFailed = &LocalError{
ErrBootloaderFailed = &Error{
msg: "bootloader failed",
help: "The bootloader failed to its initialization checks or migrations. Try running again with --verbose to see the full bootloader logs.",
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package localerr
package abctl

import (
"errors"
Expand All @@ -9,14 +9,14 @@ import (

func TestLocalError(t *testing.T) {
f := func() error {
return &LocalError{
return &Error{
help: "help message",
msg: "error message",
}
}

err := f()
var e *LocalError
var e *Error
if !errors.As(err, &e) {
t.Fatal("error should be of type LocalError")
}
Expand Down
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion internal/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (

"github.com/airbytehq/abctl/internal/cmd/images"
"github.com/airbytehq/abctl/internal/cmd/local"
"github.com/airbytehq/abctl/internal/cmd/local/k8s"
"github.com/airbytehq/abctl/internal/cmd/version"
"github.com/airbytehq/abctl/internal/k8s"
"github.com/alecthomas/kong"
"github.com/pterm/pterm"
)
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/images/manifest_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"slices"
"strings"

"github.com/airbytehq/abctl/internal/cmd/local/helm"
"github.com/airbytehq/abctl/internal/common"
"github.com/airbytehq/abctl/internal/helm"
"github.com/airbytehq/abctl/internal/trace"
helmlib "github.com/mittwald/go-helm-client"
"helm.sh/helm/v3/pkg/repo"
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/images/manifest_cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/google/go-cmp/cmp"
helmlib "github.com/mittwald/go-helm-client"

"github.com/airbytehq/abctl/internal/cmd/local/helm"
"github.com/airbytehq/abctl/internal/helm"
)

func getHelmTestClient(t *testing.T) helm.Client {
Expand Down
16 changes: 8 additions & 8 deletions internal/cmd/local/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (
"strconv"
"syscall"

"github.com/airbytehq/abctl/internal/cmd/local/docker"
"github.com/airbytehq/abctl/internal/cmd/local/localerr"
"github.com/airbytehq/abctl/internal/abctl"
"github.com/airbytehq/abctl/internal/docker"
"github.com/airbytehq/abctl/internal/telemetry"
"github.com/airbytehq/abctl/internal/trace"
"github.com/pterm/pterm"
Expand All @@ -35,14 +35,14 @@ func dockerInstalled(ctx context.Context, telClient telemetry.Client) (docker.Ve
if dockerClient == nil {
if dockerClient, err = docker.New(ctx); err != nil {
pterm.Error.Println("Unable to create Docker client")
return docker.Version{}, fmt.Errorf("%w: unable to create client: %w", localerr.ErrDocker, err)
return docker.Version{}, fmt.Errorf("%w: unable to create client: %w", abctl.ErrDocker, err)
}
}

version, err := dockerClient.Version(ctx)
if err != nil {
pterm.Error.Println("Unable to communicate with the Docker daemon")
return docker.Version{}, fmt.Errorf("%w: %w", localerr.ErrDocker, err)
return docker.Version{}, fmt.Errorf("%w: %w", abctl.ErrDocker, err)
}

span.SetAttributes(
Expand Down Expand Up @@ -94,10 +94,10 @@ func portAvailable(ctx context.Context, port int) error {
lc := &net.ListenConfig{}
listener, err := lc.Listen(ctx, "tcp", fmt.Sprintf("localhost:%d", port))
if isErrorAddressAlreadyInUse(err) {
return fmt.Errorf("%w: port %d is already in use", localerr.ErrPort, port)
return fmt.Errorf("%w: port %d is already in use", abctl.ErrPort, port)
}
if err != nil {
return fmt.Errorf("%w: unable to determine if port '%d' is available: %w", localerr.ErrPort, port, err)
return fmt.Errorf("%w: unable to determine if port '%d' is available: %w", abctl.ErrPort, port, err)
}
// if we're able to bind to the port (and then release it), it should be available
defer func() {
Expand Down Expand Up @@ -193,10 +193,10 @@ func (e InvalidPortError) Error() string {

func validateHostFlag(host string) error {
if ip := net.ParseIP(host); ip != nil {
return localerr.ErrIpAddressForHostFlag
return abctl.ErrIpAddressForHostFlag
}
if !regexp.MustCompile(`^[a-z0-9](?:[-a-z0-9]*[a-z0-9])?(?:\.[a-z0-9](?:[-a-z0-9]*[a-z0-9])?)*$`).MatchString(host) {
return localerr.ErrInvalidHostFlag
return abctl.ErrInvalidHostFlag
}
return nil
}
18 changes: 9 additions & 9 deletions internal/cmd/local/check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
"strings"
"testing"

"github.com/airbytehq/abctl/internal/cmd/local/docker"
"github.com/airbytehq/abctl/internal/cmd/local/docker/dockertest"
"github.com/airbytehq/abctl/internal/cmd/local/localerr"
"github.com/airbytehq/abctl/internal/abctl"
"github.com/airbytehq/abctl/internal/docker"
"github.com/airbytehq/abctl/internal/docker/dockertest"
"github.com/airbytehq/abctl/internal/telemetry"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
Expand Down Expand Up @@ -107,7 +107,7 @@ func TestPortAvailable_Unavailable(t *testing.T) {
if err == nil {
t.Error("portAvailable should have returned an error")
}
if !errors.Is(err, localerr.ErrPort) {
if !errors.Is(err, abctl.ErrPort) {
t.Error("error should be of type ErrPort")
}
}
Expand Down Expand Up @@ -276,11 +276,11 @@ func TestValidateHostFlag(t *testing.T) {
t.Errorf("expected error %v for host %q but got %v", expect, host, err)
}
}
expectErr("1.2.3.4", localerr.ErrIpAddressForHostFlag)
expectErr("1.2.3.4:8000", localerr.ErrInvalidHostFlag)
expectErr("1.2.3.4:8000", localerr.ErrInvalidHostFlag)
expectErr("ABC-DEF-GHI.abcd.efgh", localerr.ErrInvalidHostFlag)
expectErr("http://airbyte.foo-data-platform-sbx.bar.cloud", localerr.ErrInvalidHostFlag)
expectErr("1.2.3.4", abctl.ErrIpAddressForHostFlag)
expectErr("1.2.3.4:8000", abctl.ErrInvalidHostFlag)
expectErr("1.2.3.4:8000", abctl.ErrInvalidHostFlag)
expectErr("ABC-DEF-GHI.abcd.efgh", abctl.ErrInvalidHostFlag)
expectErr("http://airbyte.foo-data-platform-sbx.bar.cloud", abctl.ErrInvalidHostFlag)

expectOk := func(host string) {
err := validateHostFlag(host)
Expand Down
35 changes: 35 additions & 0 deletions internal/cmd/local/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package local

import (
"net/http"

"github.com/airbytehq/abctl/internal/docker"
"github.com/airbytehq/abctl/internal/helm"
"github.com/airbytehq/abctl/internal/k8s"
"github.com/airbytehq/abctl/internal/telemetry"
"github.com/pterm/pterm"
)

type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
}

// BrowserLauncher primarily for testing purposes.
type BrowserLauncher func(url string) error

// Command is the local command, responsible for installing, uninstalling, or other local actions.
type Command struct {
provider k8s.Provider
docker *docker.Docker

http HTTPClient
helm helm.Client
k8s k8s.Client
portHTTP int
spinner *pterm.SpinnerPrinter
tel telemetry.Client
launcher BrowserLauncher
userHome string
}

// TODO: Move the constructor and other Command methods from local/local/cmd.go to here
29 changes: 29 additions & 0 deletions internal/cmd/local/install.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package local

import (
"github.com/airbytehq/abctl/internal/k8s"
)

type InstallOpts struct {
HelmChartVersion string
HelmValuesYaml string
AirbyteChartLoc string
Secrets []string
Hosts []string
ExtraVolumeMounts []k8s.ExtraVolumeMount
LocalStorage bool
EnablePsql17 bool

DockerServer string
DockerUser string
DockerPass string
DockerEmail string

NoBrowser bool
}

func (i *InstallOpts) DockerAuth() bool {
return i.DockerUser != "" && i.DockerPass != ""
}

// TODO: Move the Install method and related functions from local/local/install.go to here
8 changes: 4 additions & 4 deletions internal/cmd/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"io/fs"
"os"

"github.com/airbytehq/abctl/internal/cmd/local/k8s"
"github.com/airbytehq/abctl/internal/cmd/local/localerr"
"github.com/airbytehq/abctl/internal/cmd/local/paths"
"github.com/airbytehq/abctl/internal/abctl"
"github.com/airbytehq/abctl/internal/k8s"
"github.com/airbytehq/abctl/internal/paths"
"github.com/pterm/pterm"
)

Expand All @@ -26,7 +26,7 @@ func (c *Cmd) BeforeApply() error {
}

if err := checkAirbyteDir(); err != nil {
return fmt.Errorf("%w: %w", localerr.ErrAirbyteDir, err)
return fmt.Errorf("%w: %w", abctl.ErrAirbyteDir, err)
}

return nil
Expand Down
18 changes: 9 additions & 9 deletions internal/cmd/local/local/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ import (
"path/filepath"
"time"

"github.com/airbytehq/abctl/internal/cmd/local/docker"
"github.com/airbytehq/abctl/internal/cmd/local/helm"
"github.com/airbytehq/abctl/internal/cmd/local/k8s/kind"
"github.com/airbytehq/abctl/internal/cmd/local/paths"
"github.com/airbytehq/abctl/internal/abctl"
"github.com/airbytehq/abctl/internal/common"
"github.com/airbytehq/abctl/internal/docker"
"github.com/airbytehq/abctl/internal/helm"
"github.com/airbytehq/abctl/internal/k8s/kind"
"github.com/airbytehq/abctl/internal/paths"
"github.com/airbytehq/abctl/internal/pgdata"
"k8s.io/client-go/rest"

"github.com/airbytehq/abctl/internal/cmd/local/k8s"
"github.com/airbytehq/abctl/internal/cmd/local/localerr"
"github.com/airbytehq/abctl/internal/k8s"
"github.com/airbytehq/abctl/internal/telemetry"
"github.com/cli/browser"
"github.com/pterm/pterm"
Expand Down Expand Up @@ -168,7 +168,7 @@ func New(provider k8s.Provider, opts ...Option) (*Command, error) {
{
k8sVersion, err := c.k8s.ServerVersionGet()
if err != nil {
return nil, fmt.Errorf("%w: unable to fetch kubernetes server version: %w", localerr.ErrKubernetes, err)
return nil, fmt.Errorf("%w: unable to fetch kubernetes server version: %w", abctl.ErrKubernetes, err)
}
c.tel.Attr("k8s_version", k8sVersion)
}
Expand All @@ -189,11 +189,11 @@ func DefaultK8s(kubecfg, kubectx string) (k8s.Client, error) {

restCfg, err := k8sCfg.ClientConfig()
if err != nil {
return nil, fmt.Errorf("%w: could not create rest config: %w", localerr.ErrKubernetes, err)
return nil, fmt.Errorf("%w: could not create rest config: %w", abctl.ErrKubernetes, err)
}
k8sClient, err := kubernetes.NewForConfig(restCfg)
if err != nil {
return nil, fmt.Errorf("%w: could not create clientset: %w", localerr.ErrKubernetes, err)
return nil, fmt.Errorf("%w: could not create clientset: %w", abctl.ErrKubernetes, err)
}

return &k8s.DefaultK8sClient{ClientSet: k8sClient}, nil
Expand Down
Loading