Skip to content
Open
Show file tree
Hide file tree
Changes from 10 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
4 changes: 2 additions & 2 deletions cluster/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ type Client interface {
tsq remotecommand.TerminalSizeQueue) (ctypes.ExecResult, error)

// ConnectHostnameToDeployment Connect a given hostname to a deployment
ConnectHostnameToDeployment(ctx context.Context, directive ctypes.ConnectHostnameToDeploymentDirective) error
ConnectHostnameToDeployment(ctx context.Context, directive ctypes.ConnectHostnameToDeploymentDirective, tlsEnabled bool) error
// RemoveHostnameFromDeployment Remove a given hostname from a deployment
RemoveHostnameFromDeployment(ctx context.Context, hostname string, leaseID mtypes.LeaseID, allowMissing bool) error

Expand Down Expand Up @@ -415,7 +415,7 @@ func (c *nullClient) GetHostnameDeploymentConnections(_ context.Context) ([]ctyp
return nil, errNotImplemented
}

func (c *nullClient) ConnectHostnameToDeployment(_ context.Context, _ ctypes.ConnectHostnameToDeploymentDirective) error {
func (c *nullClient) ConnectHostnameToDeployment(_ context.Context, _ ctypes.ConnectHostnameToDeploymentDirective, _ bool) error {
return errNotImplemented
}

Expand Down
7 changes: 7 additions & 0 deletions cluster/kube/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type client struct {
ns string
log log.Logger
kubeContentConfig *restclient.Config
cfg clientConfig
}

func (c *client) String() string {
Expand Down Expand Up @@ -91,13 +92,19 @@ func NewClient(ctx context.Context, log log.Logger, ns string, configPath string
return nil, errors.Wrap(err, "kube: error creating metrics client")
}

ccfg, err := configFromEnv()
if err != nil {
return nil, errors.Wrap(err, "kube: error creating client configuration")
}

return &client{
kc: kc,
ac: mc,
metc: metc,
ns: ns,
log: log.With("client", "kube"),
kubeContentConfig: config,
cfg: *ccfg,
}, nil
}

Expand Down
29 changes: 25 additions & 4 deletions cluster/kube/client_ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ import (

const (
akashIngressClassName = "akash-ingress-class"
root = "nginx.ingress.kubernetes.io"
certManager = "cert-manager.io"
)

func kubeNginxIngressAnnotations(directive ctypes.ConnectHostnameToDeploymentDirective) map[string]string {
func (c *client) kubeNginxIngressAnnotations(directive ctypes.ConnectHostnameToDeploymentDirective) map[string]string {
// For kubernetes/ingress-nginx
// https://github.com/kubernetes/ingress-nginx
const root = "nginx.ingress.kubernetes.io"

readTimeout := math.Ceil(float64(directive.ReadTimeout) / 1000.0)
sendTimeout := math.Ceil(float64(directive.SendTimeout) / 1000.0)
Expand Down Expand Up @@ -66,11 +67,20 @@ func kubeNginxIngressAnnotations(directive ctypes.ConnectHostnameToDeploymentDir
}
}

switch c.cfg.ssl.issuerType {
case clusterIssuer:
result[fmt.Sprintf("%s/cluster-issuer", certManager)] = c.cfg.ssl.issuerName
break
case issuer:
result[fmt.Sprintf("%s/issuer", certManager)] = c.cfg.ssl.issuerName
break
}

result[fmt.Sprintf("%s/proxy-next-upstream", root)] = strBuilder.String()
return result
}

func (c *client) ConnectHostnameToDeployment(ctx context.Context, directive ctypes.ConnectHostnameToDeploymentDirective) error {
func (c *client) ConnectHostnameToDeployment(ctx context.Context, directive ctypes.ConnectHostnameToDeploymentDirective, tlsEnabled bool) error {
ingressName := directive.Hostname
ns := builder.LidNS(directive.LeaseID)
rules := ingressRules(directive.Hostname, directive.ServiceName, directive.ServicePort)
Expand All @@ -82,16 +92,27 @@ func (c *client) ConnectHostnameToDeployment(ctx context.Context, directive ctyp
labels[builder.AkashManagedLabelName] = "true"
builder.AppendLeaseLabels(directive.LeaseID, labels)

var tls []netv1.IngressTLS
if tlsEnabled {
tls = []netv1.IngressTLS{
{
Hosts: []string{directive.Hostname},
SecretName: fmt.Sprintf("%s-tls", ingressName),
},
}
}

ingressClassName := akashIngressClassName
obj := &netv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: ingressName,
Labels: labels,
Annotations: kubeNginxIngressAnnotations(directive),
Annotations: c.kubeNginxIngressAnnotations(directive),
},
Spec: netv1.IngressSpec{
IngressClassName: &ingressClassName,
Rules: rules,
TLS: tls,
},
}

Expand Down
52 changes: 52 additions & 0 deletions cluster/kube/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package kube

import (
"fmt"
kubeclienterrors "github.com/akash-network/provider/cluster/kube/errors"
"github.com/pkg/errors"
"os"
)

const (
issuer = "issuer"
clusterIssuer = "cluster-issuer"
akashProviderIssuerTypeStr = "AKASH_PROVIDER_ISSUER_TYPE"
akashProviderIssuerNameStr = "AKASH_PROVIDER_ISSUER_NAME"
akashProviderSslEnabledStr = "AKASH_PROVIDER_SSL_ENABLED"
)

type clientConfig struct {
ssl ssl
}

type ssl struct {
issuerType string
issuerName string
}

// configFromEnv creates a new clientConfig from environment variables.
func configFromEnv() (*clientConfig, error) {
sslEnabled := os.Getenv(akashProviderSslEnabledStr)
var sslCfg ssl

if sslEnabled != "" && sslEnabled != "0" {
issuerType, ok := os.LookupEnv(akashProviderIssuerTypeStr)
if !ok || (issuerType != issuer && issuerType != clusterIssuer) {
return nil, errors.Wrap(kubeclienterrors.ErrInternalError, fmt.Sprintf("Invalid value for %s: %s", akashProviderIssuerTypeStr, issuerType))
}

issuerName, ok := os.LookupEnv(akashProviderIssuerNameStr)
if !ok {
return nil, errors.Wrap(kubeclienterrors.ErrInternalError, fmt.Sprintf("Value for %s not set", akashProviderIssuerNameStr))
}

sslCfg = ssl{
issuerType: issuerType,
issuerName: issuerName,
}
}

return &clientConfig{
ssl: sslCfg,
}, nil
}
64 changes: 64 additions & 0 deletions cluster/kube/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package kube

import (
"os"
"testing"
)

func TestConfigFromEnv(t *testing.T) {
t.Run("should create if environment variables are set correctly", func(t *testing.T) {
os.Setenv(akashProviderIssuerTypeStr, "cluster-issuer")
os.Setenv(akashProviderIssuerNameStr, "letsencrypt")
os.Setenv(akashProviderSslEnabledStr, "1")
ccfg, err := configFromEnv()

if err != nil {
t.Fatalf("Did not expect an error: %s", err)
}

if ccfg.ssl.issuerType != "cluster-issuer" {
t.Errorf("Expected cluster-issuer, got %s", ccfg.ssl.issuerType)
}

if ccfg.ssl.issuerName != "letsencrypt" {
t.Errorf("Expected letsencrypt, got %s", ccfg.ssl.issuerName)
}
})

t.Run("should return error if type not set", func(t *testing.T) {
os.Clearenv()
os.Setenv(akashProviderIssuerNameStr, "letsencrypt")
os.Setenv(akashProviderSslEnabledStr, "1")

_, err := configFromEnv()

if err == nil {
t.Fatalf("Expected an error")
}
})

t.Run("should return error if name not set", func(t *testing.T) {
os.Clearenv()
os.Setenv(akashProviderIssuerTypeStr, "cluster-issuer")
os.Setenv(akashProviderSslEnabledStr, "1")

_, err := configFromEnv()

if err == nil {
t.Fatalf("Expected an error")
}
})

t.Run("should return error if type is invalid", func(t *testing.T) {
os.Clearenv()
os.Setenv(akashProviderIssuerTypeStr, "fake-issuer-type")
os.Setenv(akashProviderIssuerNameStr, "letsencrypt")
os.Setenv(akashProviderSslEnabledStr, "1")

_, err := configFromEnv()

if err == nil {
t.Fatalf("Expected an error")
}
})
}
21 changes: 11 additions & 10 deletions cluster/mocks/client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions cluster/util/environment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package util

import (
"os"
"strings"
)

func EnvironmentVariablesToMap() map[string]string {
m := make(map[string]string, len(os.Environ()))
for _, e := range os.Environ() {
if i := strings.Index(e, "="); i >= 0 {
m[e[:i]] = e[i+1:]
}
}

return m
}
7 changes: 5 additions & 2 deletions operator/hostnameoperator/hostname_operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ type hostnameOperator struct {

flagHostnamesData operatorcommon.PrepareFlagFn
flagIgnoreListData operatorcommon.PrepareFlagFn

env map[string]string
}

func (op *hostnameOperator) run(parentCtx context.Context) error {
Expand Down Expand Up @@ -389,7 +391,7 @@ func (op *hostnameOperator) applyAddOrUpdateEvent(ctx context.Context, ev ctypes
if shouldConnect {
op.log.Debug("Updating ingress")
// Update or create the existing ingress
err = op.client.ConnectHostnameToDeployment(ctx, directive)
err = op.client.ConnectHostnameToDeployment(ctx, directive, op.env["AKASH_SSL_ENABLED"] != "")
}
} else {
op.log.Debug("Swapping ingress to new deployment")
Expand All @@ -398,7 +400,7 @@ func (op *hostnameOperator) applyAddOrUpdateEvent(ctx context.Context, ev ctypes
if err == nil {
// Remove the current entry, if the next action succeeds then it gets inserted below
delete(op.hostnames, ev.GetHostname())
err = op.client.ConnectHostnameToDeployment(ctx, directive)
err = op.client.ConnectHostnameToDeployment(ctx, directive, op.env["AKASH_SSL_ENABLED"] != "")
}
}

Expand Down Expand Up @@ -427,6 +429,7 @@ func newHostnameOperator(logger log.Logger, client cluster.Client, config operat
cfg: config,
server: opHTTP,
leasesIgnored: operatorcommon.NewIgnoreList(ilc),
env: clusterutil.EnvironmentVariablesToMap(),
}

op.flagIgnoreListData = op.server.AddPreparedEndpoint("/ignore-list", op.prepareIgnoreListData)
Expand Down
8 changes: 4 additions & 4 deletions operator/hostnameoperator/hostname_operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ func TestHostnameOperatorApplyAdd(t *testing.T) {
}
s.client.On("GetManifestGroup", mock.Anything, leaseID).Return(true, mg, nil)
directive := buildDirective(ev, serviceExpose) // result tested in other unit tests
s.client.On("ConnectHostnameToDeployment", mock.Anything, directive).Return(nil)
s.client.On("ConnectHostnameToDeployment", mock.Anything, directive, mock.Anything).Return(nil)

managed := grabManagedHostnames(t, s.op.server.GetRouter().ServeHTTP)
require.Empty(t, managed)
Expand Down Expand Up @@ -511,7 +511,7 @@ func TestHostnameOperatorApplyAddMultipleServices(t *testing.T) {
}
s.client.On("GetManifestGroup", mock.Anything, leaseID).Return(true, mg, nil)
directive := buildDirective(ev, serviceExpose) // result tested in other unit tests
s.client.On("ConnectHostnameToDeployment", mock.Anything, directive).Return(nil)
s.client.On("ConnectHostnameToDeployment", mock.Anything, directive, mock.Anything).Return(nil)

err := s.op.applyEvent(s.ctx, ev)
require.NoError(t, err)
Expand Down Expand Up @@ -596,9 +596,9 @@ func TestHostnameOperatorApplyUpdate(t *testing.T) {
s.client.On("GetManifestGroup", mock.Anything, secondLeaseID).Return(true, mg2, nil)

directive := buildDirective(ev, serviceExpose) // result tested in other unit tests
s.client.On("ConnectHostnameToDeployment", mock.Anything, directive).Return(nil)
s.client.On("ConnectHostnameToDeployment", mock.Anything, directive, mock.Anything).Return(nil)
secondDirective := buildDirective(secondEv, secondServiceExpose) // result tested in other unit tests
s.client.On("ConnectHostnameToDeployment", mock.Anything, secondDirective).Return(nil)
s.client.On("ConnectHostnameToDeployment", mock.Anything, secondDirective, mock.Anything).Return(nil)

s.client.On("RemoveHostnameFromDeployment", mock.Anything, hostname, leaseID, false).Return(nil)

Expand Down