initialize using a k8s-friendly name derived from full service name

This commit is contained in:
Luke K 2020-04-11 19:30:47 +00:00
parent b75edf2d82
commit a4565d497f
No known key found for this signature in database
GPG Key ID: 4896F75BAF2E1966
3 changed files with 134 additions and 7 deletions

View File

@ -7,6 +7,8 @@ import (
"os"
"os/exec"
"strings"
"github.com/lkingland/faas/k8s"
)
// NameMappings are short-name to repository full name mappings,
@ -39,11 +41,14 @@ func (n *Initializer) Initialize(name, language, path string) error {
// Appsody does not support domain names as the project name
// (ex: www.example.com), and has extremely strict naming requirements
// (only lower case letters, numbers and dashes). So for now replace
// any dots with dashes.
name = strings.ReplaceAll(name, ".", "-")
// (subdomains per rfc 1035). So let's just assume its name must be a valid domain, and
// encode it as a 1035 domain by doubling down on hyphens.
project, err := k8s.ToSubdomain(name)
if err != nil {
return err
}
// Dereference stack short name
// Dereference stack short name. ex. "go" -> "go-ce-functions"
stackName, ok := stackShortNames[language]
if !ok {
languages := []string{}
@ -56,13 +61,12 @@ func (n *Initializer) Initialize(name, language, path string) error {
// set up the command, specifying a sanitized project name and connecting
// standard output and error.
cmd := exec.Command("appsody", "init", "boson/"+stackName, "--project-name", name)
cmd := exec.Command("appsody", "init", "boson/"+stackName, "--project-name", project)
cmd.Dir = path
fmt.Println(cmd)
// If verbose logging is enabled, echo appsody's chatty stdout.
if n.Verbose {
fmt.Println(cmd)
cmd.Stdout = os.Stdout
}

67
k8s/names.go Normal file
View File

@ -0,0 +1,67 @@
package k8s
import (
"errors"
"strings"
"k8s.io/apimachinery/pkg/util/validation"
)
// ToSubdomain converts a domain to a subdomain.
// If the input is not a valid domain an error is thrown.
func ToSubdomain(in string) (string, error) {
if err := validation.IsFullyQualifiedDomainName(nil, in); err != nil {
return "", err.ToAggregate()
}
out := []rune{}
for _, c := range in {
// convert dots to hyphens
if c == '.' {
out = append(out, '-')
} else if c == '-' {
out = append(out, '-')
out = append(out, '-')
} else {
out = append(out, c)
}
}
return string(out), nil
}
// FromSubdomain converts a doman which has been encoded as
// a subdomain using the algorithm of ToSubdoman back to a domain.
// Input errors if not a 1035 label.
func FromSubdomain(in string) (string, error) {
if errs := validation.IsDNS1035Label(in); len(errs) > 0 {
return "", errors.New(strings.Join(errs, ","))
}
rr := []rune(in)
out := []rune{}
for i := 0; i < len(rr); i++ {
c := rr[i]
if c == '-' {
// If the next rune is either nonexistent
// or not also a dash, this is an encoded dot.
if i+1 == len(rr) || rr[i+1] != '-' {
out = append(out, '.')
continue
}
// If the next rune is also a dash, this is
// an escaping dash, so append a slash, and
// increment the pointer such that the next
// loop begins with the next potential tuple.
if rr[i+1] == '-' {
out = append(out, '-')
i++
continue
}
}
out = append(out, c)
}
return string(out), nil
}

56
k8s/names_test.go Normal file
View File

@ -0,0 +1,56 @@
package k8s
import "testing"
// TestToSubdomain ensures that a valid domain name is
// encoded into the expected subdmain.
func TestToSubdomain(t *testing.T) {
cases := []struct {
In string
Out string
Err bool
}{
{"", "", true}, // invalid domain
{"*", "", true}, // invalid domain
{"example", "", true}, // invalid domain
{"example.com", "example-com", false},
{"my-domain.com", "my--domain-com", false},
}
for _, c := range cases {
out, err := ToSubdomain(c.In)
if err != nil && !c.Err {
t.Fatalf("Unexpected error: %v", err)
}
if out != c.Out {
t.Fatalf("expected '%v' to yield '%v', got '%v'", c.In, c.Out, out)
}
}
}
// TestFromSubdomain ensures that a valid subdomain is decoded
// back into a domain.
func TestFromSubdomain(t *testing.T) {
cases := []struct {
In string
Out string
Err bool
}{
{"", "", true}, // invalid subdomain
{"*", "", true}, // invalid subdomain
{"example-com", "example.com", false},
{"my--domain-com", "my-domain.com", false},
{"cdn----1-my--domain-com", "cdn--1.my-domain.com", false},
}
for _, c := range cases {
out, err := FromSubdomain(c.In)
if err != nil && !c.Err {
t.Fatalf("Unexpected error: %v", err)
}
if out != c.Out {
t.Fatalf("expected '%v' to yield '%v', got '%v'", c.In, c.Out, out)
}
}
}