diff --git a/cmd/tailscaled/tailscaled.openrc b/cmd/tailscaled/tailscaled.openrc new file mode 100755 index 000000000..bc6936fa1 --- /dev/null +++ b/cmd/tailscaled/tailscaled.openrc @@ -0,0 +1,23 @@ +#!/sbin/openrc-run + +source /etc/default/tailscaled + +command="/usr/sbin/tailscaled" +command_args="--state=/var/lib/tailscale/tailscaled.state --port=$PORT --socket=/var/run/tailscale/tailscaled.sock $FLAGS" +command_background=true +pidfile="/run/tailscaled.pid" +start_stop_daemon_args="-1 /var/log/tailscaled.log -2 /var/log/tailscaled.log" + +depend() { + need net +} + +start_pre() { + mkdir -p /var/run/tailscale + mkdir -p /var/lib/tailscale + $command --cleanup +} + +stop_post() { + $command --cleanup +} diff --git a/tstest/integration/vms/vms_test.go b/tstest/integration/vms/vms_test.go index a1f0f2208..1a7664035 100644 --- a/tstest/integration/vms/vms_test.go +++ b/tstest/integration/vms/vms_test.go @@ -67,6 +67,7 @@ type Distro struct { sha256sum string // hex-encoded sha256 sum of contents of URL mem int // VM memory in megabytes packageManager string // yum/apt/dnf/zypper + initSystem string // systemd/openrc } func (d *Distro) InstallPre() string { @@ -85,7 +86,8 @@ func (d *Distro) InstallPre() string { - [ apt-get, "-y", install, curl, "apt-transport-https", gnupg2 ]` case "apk": - return ` - [ apk, "-U", add, curl, "ca-certificates" ]` + return ` - [ apk, "-U", add, curl, "ca-certificates", iptables ] + - [ modprobe, tun ]` } return "" @@ -111,8 +113,8 @@ func TestDownloadImages(t *testing.T) { } var distros = []Distro{ - // NOTE(Xe): If you run into issues getting the autoconfig to work, comment - // out all the other distros and uncomment this one. Connect with a VNC + // NOTE(Xe): If you run into issues getting the autoconfig to work, run + // this test with the flag `--distro-regex=alpine-edge`. Connect with a VNC // client with a command like this: // // $ vncviewer :0 @@ -124,24 +126,36 @@ var distros = []Distro{ // Login as root with the password root. Then look in // /var/log/cloud-init-output.log for what you messed up. - // {"alpine-edge", "https://xena.greedo.xeserv.us/pkg/alpine/img/alpine-edge-2021-05-18-cloud-init-within.qcow2", "b3bb15311c0bd3beffa1b554f022b75d3b7309b5fdf76fb146fe7c72b83b16d0", 256, "apk"}, + // NOTE(Xe): These images are not official images created by the Alpine Linux + // cloud team because the cloud team hasn't created any official images yet. + // These images were created under the guidance of the cloud team and contain + // few notable differences from what they would end up shipping. The Alpine + // Linux cloud team probably won't have official images up until a year or so + // after this comment is written (2021-06-11), but overall they will be + // compatible with these images. These images were created using the setup in + // this repo: https://github.com/Xe/alpine-image. I hereby promise to not break + // these links. + {"alpine-3-13-5", "https://xena.greedo.xeserv.us/pkg/alpine/img/alpine-3.13.5-cloud-init-within.qcow2", "a2665c16724e75899723e81d81126bd0254a876e5de286b0b21553734baec287", 256, "apk", "openrc"}, + {"alpine-edge", "https://xena.greedo.xeserv.us/pkg/alpine/img/alpine-edge-2021-05-18-cloud-init-within.qcow2", "b3bb15311c0bd3beffa1b554f022b75d3b7309b5fdf76fb146fe7c72b83b16d0", 256, "apk", "openrc"}, - {"amazon-linux", "https://cdn.amazonlinux.com/os-images/2.0.20210427.0/kvm/amzn2-kvm-2.0.20210427.0-x86_64.xfs.gpt.qcow2", "6ef9daef32cec69b2d0088626ec96410cd24afc504d57278bbf2f2ba2b7e529b", 512, "yum"}, - {"arch", "https://mirror.pkgbuild.com/images/v20210515.22945/Arch-Linux-x86_64-cloudimg-20210515.22945.qcow2", "e4077f5ba3c5d545478f64834bc4852f9f7a2e05950fce8ecd0df84193162a27", 512, "pacman"}, - {"centos-7", "https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-2003.qcow2c", "b7555ecf90b24111f2efbc03c1e80f7b38f1e1fc7e1b15d8fee277d1a4575e87", 512, "yum"}, - {"centos-8", "https://cloud.centos.org/centos/8/x86_64/images/CentOS-8-GenericCloud-8.3.2011-20201204.2.x86_64.qcow2", "7ec97062618dc0a7ebf211864abf63629da1f325578868579ee70c495bed3ba0", 768, "dnf"}, - {"debian-9", "http://cloud.debian.org/images/cloud/OpenStack/9.13.22-20210531/debian-9.13.22-20210531-openstack-amd64.qcow2", "c36e25f2ab0b5be722180db42ed9928476812f02d053620e1c287f983e9f6f1d", 512, "apt"}, - {"debian-10", "https://cdimage.debian.org/images/cloud/buster/20210329-591/debian-10-generic-amd64-20210329-591.qcow2", "70c61956095870c4082103d1a7a1cb5925293f8405fc6cb348588ec97e8611b0", 768, "apt"}, - {"fedora-34", "https://download.fedoraproject.org/pub/fedora/linux/releases/34/Cloud/x86_64/images/Fedora-Cloud-Base-34-1.2.x86_64.qcow2", "b9b621b26725ba95442d9a56cbaa054784e0779a9522ec6eafff07c6e6f717ea", 768, "dnf"}, - {"opensuse-leap-15-1", "https://download.opensuse.org/repositories/Cloud:/Images:/Leap_15.1/images/openSUSE-Leap-15.1-OpenStack.x86_64.qcow2", "40bc72b8ee143364fc401f2c9c9a11ecb7341a29fa84c6f7bf42fc94acf19a02", 512, "zypper"}, - {"opensuse-leap-15-2", "https://download.opensuse.org/repositories/Cloud:/Images:/Leap_15.2/images/openSUSE-Leap-15.2-OpenStack.x86_64.qcow2", "4df9cee9281d1f57d20f79dc65d76e255592b904760e73c0dd44ac753a54330f", 512, "zypper"}, - {"opensuse-leap-15-3", "http://mirror.its.dal.ca/opensuse/distribution/leap/15.3/appliances/openSUSE-Leap-15.3-JeOS.x86_64-OpenStack-Cloud.qcow2", "22e0392e4d0becb523d1bc5f709366140b7ee20d6faf26de3d0f9046d1ee15d5", 512, "zypper"}, - {"opensuse-tumbleweed", "https://download.opensuse.org/tumbleweed/appliances/openSUSE-Tumbleweed-JeOS.x86_64-OpenStack-Cloud.qcow2", "79e610bba3ed116556608f031c06e4b9260e3be2b193ce1727914ba213afac3f", 512, "zypper"}, - {"ubuntu-16-04", "https://cloud-images.ubuntu.com/xenial/20210429/xenial-server-cloudimg-amd64-disk1.img", "50a21bc067c05e0c73bf5d8727ab61152340d93073b3dc32eff18b626f7d813b", 512, "apt"}, - {"ubuntu-18-04", "https://cloud-images.ubuntu.com/bionic/20210526/bionic-server-cloudimg-amd64.img", "389ffd5d36bbc7a11bf384fd217cda9388ccae20e5b0cb7d4516733623c96022", 512, "apt"}, - {"ubuntu-20-04", "https://cloud-images.ubuntu.com/focal/20210603/focal-server-cloudimg-amd64.img", "1c0969323b058ba8b91fec245527069c2f0502fc119b9138b213b6bfebd965cb", 512, "apt"}, - {"ubuntu-20-10", "https://cloud-images.ubuntu.com/groovy/20210604/groovy-server-cloudimg-amd64.img", "2196df5f153faf96443e5502bfdbcaa0baaefbaec614348fec344a241855b0ef", 512, "apt"}, - {"ubuntu-21-04", "https://cloud-images.ubuntu.com/hirsute/20210603/hirsute-server-cloudimg-amd64.img", "bf07f36fc99ff521d3426e7d257e28f0c81feebc9780b0c4f4e25ae594ff4d3b", 512, "apt"}, + // NOTE(Xe): All of the following images are official images straight from each + // distribution's official documentation. + {"amazon-linux", "https://cdn.amazonlinux.com/os-images/2.0.20210427.0/kvm/amzn2-kvm-2.0.20210427.0-x86_64.xfs.gpt.qcow2", "6ef9daef32cec69b2d0088626ec96410cd24afc504d57278bbf2f2ba2b7e529b", 512, "yum", "systemd"}, + {"arch", "https://mirror.pkgbuild.com/images/v20210515.22945/Arch-Linux-x86_64-cloudimg-20210515.22945.qcow2", "e4077f5ba3c5d545478f64834bc4852f9f7a2e05950fce8ecd0df84193162a27", 512, "pacman", "systemd"}, + {"centos-7", "https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-2003.qcow2c", "b7555ecf90b24111f2efbc03c1e80f7b38f1e1fc7e1b15d8fee277d1a4575e87", 512, "yum", "systemd"}, + {"centos-8", "https://cloud.centos.org/centos/8/x86_64/images/CentOS-8-GenericCloud-8.3.2011-20201204.2.x86_64.qcow2", "7ec97062618dc0a7ebf211864abf63629da1f325578868579ee70c495bed3ba0", 768, "dnf", "systemd"}, + {"debian-9", "http://cloud.debian.org/images/cloud/OpenStack/9.13.22-20210531/debian-9.13.22-20210531-openstack-amd64.qcow2", "c36e25f2ab0b5be722180db42ed9928476812f02d053620e1c287f983e9f6f1d", 512, "apt", "systemd"}, + {"debian-10", "https://cdimage.debian.org/images/cloud/buster/20210329-591/debian-10-generic-amd64-20210329-591.qcow2", "70c61956095870c4082103d1a7a1cb5925293f8405fc6cb348588ec97e8611b0", 768, "apt", "systemd"}, + {"fedora-34", "https://download.fedoraproject.org/pub/fedora/linux/releases/34/Cloud/x86_64/images/Fedora-Cloud-Base-34-1.2.x86_64.qcow2", "b9b621b26725ba95442d9a56cbaa054784e0779a9522ec6eafff07c6e6f717ea", 768, "dnf", "systemd"}, + {"opensuse-leap-15-1", "https://download.opensuse.org/repositories/Cloud:/Images:/Leap_15.1/images/openSUSE-Leap-15.1-OpenStack.x86_64.qcow2", "40bc72b8ee143364fc401f2c9c9a11ecb7341a29fa84c6f7bf42fc94acf19a02", 512, "zypper", "systemd"}, + {"opensuse-leap-15-2", "https://download.opensuse.org/repositories/Cloud:/Images:/Leap_15.2/images/openSUSE-Leap-15.2-OpenStack.x86_64.qcow2", "4df9cee9281d1f57d20f79dc65d76e255592b904760e73c0dd44ac753a54330f", 512, "zypper", "systemd"}, + {"opensuse-leap-15-3", "http://mirror.its.dal.ca/opensuse/distribution/leap/15.3/appliances/openSUSE-Leap-15.3-JeOS.x86_64-OpenStack-Cloud.qcow2", "22e0392e4d0becb523d1bc5f709366140b7ee20d6faf26de3d0f9046d1ee15d5", 512, "zypper", "systemd"}, + {"opensuse-tumbleweed", "https://download.opensuse.org/tumbleweed/appliances/openSUSE-Tumbleweed-JeOS.x86_64-OpenStack-Cloud.qcow2", "79e610bba3ed116556608f031c06e4b9260e3be2b193ce1727914ba213afac3f", 512, "zypper", "systemd"}, + {"ubuntu-16-04", "https://cloud-images.ubuntu.com/xenial/20210429/xenial-server-cloudimg-amd64-disk1.img", "50a21bc067c05e0c73bf5d8727ab61152340d93073b3dc32eff18b626f7d813b", 512, "apt", "systemd"}, + {"ubuntu-18-04", "https://cloud-images.ubuntu.com/bionic/20210526/bionic-server-cloudimg-amd64.img", "389ffd5d36bbc7a11bf384fd217cda9388ccae20e5b0cb7d4516733623c96022", 512, "apt", "systemd"}, + {"ubuntu-20-04", "https://cloud-images.ubuntu.com/focal/20210603/focal-server-cloudimg-amd64.img", "1c0969323b058ba8b91fec245527069c2f0502fc119b9138b213b6bfebd965cb", 512, "apt", "systemd"}, + {"ubuntu-20-10", "https://cloud-images.ubuntu.com/groovy/20210604/groovy-server-cloudimg-amd64.img", "2196df5f153faf96443e5502bfdbcaa0baaefbaec614348fec344a241855b0ef", 512, "apt", "systemd"}, + {"ubuntu-21-04", "https://cloud-images.ubuntu.com/hirsute/20210603/hirsute-server-cloudimg-amd64.img", "bf07f36fc99ff521d3426e7d257e28f0c81feebc9780b0c4f4e25ae594ff4d3b", 512, "apt", "systemd"}, } // fetchFromS3 fetches a distribution image from Amazon S3 or reports whether @@ -589,13 +603,13 @@ func TestVMIntegrationEndToEnd(t *testing.T) { } }) - testDistro(t, loginServer, signer, ipm, bins) + testDistro(t, loginServer, distro, signer, ipm, bins) }) } }) } -func testDistro(t *testing.T, loginServer string, signer ssh.Signer, ipm ipMapping, bins *integration.Binaries) { +func testDistro(t *testing.T, loginServer string, d Distro, signer ssh.Signer, ipm ipMapping, bins *integration.Binaries) { t.Helper() port := ipm.port hostport := fmt.Sprintf("127.0.0.1:%d", port) @@ -631,11 +645,18 @@ func testDistro(t *testing.T, loginServer string, signer ssh.Signer, ipm ipMappi if err != nil { t.Fatal(err) } - copyBinaries(t, cli, bins) + copyBinaries(t, d, cli, bins) - timeout := 5 * time.Minute + timeout := 30 * time.Second - e, _, err := expect.SpawnSSH(cli, timeout, expect.Verbose(true), expect.VerboseWriter(log.Writer())) + e, _, err := expect.SpawnSSH(cli, timeout, + expect.Verbose(true), + expect.VerboseWriter(log.Writer()), + + // // NOTE(Xe): if you get a timeout, uncomment this line to have the raw + // output be sent to the test log quicker. + //expect.Tee(nopWriteCloser{log.Writer()}), + ) if err != nil { t.Fatalf("%d: can't register a shell session: %v", port, err) } @@ -648,7 +669,17 @@ func testDistro(t *testing.T, loginServer string, signer ssh.Signer, ipm ipMappi t.Fatalf("%d: can't get a shell: %v", port, err) } t.Logf("got shell for %d", port) - err = e.Send("systemctl start tailscaled.service\n") + switch d.initSystem { + case "openrc": + // NOTE(Xe): this is a sin, however openrc doesn't really have the concept + // of service readiness. If this sleep is removed then tailscale will not be + // ready once the `tailscale up` command is sent. This is not ideal, but I + // am not really sure there is a good way around this without a delay of + // some kind. + err = e.Send("rc-service tailscaled start && sleep 2\n") + case "systemd": + err = e.Send("systemctl start tailscaled.service\n") + } if err != nil { t.Fatalf("can't send command to start tailscaled: %v", err) } @@ -656,7 +687,7 @@ func testDistro(t *testing.T, loginServer string, signer ssh.Signer, ipm ipMappi if err != nil { t.Fatalf("%d: can't get a shell: %v", port, err) } - err = e.Send(fmt.Sprintf("sudo tailscale up --login-server %s\n", loginServer)) + err = e.Send(fmt.Sprintf("tailscale up --login-server %s\n", loginServer)) if err != nil { t.Fatalf("%d: can't send tailscale up command: %v", port, err) } @@ -666,7 +697,7 @@ func testDistro(t *testing.T, loginServer string, signer ssh.Signer, ipm ipMappi } } -func copyBinaries(t *testing.T, conn *ssh.Client, bins *integration.Binaries) { +func copyBinaries(t *testing.T, d Distro, conn *ssh.Client, bins *integration.Binaries) { cli, err := sftp.NewClient(conn) if err != nil { t.Fatalf("can't connect over sftp to copy binaries: %v", err) @@ -674,16 +705,23 @@ func copyBinaries(t *testing.T, conn *ssh.Client, bins *integration.Binaries) { mkdir(t, cli, "/usr/bin") mkdir(t, cli, "/usr/sbin") - mkdir(t, cli, "/etc/systemd/system") mkdir(t, cli, "/etc/default") + mkdir(t, cli, "/var/lib/tailscale") copyFile(t, cli, bins.Daemon, "/usr/sbin/tailscaled") copyFile(t, cli, bins.CLI, "/usr/bin/tailscale") - // TODO(Xe): revisit this life decision, hopefully before this assumption - // breaks the test. + // TODO(Xe): revisit this assumption before it breaks the test. copyFile(t, cli, "../../../cmd/tailscaled/tailscaled.defaults", "/etc/default/tailscaled") - copyFile(t, cli, "../../../cmd/tailscaled/tailscaled.service", "/etc/systemd/system/tailscaled.service") + + switch d.initSystem { + case "openrc": + mkdir(t, cli, "/etc/init.d") + copyFile(t, cli, "../../../cmd/tailscaled/tailscaled.openrc", "/etc/init.d/tailscaled") + case "systemd": + mkdir(t, cli, "/etc/systemd/system") + copyFile(t, cli, "../../../cmd/tailscaled/tailscaled.service", "/etc/systemd/system/tailscaled.service") + } t.Log("tailscale installed!") } @@ -767,6 +805,14 @@ func TestDeriveBindhost(t *testing.T) { t.Log(deriveBindhost(t)) } +//lint:ignore U1000 Xe: used when debugging the virtual machines +type nopWriteCloser struct { + io.Writer +} + +//lint:ignore U1000 Xe: used when debugging the virtual machines +func (nwc nopWriteCloser) Close() error { return nil } + const metaDataTemplate = `instance-id: {{.ID}} local-hostname: {{.Hostname}}`