mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 19:15:34 +00:00
release/dist/synology: build synology packages with cmd/dist
Updates #8217 Signed-off-by: David Anderson <danderson@tailscale.com>
This commit is contained in:
parent
399a80785e
commit
32e0ba5e68
5
Makefile
5
Makefile
@ -48,11 +48,10 @@ staticcheck: ## Run staticcheck.io checks
|
|||||||
./tool/go run honnef.co/go/tools/cmd/staticcheck -- $$(./tool/go list ./... | grep -v tempfork)
|
./tool/go run honnef.co/go/tools/cmd/staticcheck -- $$(./tool/go list ./... | grep -v tempfork)
|
||||||
|
|
||||||
spk: ## Build synology package for ${SYNO_ARCH} architecture and ${SYNO_DSM} DSM version
|
spk: ## Build synology package for ${SYNO_ARCH} architecture and ${SYNO_DSM} DSM version
|
||||||
PATH="${PWD}/tool:${PATH}" ./tool/go run github.com/tailscale/tailscale-synology@main -o tailscale.spk --source=. --goarch=${SYNO_ARCH} --dsm-version=${SYNO_DSM}
|
./tool/go run ./cmd/dist build synology/dsm${SYNO_DSM}/${SYNO_ARCH}
|
||||||
|
|
||||||
spkall: ## Build synology packages for all architectures and DSM versions
|
spkall: ## Build synology packages for all architectures and DSM versions
|
||||||
mkdir -p spks
|
./tool/go run ./cmd/dist build synology
|
||||||
PATH="${PWD}/tool:${PATH}" ./tool/go run github.com/tailscale/tailscale-synology@main -o spks --source=. --goarch=all --dsm-version=all
|
|
||||||
|
|
||||||
pushspk: spk ## Push and install synology package on ${SYNO_HOST} host
|
pushspk: spk ## Push and install synology package on ${SYNO_HOST} host
|
||||||
echo "Pushing SPK to root@${SYNO_HOST} (env var SYNO_HOST) ..."
|
echo "Pushing SPK to root@${SYNO_HOST} (env var SYNO_HOST) ..."
|
||||||
|
25
cmd/dist/dist.go
vendored
25
cmd/dist/dist.go
vendored
@ -13,15 +13,38 @@
|
|||||||
|
|
||||||
"tailscale.com/release/dist"
|
"tailscale.com/release/dist"
|
||||||
"tailscale.com/release/dist/cli"
|
"tailscale.com/release/dist/cli"
|
||||||
|
"tailscale.com/release/dist/synology"
|
||||||
"tailscale.com/release/dist/unixpkgs"
|
"tailscale.com/release/dist/unixpkgs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var synologyPackageCenter bool
|
||||||
|
|
||||||
func getTargets() ([]dist.Target, error) {
|
func getTargets() ([]dist.Target, error) {
|
||||||
return unixpkgs.Targets(), nil
|
var ret []dist.Target
|
||||||
|
|
||||||
|
ret = append(ret, unixpkgs.Targets()...)
|
||||||
|
// Synology packages can be built either for sideloading, or for
|
||||||
|
// distribution by Synology in their package center. When
|
||||||
|
// distributed through the package center, apps can request
|
||||||
|
// additional permissions to use a tuntap interface and control
|
||||||
|
// the NAS's network stack, rather than be forced to run in
|
||||||
|
// userspace mode.
|
||||||
|
//
|
||||||
|
// Since only we can provide packages to Synology for
|
||||||
|
// distribution, we default to building the "sideload" variant of
|
||||||
|
// packages that we distribute on pkgs.tailscale.com.
|
||||||
|
ret = append(ret, synology.Targets(synologyPackageCenter)...)
|
||||||
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cmd := cli.CLI(getTargets)
|
cmd := cli.CLI(getTargets)
|
||||||
|
for _, subcmd := range cmd.Subcommands {
|
||||||
|
if subcmd.Name == "build" {
|
||||||
|
subcmd.FlagSet.BoolVar(&synologyPackageCenter, "synology-package-center", false, "build synology packages with extra metadata for the official package center")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := cmd.ParseAndRun(context.Background(), os.Args[1:]); err != nil && !errors.Is(err, flag.ErrHelp) {
|
if err := cmd.ParseAndRun(context.Background(), os.Args[1:]); err != nil && !errors.Is(err, flag.ErrHelp) {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
7
release/dist/dist.go
vendored
7
release/dist/dist.go
vendored
@ -17,6 +17,7 @@
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"tailscale.com/util/multierr"
|
"tailscale.com/util/multierr"
|
||||||
"tailscale.com/version/mkversion"
|
"tailscale.com/version/mkversion"
|
||||||
@ -44,6 +45,8 @@ type Build struct {
|
|||||||
Go string
|
Go string
|
||||||
// Version is the version info of the build.
|
// Version is the version info of the build.
|
||||||
Version mkversion.VersionInfo
|
Version mkversion.VersionInfo
|
||||||
|
// Time is the timestamp of the build.
|
||||||
|
Time time.Time
|
||||||
|
|
||||||
// once is a cache of function invocations that should run once per process
|
// once is a cache of function invocations that should run once per process
|
||||||
// (for example building a helper docker container)
|
// (for example building a helper docker container)
|
||||||
@ -86,6 +89,7 @@ func NewBuild(repo, out string) (*Build, error) {
|
|||||||
Out: out,
|
Out: out,
|
||||||
Go: goTool,
|
Go: goTool,
|
||||||
Version: mkversion.Info(),
|
Version: mkversion.Info(),
|
||||||
|
Time: time.Now().UTC(),
|
||||||
extra: map[any]any{},
|
extra: map[any]any{},
|
||||||
goBuildLimit: make(chan struct{}, runtime.NumCPU()),
|
goBuildLimit: make(chan struct{}, runtime.NumCPU()),
|
||||||
}
|
}
|
||||||
@ -114,6 +118,9 @@ func (b *Build) Build(targets []Target) (files []string, err error) {
|
|||||||
go func(i int, t Target) {
|
go func(i int, t Target) {
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("%s: %w", t, err)
|
||||||
|
}
|
||||||
errs[i] = err
|
errs[i] = err
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
|
BIN
release/dist/synology/files/PACKAGE_ICON.PNG
vendored
Normal file
BIN
release/dist/synology/files/PACKAGE_ICON.PNG
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
BIN
release/dist/synology/files/PACKAGE_ICON_256.PNG
vendored
Normal file
BIN
release/dist/synology/files/PACKAGE_ICON_256.PNG
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
6
release/dist/synology/files/Tailscale.sc
vendored
Normal file
6
release/dist/synology/files/Tailscale.sc
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[Tailscale]
|
||||||
|
title="Tailscale"
|
||||||
|
desc="Tailscale VPN"
|
||||||
|
port_forward="no"
|
||||||
|
src.ports="41641/udp"
|
||||||
|
dst.ports="41641/udp"
|
12
release/dist/synology/files/config
vendored
Normal file
12
release/dist/synology/files/config
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
".url": {
|
||||||
|
"SYNO.SDS.Tailscale": {
|
||||||
|
"type": "url",
|
||||||
|
"version": "1.8.3",
|
||||||
|
"title": "Tailscale",
|
||||||
|
"icon": "PACKAGE_ICON_256.PNG",
|
||||||
|
"url": "webman/3rdparty/Tailscale/",
|
||||||
|
"urlTarget": "_syno_tailscale"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
release/dist/synology/files/index.cgi
vendored
Executable file
2
release/dist/synology/files/index.cgi
vendored
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
exec /var/packages/Tailscale/target/bin/tailscale web -cgi
|
8
release/dist/synology/files/logrotate-dsm6
vendored
Normal file
8
release/dist/synology/files/logrotate-dsm6
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/var/packages/Tailscale/etc/tailscaled.stdout.log {
|
||||||
|
size 10M
|
||||||
|
rotate 3
|
||||||
|
missingok
|
||||||
|
copytruncate
|
||||||
|
compress
|
||||||
|
notifempty
|
||||||
|
}
|
8
release/dist/synology/files/logrotate-dsm7
vendored
Normal file
8
release/dist/synology/files/logrotate-dsm7
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/var/packages/Tailscale/var/tailscaled.stdout.log {
|
||||||
|
size 10M
|
||||||
|
rotate 3
|
||||||
|
missingok
|
||||||
|
copytruncate
|
||||||
|
compress
|
||||||
|
notifempty
|
||||||
|
}
|
7
release/dist/synology/files/privilege-dsm6
vendored
Normal file
7
release/dist/synology/files/privilege-dsm6
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"defaults":{
|
||||||
|
"run-as": "root"
|
||||||
|
},
|
||||||
|
"username": "tailscale",
|
||||||
|
"groupname": "tailscale"
|
||||||
|
}
|
7
release/dist/synology/files/privilege-dsm7
vendored
Normal file
7
release/dist/synology/files/privilege-dsm7
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"defaults":{
|
||||||
|
"run-as": "package"
|
||||||
|
},
|
||||||
|
"username": "tailscale",
|
||||||
|
"groupname": "tailscale"
|
||||||
|
}
|
13
release/dist/synology/files/privilege-dsm7.for-package-center
vendored
Normal file
13
release/dist/synology/files/privilege-dsm7.for-package-center
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"defaults":{
|
||||||
|
"run-as": "package"
|
||||||
|
},
|
||||||
|
"username": "tailscale",
|
||||||
|
"groupname": "tailscale",
|
||||||
|
"tool": [{
|
||||||
|
"relpath": "bin/tailscaled",
|
||||||
|
"user": "package",
|
||||||
|
"group": "package",
|
||||||
|
"capabilities": "cap_net_admin,cap_chown,cap_net_raw"
|
||||||
|
}]
|
||||||
|
}
|
11
release/dist/synology/files/resource
vendored
Normal file
11
release/dist/synology/files/resource
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"port-config": {
|
||||||
|
"protocol-file": "conf/Tailscale.sc"
|
||||||
|
},
|
||||||
|
"usr-local-linker": {
|
||||||
|
"bin": ["bin/tailscale"]
|
||||||
|
},
|
||||||
|
"syslog-config": {
|
||||||
|
"logrotate-relpath": "conf/logrotate.conf"
|
||||||
|
}
|
||||||
|
}
|
3
release/dist/synology/files/scripts/postupgrade
vendored
Normal file
3
release/dist/synology/files/scripts/postupgrade
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
exit 0
|
3
release/dist/synology/files/scripts/preupgrade
vendored
Normal file
3
release/dist/synology/files/scripts/preupgrade
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
exit 0
|
129
release/dist/synology/files/scripts/start-stop-status
vendored
Executable file
129
release/dist/synology/files/scripts/start-stop-status
vendored
Executable file
@ -0,0 +1,129 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SERVICE_NAME="tailscale"
|
||||||
|
|
||||||
|
if [ "${SYNOPKG_DSM_VERSION_MAJOR}" -eq "6" ]; then
|
||||||
|
PKGVAR="/var/packages/Tailscale/etc"
|
||||||
|
else
|
||||||
|
PKGVAR="${SYNOPKG_PKGVAR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PID_FILE="${PKGVAR}/tailscaled.pid"
|
||||||
|
LOG_FILE="${PKGVAR}/tailscaled.stdout.log"
|
||||||
|
STATE_FILE="${PKGVAR}/tailscaled.state"
|
||||||
|
SOCKET_FILE="${PKGVAR}/tailscaled.sock"
|
||||||
|
PORT="41641"
|
||||||
|
|
||||||
|
SERVICE_COMMAND="${SYNOPKG_PKGDEST}/bin/tailscaled \
|
||||||
|
--state=${STATE_FILE} \
|
||||||
|
--socket=${SOCKET_FILE} \
|
||||||
|
--port=$PORT"
|
||||||
|
|
||||||
|
if [ "${SYNOPKG_DSM_VERSION_MAJOR}" -eq "7" -a ! -e "/dev/net/tun" ]; then
|
||||||
|
# TODO(maisem/crawshaw): Disable the tun device in DSM7 for now.
|
||||||
|
SERVICE_COMMAND="${SERVICE_COMMAND} --tun=userspace-networking"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${SYNOPKG_DSM_VERSION_MAJOR}" -eq "6" ]; then
|
||||||
|
chown -R tailscale:tailscale "${PKGVAR}/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
start_daemon() {
|
||||||
|
local ts=$(date --iso-8601=second)
|
||||||
|
echo "${ts} Starting ${SERVICE_NAME} with: ${SERVICE_COMMAND}" >${LOG_FILE}
|
||||||
|
STATE_DIRECTORY=${PKGVAR} ${SERVICE_COMMAND} 2>&1 | sed -u '1,200p;201s,.*,[further tailscaled logs suppressed],p;d' >>${LOG_FILE} &
|
||||||
|
# We pipe tailscaled's output to sed, so "$!" retrieves the PID of sed not tailscaled.
|
||||||
|
# Use jobs -p to retrieve the PID of the most recent process group leader.
|
||||||
|
jobs -p >"${PID_FILE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_daemon() {
|
||||||
|
if [ -r "${PID_FILE}" ]; then
|
||||||
|
local PID=$(cat "${PID_FILE}")
|
||||||
|
local ts=$(date --iso-8601=second)
|
||||||
|
echo "${ts} Stopping ${SERVICE_NAME} service PID=${PID}" >>${LOG_FILE}
|
||||||
|
kill -TERM $PID >>${LOG_FILE} 2>&1
|
||||||
|
wait_for_status 1 || kill -KILL $PID >>${LOG_FILE} 2>&1
|
||||||
|
rm -f "${PID_FILE}" >/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
daemon_status() {
|
||||||
|
if [ -r "${PID_FILE}" ]; then
|
||||||
|
local PID=$(cat "${PID_FILE}")
|
||||||
|
if ps -o pid -p ${PID} > /dev/null; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
rm -f "${PID_FILE}" >/dev/null
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_status() {
|
||||||
|
# 20 tries
|
||||||
|
# sleeps for 1 second after each try
|
||||||
|
local counter=20
|
||||||
|
while [ ${counter} -gt 0 ]; do
|
||||||
|
daemon_status
|
||||||
|
[ $? -eq $1 ] && return
|
||||||
|
counter=$((counter - 1))
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_tun_created() {
|
||||||
|
if [ "${SYNOPKG_DSM_VERSION_MAJOR}" -eq "7" ]; then
|
||||||
|
# TODO(maisem/crawshaw): Disable the tun device in DSM7 for now.
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
# Create the necessary file structure for /dev/net/tun
|
||||||
|
if ([ ! -c /dev/net/tun ]); then
|
||||||
|
if ([ ! -d /dev/net ]); then
|
||||||
|
mkdir -m 755 /dev/net
|
||||||
|
fi
|
||||||
|
mknod /dev/net/tun c 10 200
|
||||||
|
chmod 0755 /dev/net/tun
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Load the tun module if not already loaded
|
||||||
|
if (!(lsmod | grep -q "^tun\s")); then
|
||||||
|
insmod /lib/modules/tun.ko
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
start)
|
||||||
|
if daemon_status; then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
ensure_tun_created
|
||||||
|
start_daemon
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
if daemon_status; then
|
||||||
|
stop_daemon
|
||||||
|
exit $?
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
if daemon_status; then
|
||||||
|
echo "${SERVICE_NAME} is running"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "${SERVICE_NAME} is not running"
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
log)
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "command $1 is not implemented"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
306
release/dist/synology/pkgs.go
vendored
Normal file
306
release/dist/synology/pkgs.go
vendored
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
// Package synology contains dist Targets for building Synology Tailscale packages.
|
||||||
|
package synology
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tailscale.com/release/dist"
|
||||||
|
)
|
||||||
|
|
||||||
|
type target struct {
|
||||||
|
filenameArch string
|
||||||
|
dsmMajorVersion int
|
||||||
|
goenv map[string]string
|
||||||
|
packageCenter bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *target) String() string {
|
||||||
|
return fmt.Sprintf("synology/dsm%d/%s", t.dsmMajorVersion, t.filenameArch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *target) Build(b *dist.Build) ([]string, error) {
|
||||||
|
inner, err := getSynologyBuilds(b).buildInnerPackage(b, t.dsmMajorVersion, t.goenv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := t.buildSPK(b, inner)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return []string{out}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *target) buildSPK(b *dist.Build, inner *innerPkg) (string, error) {
|
||||||
|
filename := fmt.Sprintf("tailscale-%s-%s-%d-dsm%d.spk", t.filenameArch, b.Version.Short, b.Version.Synology[t.dsmMajorVersion], t.dsmMajorVersion)
|
||||||
|
out := filepath.Join(b.Out, filename)
|
||||||
|
log.Printf("Building %s", filename)
|
||||||
|
|
||||||
|
privFile := fmt.Sprintf("privilege-dsm%d", t.dsmMajorVersion)
|
||||||
|
if t.packageCenter && t.dsmMajorVersion == 7 {
|
||||||
|
privFile += ".for-package-center"
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Create(out)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
tw := tar.NewWriter(f)
|
||||||
|
defer tw.Close()
|
||||||
|
|
||||||
|
err = writeTar(tw, b.Time,
|
||||||
|
memFile("INFO", t.mkInfo(b, inner.uncompressedSz), 0644),
|
||||||
|
static("PACKAGE_ICON.PNG", "PACKAGE_ICON.PNG", 0644),
|
||||||
|
static("PACKAGE_ICON_256.PNG", "PACKAGE_ICON_256.PNG", 0644),
|
||||||
|
static("Tailscale.sc", "Tailscale.sc", 0644),
|
||||||
|
dir("conf"),
|
||||||
|
static("resource", "conf/resource", 0644),
|
||||||
|
static(privFile, "conf/privilege", 0644),
|
||||||
|
file(inner.path, "package.tgz", 0644),
|
||||||
|
dir("scripts"),
|
||||||
|
static("scripts/start-stop-status", "scripts/start-stop-status", 0644),
|
||||||
|
static("scripts/postupgrade", "scripts/postupgrade", 0644),
|
||||||
|
static("scripts/preupgrade", "scripts/preupgrade", 0644),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tw.Close(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *target) mkInfo(b *dist.Build, uncompressedSz int64) []byte {
|
||||||
|
var ret bytes.Buffer
|
||||||
|
f := func(k, v string) {
|
||||||
|
fmt.Fprintf(&ret, "%s=%q\n", k, v)
|
||||||
|
}
|
||||||
|
f("package", "Tailscale")
|
||||||
|
f("version", fmt.Sprintf("%s-%d", b.Version.Short, b.Version.Synology[t.dsmMajorVersion]))
|
||||||
|
f("arch", t.filenameArch)
|
||||||
|
f("description", "Connect all your devices using WireGuard, without the hassle.")
|
||||||
|
f("displayname", "Tailscale")
|
||||||
|
f("maintainer", "Tailscale, Inc.")
|
||||||
|
f("maintainer_url", "https://github.com/tailscale/tailscale")
|
||||||
|
f("create_time", b.Time.Format("20060102-15:04:05"))
|
||||||
|
f("dsmuidir", "ui")
|
||||||
|
f("dsmappname", "SYNO.SDS.Tailscale")
|
||||||
|
f("startstop_restart_services", "nginx")
|
||||||
|
switch t.dsmMajorVersion {
|
||||||
|
case 6:
|
||||||
|
f("os_min_ver", "6.0.1-7445")
|
||||||
|
f("os_max_ver", "7.0-40000")
|
||||||
|
case 7:
|
||||||
|
f("os_min_ver", "7.0-40000")
|
||||||
|
f("os_max_ver", "")
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unsupported DSM major version %d", t.dsmMajorVersion))
|
||||||
|
}
|
||||||
|
f("extractsize", fmt.Sprintf("%v", uncompressedSz>>10)) // in KiB
|
||||||
|
return ret.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
type synologyBuildsMemoizeKey struct{}
|
||||||
|
|
||||||
|
type innerPkg struct {
|
||||||
|
path string
|
||||||
|
uncompressedSz int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// synologyBuilds is extra build context shared by all synology builds.
|
||||||
|
type synologyBuilds struct {
|
||||||
|
innerPkgs dist.Memoize[*innerPkg]
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSynologyBuilds returns the synologyBuilds for b, creating one if needed.
|
||||||
|
func getSynologyBuilds(b *dist.Build) *synologyBuilds {
|
||||||
|
return b.Extra(synologyBuildsMemoizeKey{}, func() any { return new(synologyBuilds) }).(*synologyBuilds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildInnerPackage builds the inner tarball for synology packages,
|
||||||
|
// which contains the files to unpack to disk on installation (as
|
||||||
|
// opposed to the outer tarball, which contains package metadata)
|
||||||
|
func (m *synologyBuilds) buildInnerPackage(b *dist.Build, dsmVersion int, goenv map[string]string) (*innerPkg, error) {
|
||||||
|
key := []any{dsmVersion, goenv}
|
||||||
|
return m.innerPkgs.Do(key, func() (*innerPkg, error) {
|
||||||
|
ts, err := b.BuildGoBinary("tailscale.com/cmd/tailscale", goenv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tsd, err := b.BuildGoBinary("tailscale.com/cmd/tailscaled", goenv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp := b.TmpDir()
|
||||||
|
out := filepath.Join(tmp, "package.tgz")
|
||||||
|
|
||||||
|
f, err := os.Create(out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
gw := gzip.NewWriter(f)
|
||||||
|
defer gw.Close()
|
||||||
|
cw := &countingWriter{gw, 0}
|
||||||
|
tw := tar.NewWriter(cw)
|
||||||
|
defer tw.Close()
|
||||||
|
|
||||||
|
err = writeTar(tw, b.Time,
|
||||||
|
dir("bin"),
|
||||||
|
file(tsd, "bin/tailscaled", 0755),
|
||||||
|
file(ts, "bin/tailscale", 0755),
|
||||||
|
dir("conf"),
|
||||||
|
static("Tailscale.sc", "conf/Tailscale.sc", 0644),
|
||||||
|
static(fmt.Sprintf("logrotate-dsm%d", dsmVersion), "conf/logrotate.conf", 0644),
|
||||||
|
dir("ui"),
|
||||||
|
static("PACKAGE_ICON_256.PNG", "ui/PACKAGE_ICON_256.PNG", 0644),
|
||||||
|
static("config", "ui/config", 0644), // TODO: this has "1.8.3" hard-coded in it; why? what is it? bug?
|
||||||
|
static("index.cgi", "ui/index.cgi", 0755))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tw.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := gw.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &innerPkg{out, cw.n}, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeTar writes ents to tw.
|
||||||
|
func writeTar(tw *tar.Writer, modTime time.Time, ents ...tarEntry) error {
|
||||||
|
for _, ent := range ents {
|
||||||
|
if err := ent(tw, modTime); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// tarEntry is a function that writes tar entries (files or
|
||||||
|
// directories) to a tar.Writer.
|
||||||
|
type tarEntry func(*tar.Writer, time.Time) error
|
||||||
|
|
||||||
|
// fsFile returns a tarEntry that writes src in fsys to dst in the tar
|
||||||
|
// file, with mode.
|
||||||
|
func fsFile(fsys fs.FS, src, dst string, mode int64) tarEntry {
|
||||||
|
return func(tw *tar.Writer, modTime time.Time) error {
|
||||||
|
f, err := fsys.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hdr := &tar.Header{
|
||||||
|
Name: dst,
|
||||||
|
Size: fi.Size(),
|
||||||
|
Mode: mode,
|
||||||
|
ModTime: modTime,
|
||||||
|
}
|
||||||
|
if err := tw.WriteHeader(hdr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err = io.Copy(tw, f); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// file returns a tarEntry that writes src on disk into the tar file as
|
||||||
|
// dst, with mode.
|
||||||
|
func file(src, dst string, mode int64) tarEntry {
|
||||||
|
return fsFile(os.DirFS(filepath.Dir(src)), filepath.Base(src), dst, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:embed files/*
|
||||||
|
var files embed.FS
|
||||||
|
|
||||||
|
// static returns a tarEntry that writes src in files/ into the tar
|
||||||
|
// file as dst, with mode.
|
||||||
|
func static(src, dst string, mode int64) tarEntry {
|
||||||
|
fsys, err := fs.Sub(files, "files")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return fsFile(fsys, src, dst, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// memFile returns a tarEntry that writes bs to dst in the tar file,
|
||||||
|
// with mode.
|
||||||
|
func memFile(dst string, bs []byte, mode int64) tarEntry {
|
||||||
|
return func(tw *tar.Writer, modTime time.Time) error {
|
||||||
|
hdr := &tar.Header{
|
||||||
|
Name: dst,
|
||||||
|
Size: int64(len(bs)),
|
||||||
|
Mode: mode,
|
||||||
|
ModTime: modTime,
|
||||||
|
}
|
||||||
|
if err := tw.WriteHeader(hdr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := tw.Write(bs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dir returns a tarEntry that creates a world-readable directory in
|
||||||
|
// the tar file.
|
||||||
|
func dir(name string) tarEntry {
|
||||||
|
return func(tw *tar.Writer, modTime time.Time) error {
|
||||||
|
return tw.WriteHeader(&tar.Header{
|
||||||
|
Typeflag: tar.TypeDir,
|
||||||
|
Name: name + "/",
|
||||||
|
Mode: 0755,
|
||||||
|
ModTime: modTime,
|
||||||
|
// TODO: why tailscale? Files are being written as owned by root.
|
||||||
|
Uname: "tailscale",
|
||||||
|
Gname: "tailscale",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type countingWriter struct {
|
||||||
|
w io.Writer
|
||||||
|
n int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cw *countingWriter) Write(bs []byte) (int, error) {
|
||||||
|
n, err := cw.w.Write(bs)
|
||||||
|
cw.n += int64(n)
|
||||||
|
return n, err
|
||||||
|
}
|
69
release/dist/synology/targets.go
vendored
Normal file
69
release/dist/synology/targets.go
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
package synology
|
||||||
|
|
||||||
|
import "tailscale.com/release/dist"
|
||||||
|
|
||||||
|
func Targets(forPackageCenter bool) []dist.Target {
|
||||||
|
var ret []dist.Target
|
||||||
|
for _, dsmVersion := range []int{6, 7} {
|
||||||
|
ret = append(ret,
|
||||||
|
&target{
|
||||||
|
filenameArch: "x86_64",
|
||||||
|
dsmMajorVersion: dsmVersion,
|
||||||
|
goenv: map[string]string{
|
||||||
|
"GOOS": "linux",
|
||||||
|
"GOARCH": "amd64",
|
||||||
|
},
|
||||||
|
packageCenter: forPackageCenter,
|
||||||
|
},
|
||||||
|
&target{
|
||||||
|
filenameArch: "i686",
|
||||||
|
dsmMajorVersion: dsmVersion,
|
||||||
|
goenv: map[string]string{
|
||||||
|
"GOOS": "linux",
|
||||||
|
"GOARCH": "386",
|
||||||
|
},
|
||||||
|
packageCenter: forPackageCenter,
|
||||||
|
},
|
||||||
|
&target{
|
||||||
|
filenameArch: "armv8",
|
||||||
|
dsmMajorVersion: dsmVersion,
|
||||||
|
goenv: map[string]string{
|
||||||
|
"GOOS": "linux",
|
||||||
|
"GOARCH": "arm64",
|
||||||
|
},
|
||||||
|
packageCenter: forPackageCenter,
|
||||||
|
})
|
||||||
|
|
||||||
|
// On older ARMv5 and ARMv7 platforms, synology used a whole
|
||||||
|
// mess of SoC-specific target names, even though the packages
|
||||||
|
// built for each are identical apart from metadata.
|
||||||
|
for _, v5Arch := range []string{"armv5", "88f6281", "88f6282"} {
|
||||||
|
ret = append(ret, &target{
|
||||||
|
filenameArch: v5Arch,
|
||||||
|
dsmMajorVersion: dsmVersion,
|
||||||
|
goenv: map[string]string{
|
||||||
|
"GOOS": "linux",
|
||||||
|
"GOARCH": "arm",
|
||||||
|
"GOARM": "5",
|
||||||
|
},
|
||||||
|
packageCenter: forPackageCenter,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for _, v7Arch := range []string{"armv7", "alpine", "armada370", "armada375", "armada38x", "armadaxp", "comcerto2k", "monaco", "hi3535"} {
|
||||||
|
ret = append(ret, &target{
|
||||||
|
filenameArch: v7Arch,
|
||||||
|
dsmMajorVersion: dsmVersion,
|
||||||
|
goenv: map[string]string{
|
||||||
|
"GOOS": "linux",
|
||||||
|
"GOARCH": "arm",
|
||||||
|
"GOARM": "7",
|
||||||
|
},
|
||||||
|
packageCenter: forPackageCenter,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
6
release/dist/unixpkgs/pkgs.go
vendored
6
release/dist/unixpkgs/pkgs.go
vendored
@ -14,7 +14,6 @@
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/goreleaser/nfpm"
|
"github.com/goreleaser/nfpm"
|
||||||
"tailscale.com/release/dist"
|
"tailscale.com/release/dist"
|
||||||
@ -71,7 +70,6 @@ func (t *tgzTarget) Build(b *dist.Build) ([]string, error) {
|
|||||||
tw := tar.NewWriter(gw)
|
tw := tar.NewWriter(gw)
|
||||||
defer tw.Close()
|
defer tw.Close()
|
||||||
|
|
||||||
buildTime := time.Now()
|
|
||||||
addFile := func(src, dst string, mode int64) error {
|
addFile := func(src, dst string, mode int64) error {
|
||||||
f, err := os.Open(src)
|
f, err := os.Open(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -86,7 +84,7 @@ func (t *tgzTarget) Build(b *dist.Build) ([]string, error) {
|
|||||||
Name: dst,
|
Name: dst,
|
||||||
Size: fi.Size(),
|
Size: fi.Size(),
|
||||||
Mode: mode,
|
Mode: mode,
|
||||||
ModTime: buildTime,
|
ModTime: b.Time,
|
||||||
Uid: 0,
|
Uid: 0,
|
||||||
Gid: 0,
|
Gid: 0,
|
||||||
Uname: "root",
|
Uname: "root",
|
||||||
@ -104,7 +102,7 @@ func (t *tgzTarget) Build(b *dist.Build) ([]string, error) {
|
|||||||
hdr := &tar.Header{
|
hdr := &tar.Header{
|
||||||
Name: name + "/",
|
Name: name + "/",
|
||||||
Mode: 0755,
|
Mode: 0755,
|
||||||
ModTime: buildTime,
|
ModTime: b.Time,
|
||||||
Uid: 0,
|
Uid: 0,
|
||||||
Gid: 0,
|
Gid: 0,
|
||||||
Uname: "root",
|
Uname: "root",
|
||||||
|
@ -153,7 +153,9 @@ func autoflagsForTest(argv []string, env *Environment, goroot, nativeGOOS, nativ
|
|||||||
|
|
||||||
env.Set("GOOS", targetOS)
|
env.Set("GOOS", targetOS)
|
||||||
env.Set("GOARCH", targetArch)
|
env.Set("GOARCH", targetArch)
|
||||||
|
if !env.IsSet("GOARM") {
|
||||||
env.Set("GOARM", "5") // TODO: fix, see go/internal-bug/3092
|
env.Set("GOARM", "5") // TODO: fix, see go/internal-bug/3092
|
||||||
|
}
|
||||||
env.Set("GOMIPS", "softfloat")
|
env.Set("GOMIPS", "softfloat")
|
||||||
env.Set("CGO_ENABLED", boolStr(cgo))
|
env.Set("CGO_ENABLED", boolStr(cgo))
|
||||||
env.Set("CGO_CFLAGS", strings.Join(cgoCflags, " "))
|
env.Set("CGO_CFLAGS", strings.Join(cgoCflags, " "))
|
||||||
|
@ -61,6 +61,10 @@ type VersionInfo struct {
|
|||||||
// Winres is the version string that gets embedded into Windows exe
|
// Winres is the version string that gets embedded into Windows exe
|
||||||
// metadata. It is of the form "x,y,z,0".
|
// metadata. It is of the form "x,y,z,0".
|
||||||
Winres string
|
Winres string
|
||||||
|
// Synology is a map of Synology DSM major version to the
|
||||||
|
// Tailscale numeric version that gets embedded in Synology spk
|
||||||
|
// files.
|
||||||
|
Synology map[int]int64
|
||||||
// GitDate is the unix timestamp of GitHash's commit date.
|
// GitDate is the unix timestamp of GitHash's commit date.
|
||||||
GitDate string
|
GitDate string
|
||||||
// OtherDate is the unix timestamp of OtherHash's commit date, if any.
|
// OtherDate is the unix timestamp of OtherHash's commit date, if any.
|
||||||
@ -239,6 +243,10 @@ func mkOutput(v verInfo) (VersionInfo, error) {
|
|||||||
GitHash: fmt.Sprintf("%s", v.hash),
|
GitHash: fmt.Sprintf("%s", v.hash),
|
||||||
GitDate: fmt.Sprintf("%s", v.date),
|
GitDate: fmt.Sprintf("%s", v.date),
|
||||||
Track: track,
|
Track: track,
|
||||||
|
Synology: map[int]int64{
|
||||||
|
6: 6*1_000_000_000 + int64(v.major-1)*1_000_000 + int64(v.minor)*1_000 + int64(v.patch),
|
||||||
|
7: 7*1_000_000_000 + int64(v.major-1)*1_000_000 + int64(v.minor)*1_000 + int64(v.patch),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.otherHash != "" {
|
if v.otherHash != "" {
|
||||||
|
Loading…
Reference in New Issue
Block a user