Add options to hsic, ACL and env overrides

Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
Kristoffer Dalby 2022-11-02 11:08:54 +01:00 committed by Juan Font
parent 4f9fe93146
commit aad4c90fe6

View file

@ -21,6 +21,7 @@ import (
const ( const (
hsicHashLength = 6 hsicHashLength = 6
dockerContextPath = "../." dockerContextPath = "../."
aclPolicyPath = "/etc/headscale/acl.hujson"
) )
var errHeadscaleStatusCodeNotOk = errors.New("headscale status code not ok") var errHeadscaleStatusCodeNotOk = errors.New("headscale status code not ok")
@ -32,26 +33,67 @@ type HeadscaleInContainer struct {
pool *dockertest.Pool pool *dockertest.Pool
container *dockertest.Resource container *dockertest.Resource
network *dockertest.Network network *dockertest.Network
// optional config
aclPolicy *headscale.ACLPolicy
env []string
}
type Option = func(c *HeadscaleInContainer)
func WithACLPolicy(acl *headscale.ACLPolicy) Option {
return func(hsic *HeadscaleInContainer) {
hsic.aclPolicy = acl
}
}
func WithConfigEnv(configEnv map[string]string) Option {
return func(hsic *HeadscaleInContainer) {
env := []string{}
for key, value := range configEnv {
env = append(env, fmt.Sprintf("%s=%s", key, value))
}
hsic.env = env
}
} }
func New( func New(
pool *dockertest.Pool, pool *dockertest.Pool,
port int, port int,
network *dockertest.Network, network *dockertest.Network,
opts ...Option,
) (*HeadscaleInContainer, error) { ) (*HeadscaleInContainer, error) {
hash, err := headscale.GenerateRandomStringDNSSafe(hsicHashLength) hash, err := headscale.GenerateRandomStringDNSSafe(hsicHashLength)
if err != nil { if err != nil {
return nil, err return nil, err
} }
hostname := fmt.Sprintf("hs-%s", hash)
portProto := fmt.Sprintf("%d/tcp", port)
hsic := &HeadscaleInContainer{
hostname: hostname,
port: port,
pool: pool,
network: network,
}
for _, opt := range opts {
opt(hsic)
}
if hsic.aclPolicy != nil {
hsic.env = append(hsic.env, fmt.Sprintf("HEADSCALE_ACL_POLICY_PATH=%s", aclPolicyPath))
}
headscaleBuildOptions := &dockertest.BuildOptions{ headscaleBuildOptions := &dockertest.BuildOptions{
Dockerfile: "Dockerfile.debug", Dockerfile: "Dockerfile.debug",
ContextDir: dockerContextPath, ContextDir: dockerContextPath,
} }
hostname := fmt.Sprintf("hs-%s", hash)
portProto := fmt.Sprintf("%d/tcp", port)
runOptions := &dockertest.RunOptions{ runOptions := &dockertest.RunOptions{
Name: hostname, Name: hostname,
ExposedPorts: []string{portProto}, ExposedPorts: []string{portProto},
@ -60,6 +102,7 @@ func New(
// TODO(kradalby): Get rid of this hack, we currently need to give us some // TODO(kradalby): Get rid of this hack, we currently need to give us some
// to inject the headscale configuration further down. // to inject the headscale configuration further down.
Entrypoint: []string{"/bin/bash", "-c", "/bin/sleep 3 ; headscale serve"}, Entrypoint: []string{"/bin/bash", "-c", "/bin/sleep 3 ; headscale serve"},
Env: hsic.env,
} }
// dockertest isnt very good at handling containers that has already // dockertest isnt very good at handling containers that has already
@ -82,20 +125,25 @@ func New(
} }
log.Printf("Created %s container\n", hostname) log.Printf("Created %s container\n", hostname)
hsic := &HeadscaleInContainer{ hsic.container = container
hostname: hostname,
port: port,
pool: pool,
container: container,
network: network,
}
err = hsic.WriteFile("/etc/headscale/config.yaml", []byte(DefaultConfigYAML())) err = hsic.WriteFile("/etc/headscale/config.yaml", []byte(DefaultConfigYAML()))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to write headscale config to container: %w", err) return nil, fmt.Errorf("failed to write headscale config to container: %w", err)
} }
if hsic.aclPolicy != nil {
data, err := json.Marshal(hsic.aclPolicy)
if err != nil {
return nil, fmt.Errorf("failed to marshal ACL Policy to JSON: %w", err)
}
err = hsic.WriteFile(aclPolicyPath, data)
if err != nil {
return nil, fmt.Errorf("failed to write ACL policy to container: %w", err)
}
}
return hsic, nil return hsic, nil
} }