Creates new QNAP builder target, which builds go binaries then uses docker to build into QNAP packages. Much of the docker/script code here is pulled over from https://github.com/tailscale/tailscale-qpkg, with adaptation into our builder structures. The qnap/Tailscale folder contains static resources needed to build Tailscale qpkg packages, and is an exact copy of the existing folder in the tailscale-qpkg repo. Builds can be run with: ``` sudo ./tool/go run ./cmd/dist build qnap ``` Updates tailscale/tailscale-qpkg#135 Signed-off-by: Sonia Appasamy <sonia@tailscale.com>main
parent
b743b85dad
commit
0a84215036
@ -0,0 +1,9 @@ |
||||
FROM ubuntu:20.04 |
||||
|
||||
RUN apt-get update -y && \ |
||||
apt-get install -y --no-install-recommends \ |
||||
git-core \ |
||||
ca-certificates |
||||
RUN git clone https://github.com/qnap-dev/QDK.git |
||||
RUN cd /QDK && ./InstallToUbuntu.sh install |
||||
ENV PATH="/usr/share/QDK/bin:${PATH}" |
||||
|
|
After Width: | Height: | Size: 600 B |
|
After Width: | Height: | Size: 741 B |
|
After Width: | Height: | Size: 1.3 KiB |
@ -0,0 +1,143 @@ |
||||
###################################################################### |
||||
# List of available definitions (it's not necessary to uncomment them) |
||||
###################################################################### |
||||
###### Command definitions ##### |
||||
#CMD_AWK="/bin/awk" |
||||
#CMD_CAT="/bin/cat" |
||||
#CMD_CHMOD="/bin/chmod" |
||||
#CMD_CHOWN="/bin/chown" |
||||
#CMD_CP="/bin/cp" |
||||
#CMD_CUT="/bin/cut" |
||||
#CMD_DATE="/bin/date" |
||||
#CMD_ECHO="/bin/echo" |
||||
#CMD_EXPR="/usr/bin/expr" |
||||
#CMD_FIND="/usr/bin/find" |
||||
#CMD_GETCFG="/sbin/getcfg" |
||||
#CMD_GREP="/bin/grep" |
||||
#CMD_GZIP="/bin/gzip" |
||||
#CMD_HOSTNAME="/bin/hostname" |
||||
#CMD_LN="/bin/ln" |
||||
#CMD_LOG_TOOL="/sbin/log_tool" |
||||
#CMD_MD5SUM="/bin/md5sum" |
||||
#CMD_MKDIR="/bin/mkdir" |
||||
#CMD_MV="/bin/mv" |
||||
#CMD_RM="/bin/rm" |
||||
#CMD_RMDIR="/bin/rmdir" |
||||
#CMD_SED="/bin/sed" |
||||
#CMD_SETCFG="/sbin/setcfg" |
||||
#CMD_SLEEP="/bin/sleep" |
||||
#CMD_SORT="/usr/bin/sort" |
||||
#CMD_SYNC="/bin/sync" |
||||
#CMD_TAR="/bin/tar" |
||||
#CMD_TOUCH="/bin/touch" |
||||
#CMD_WGET="/usr/bin/wget" |
||||
#CMD_WLOG="/sbin/write_log" |
||||
#CMD_XARGS="/usr/bin/xargs" |
||||
#CMD_7Z="/usr/local/sbin/7z" |
||||
# |
||||
###### System definitions ##### |
||||
#SYS_EXTRACT_DIR="$(pwd)" |
||||
#SYS_CONFIG_DIR="/etc/config" |
||||
#SYS_INIT_DIR="/etc/init.d" |
||||
#SYS_STARTUP_DIR="/etc/rcS.d" |
||||
#SYS_SHUTDOWN_DIR="/etc/rcK.d" |
||||
#SYS_RSS_IMG_DIR="/home/httpd/RSS/images" |
||||
#SYS_QPKG_DATA_FILE_GZIP="./data.tar.gz" |
||||
#SYS_QPKG_DATA_FILE_BZIP2="./data.tar.bz2" |
||||
#SYS_QPKG_DATA_FILE_7ZIP="./data.tar.7z" |
||||
#SYS_QPKG_DATA_CONFIG_FILE="./conf.tar.gz" |
||||
#SYS_QPKG_DATA_MD5SUM_FILE="./md5sum" |
||||
#SYS_QPKG_DATA_PACKAGES_FILE="./Packages.gz" |
||||
#SYS_QPKG_CONFIG_FILE="$SYS_CONFIG_DIR/qpkg.conf" |
||||
#SYS_QPKG_CONF_FIELD_QPKGFILE="QPKG_File" |
||||
#SYS_QPKG_CONF_FIELD_NAME="Name" |
||||
#SYS_QPKG_CONF_FIELD_VERSION="Version" |
||||
#SYS_QPKG_CONF_FIELD_ENABLE="Enable" |
||||
#SYS_QPKG_CONF_FIELD_DATE="Date" |
||||
#SYS_QPKG_CONF_FIELD_SHELL="Shell" |
||||
#SYS_QPKG_CONF_FIELD_INSTALL_PATH="Install_Path" |
||||
#SYS_QPKG_CONF_FIELD_CONFIG_PATH="Config_Path" |
||||
#SYS_QPKG_CONF_FIELD_WEBUI="WebUI" |
||||
#SYS_QPKG_CONF_FIELD_WEBPORT="Web_Port" |
||||
#SYS_QPKG_CONF_FIELD_SERVICEPORT="Service_Port" |
||||
#SYS_QPKG_CONF_FIELD_SERVICE_PIDFILE="Pid_File" |
||||
#SYS_QPKG_CONF_FIELD_AUTHOR="Author" |
||||
#SYS_QPKG_CONF_FIELD_RC_NUMBER="RC_Number" |
||||
## The following variables are assigned values at run-time. |
||||
#SYS_HOSTNAME=$($CMD_HOSTNAME) |
||||
## Data file name (one of SYS_QPKG_DATA_FILE_GZIP, SYS_QPKG_DATA_FILE_BZIP2, |
||||
## or SYS_QPKG_DATA_FILE_7ZIP) |
||||
#SYS_QPKG_DATA_FILE= |
||||
## Base location. |
||||
#SYS_QPKG_BASE="" |
||||
## Base location of QPKG installed packages. |
||||
#SYS_QPKG_INSTALL_PATH="" |
||||
## Location of installed software. |
||||
#SYS_QPKG_DIR="" |
||||
## If the QPKG should be enabled or disabled after the installation/upgrade. |
||||
#SYS_QPKG_SERVICE_ENABLED="" |
||||
## Architecture of the device the QPKG is installed on. |
||||
#SYS_CPU_ARCH="" |
||||
## Name and location of system shares |
||||
#SYS_PUBLIC_SHARE="" |
||||
#SYS_PUBLIC_PATH="" |
||||
#SYS_DOWNLOAD_SHARE="" |
||||
#SYS_DOWNLOAD_PATH="" |
||||
#SYS_MULTIMEDIA_SHARE="" |
||||
#SYS_MULTIMEDIA_PATH="" |
||||
#SYS_RECORDINGS_SHARE="" |
||||
#SYS_RECORDINGS_PATH="" |
||||
#SYS_USB_SHARE="" |
||||
#SYS_USB_PATH="" |
||||
#SYS_WEB_SHARE="" |
||||
#SYS_WEB_PATH="" |
||||
## Path to ipkg or opkg package tool if installed. |
||||
#CMD_PKG_TOOL= |
||||
# |
||||
###################################################################### |
||||
# All package specific functions shall call 'err_log MSG' if an error |
||||
# is detected that shall terminate the installation. |
||||
###################################################################### |
||||
# |
||||
###################################################################### |
||||
# Define any package specific operations that shall be performed when |
||||
# the package is removed. |
||||
###################################################################### |
||||
#PKG_PRE_REMOVE="{ |
||||
#}" |
||||
# |
||||
#PKG_MAIN_REMOVE="{ |
||||
#}" |
||||
# |
||||
PKG_POST_REMOVE="{ |
||||
rm -f /home/httpd/cgi-bin/qpkg/Tailscale |
||||
rm -rf /tmp/tailscale |
||||
if [ -f /etc/resolv.pre-tailscale-backup.conf ] && grep -q 100.100.100.100 /etc/resolv.conf; then |
||||
mv /etc/resolv.pre-tailscale-backup.conf /etc/resolv.conf |
||||
fi |
||||
}" |
||||
# |
||||
###################################################################### |
||||
# Define any package specific initialization that shall be performed |
||||
# before the package is installed. |
||||
###################################################################### |
||||
#pkg_init(){ |
||||
#} |
||||
# |
||||
###################################################################### |
||||
# Define any package specific requirement checks that shall be |
||||
# performed before the package is installed. |
||||
###################################################################### |
||||
#pkg_check_requirement(){ |
||||
#} |
||||
# |
||||
###################################################################### |
||||
# Define any package specific operations that shall be performed when |
||||
# the package is installed. |
||||
###################################################################### |
||||
pkg_install(){ |
||||
${CMD_MKDIR} -p ${SYS_QPKG_DIR}/state |
||||
} |
||||
|
||||
#pkg_post_install(){ |
||||
#} |
||||
@ -0,0 +1,99 @@ |
||||
# Name of the packaged application. |
||||
QPKG_NAME="Tailscale" |
||||
# Name of the display application. |
||||
#QPKG_DISPLAY_NAME="" |
||||
# Version of the packaged application. |
||||
QPKG_VER="$QPKG_VER" |
||||
# Author or maintainer of the package |
||||
QPKG_AUTHOR="Tailscale Inc." |
||||
# License for the packaged application |
||||
#QPKG_LICENSE="" |
||||
# One-line description of the packaged application |
||||
#QPKG_SUMMARY="Connect all your devices using WireGuard, without the hassle." |
||||
|
||||
# Preferred number in start/stop sequence. |
||||
QPKG_RC_NUM="101" |
||||
# Init-script used to control the start and stop of the installed application. |
||||
QPKG_SERVICE_PROGRAM="Tailscale.sh" |
||||
|
||||
# Optional 1 is enable. Path of starting/ stopping shall script. (no start/stop on App Center) |
||||
#QPKG_DISABLE_APPCENTER_UI_SERVICE=1 |
||||
|
||||
# Specifies any packages required for the current package to operate. |
||||
QPKG_REQUIRE="" |
||||
# Specifies what packages cannot be installed if the current package |
||||
# is to operate properly. |
||||
#QPKG_CONFLICT="Python" |
||||
# Name of configuration file (multiple definitions are allowed). |
||||
#QPKG_CONFIG="Tailscale.cfg" |
||||
#QPKG_CONFIG="/etc/config/myApp.conf" |
||||
# Port number used by service program. |
||||
QPKG_SERVICE_PORT="41641" |
||||
# Location of file with running service's PID |
||||
#QPKG_SERVICE_PIDFILE="" |
||||
# Relative path to web interface |
||||
QPKG_WEBUI="/cgi-bin/qpkg/Tailscale/index.cgi" |
||||
# Port number for the web interface. |
||||
#QPKG_WEB_PORT="" |
||||
# Port number for the SSL web interface. |
||||
#QPKG_WEB_SSL_PORT="" |
||||
|
||||
# Use QTS HTTP Proxy and set Proxy_Path in the qpkg.conf. |
||||
# When the QPKG has its own HTTP service port, and want clients to connect via QTS HTTP port (default 8080). |
||||
# Usually use this option when the QPKG need to connect via myQNAPcloud service. |
||||
QPKG_USE_PROXY="1" |
||||
#QPKG_PROXY_PATH="/qpkg_name" |
||||
|
||||
#Desktop Application (since 4.1) |
||||
# Set value to 1 means to open the QPKG's Web UI inside QTS desktop instead of new window. |
||||
#QPKG_DESKTOP_APP="1" |
||||
# Desktop Application Window default inner width (since 4.1) (not over 1178) |
||||
#QPKG_DESKTOP_APP_WIN_WIDTH="" |
||||
# Desktop Application Window default inner height (since 4.1) (not over 600) |
||||
#QPKG_DESKTOP_APP_WIN_HEIGHT="" |
||||
|
||||
# Minimum QTS version requirement |
||||
QTS_MINI_VERSION="5.0.0" |
||||
# Maximum QTS version requirement |
||||
#QTS_MAX_VERSION="5.0.0" |
||||
|
||||
# Select volume |
||||
# 1: support installation |
||||
# 2: support migration |
||||
# 3 (1+2): support both installation and migration |
||||
QPKG_VOLUME_SELECT="1" |
||||
|
||||
# Set timeout for QPKG enable and QPKG disable (since 4.1.0) |
||||
# Format in seconds (enable, disable) |
||||
#QPKG_TIMEOUT="10,30" |
||||
|
||||
# Visible setting for the QPKG that has web UI, show this QPKG on the Main menu of |
||||
# 1(default): administrators, 2: all NAS users. |
||||
QPKG_VISIBLE="1" |
||||
|
||||
# Location of icons for the packaged application. |
||||
QDK_DATA_DIR_ICONS="icons" |
||||
# Location of files specific to arm-x19 packages. |
||||
#QDK_DATA_DIR_X19="arm-x19" |
||||
# Location of files specific to arm-x31 packages. |
||||
#QDK_DATA_DIR_X31="arm-x31" |
||||
# Location of files specific to arm-x41 packages. |
||||
#QDK_DATA_DIR_X41="arm_al" |
||||
# Location of files specific to x86 packages. |
||||
#QDK_DATA_DIR_X86="x86" |
||||
# Location of files specific to x86 (64-bit) packages. |
||||
#QDK_DATA_DIR_X86_64="x86_64" |
||||
# Location of files common to all architectures. |
||||
QDK_DATA_DIR_SHARED="shared" |
||||
# Location of configuration files. |
||||
#QDK_DATA_DIR_CONFIG="config" |
||||
# Name of local data package. |
||||
#QDK_DATA_FILE="" |
||||
# Name of extra package (multiple definitions are allowed). |
||||
#QDK_EXTRA_FILE="" |
||||
# For QNAP code signing (currently can be done only inside QNAP) |
||||
# Uncomment the following four options if you want to enable code signing for this QPKG |
||||
#QNAP_CODE_SIGNING="0" |
||||
#QNAP_CODE_SIGNING_SERVER_IP="codesigning.qnap.com.tw" |
||||
#QNAP_CODE_SIGNING_SERVER_PORT="5001" |
||||
#QNAP_CODE_SIGNING_CSV="build_sign.csv" |
||||
@ -0,0 +1,50 @@ |
||||
#!/bin/sh |
||||
CONF=/etc/config/qpkg.conf |
||||
QPKG_NAME="Tailscale" |
||||
QPKG_ROOT=`/sbin/getcfg ${QPKG_NAME} Install_Path -f ${CONF}` |
||||
QPKG_PORT=`/sbin/getcfg ${QPKG_NAME} Service_Port -f ${CONF}` |
||||
export QNAP_QPKG=${QPKG_NAME} |
||||
set -e |
||||
|
||||
case "$1" in |
||||
start) |
||||
ENABLED=$(/sbin/getcfg ${QPKG_NAME} Enable -u -d FALSE -f ${CONF}) |
||||
if [ "${ENABLED}" != "TRUE" ]; then |
||||
echo "${QPKG_NAME} is disabled." |
||||
exit 1 |
||||
fi |
||||
mkdir -p /home/httpd/cgi-bin/qpkg |
||||
ln -sf ${QPKG_ROOT}/ui /home/httpd/cgi-bin/qpkg/${QPKG_NAME} |
||||
mkdir -p -m 0755 /tmp/tailscale |
||||
if [ -e /tmp/tailscale/tailscaled.pid ]; then |
||||
PID=$(cat /tmp/tailscale/tailscaled.pid) |
||||
if [ -d /proc/${PID}/ ]; then |
||||
echo "${QPKG_NAME} is already running." |
||||
exit 0 |
||||
fi |
||||
fi |
||||
${QPKG_ROOT}/tailscaled --port ${QPKG_PORT} --statedir=${QPKG_ROOT}/state --socket=/tmp/tailscale/tailscaled.sock 2> /dev/null & |
||||
echo $! > /tmp/tailscale/tailscaled.pid |
||||
;; |
||||
|
||||
stop) |
||||
if [ -e /tmp/tailscale/tailscaled.pid ]; then |
||||
PID=$(cat /tmp/tailscale/tailscaled.pid) |
||||
kill -9 ${PID} || true |
||||
rm -f /tmp/tailscale/tailscaled.pid |
||||
fi |
||||
;; |
||||
|
||||
restart) |
||||
$0 stop |
||||
$0 start |
||||
;; |
||||
remove) |
||||
;; |
||||
|
||||
*) |
||||
echo "Usage: $0 {start|stop|restart|remove}" |
||||
exit 1 |
||||
esac |
||||
|
||||
exit 0 |
||||
@ -0,0 +1,2 @@ |
||||
Options +ExecCGI |
||||
AddHandler cgi-script .cgi |
||||
@ -0,0 +1,5 @@ |
||||
#!/bin/sh |
||||
CONF=/etc/config/qpkg.conf |
||||
QPKG_NAME="Tailscale" |
||||
QPKG_ROOT=$(/sbin/getcfg ${QPKG_NAME} Install_Path -f ${CONF} -d"") |
||||
exec "${QPKG_ROOT}/tailscale" --socket=/tmp/tailscale/tailscaled.sock web --cgi --prefix="/cgi-bin/qpkg/Tailscale/index.cgi/" |
||||
@ -0,0 +1,19 @@ |
||||
#!/bin/bash |
||||
|
||||
set -eu |
||||
|
||||
# Clean up folders and files created during build. |
||||
function cleanup() { |
||||
rm -rf /Tailscale/$ARCH |
||||
rm -f /Tailscale/sed* |
||||
rm -f /Tailscale/qpkg.cfg |
||||
} |
||||
trap cleanup EXIT |
||||
|
||||
mkdir -p /Tailscale/$ARCH |
||||
cp /tailscaled /Tailscale/$ARCH/tailscaled |
||||
cp /tailscale /Tailscale/$ARCH/tailscale |
||||
|
||||
sed "s/\$QPKG_VER/$TSTAG-$QNAPTAG/g" /Tailscale/qpkg.cfg.in > /Tailscale/qpkg.cfg |
||||
|
||||
qbuild --root /Tailscale --build-arch $ARCH --build-dir /out |
||||
@ -0,0 +1,229 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package qnap contains dist Targets for building QNAP Tailscale packages.
|
||||
//
|
||||
// QNAP dev docs over at https://www.qnap.com/en/how-to/tutorial/article/qpkg-development-guidelines.
|
||||
package qnap |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"log" |
||||
"os" |
||||
"os/exec" |
||||
"path/filepath" |
||||
"sync" |
||||
|
||||
"tailscale.com/release/dist" |
||||
) |
||||
|
||||
type target struct { |
||||
goenv map[string]string |
||||
arch string |
||||
signer *signer |
||||
} |
||||
|
||||
type signer struct { |
||||
privateKeyPath string |
||||
certificatePath string |
||||
} |
||||
|
||||
func (t *target) String() string { |
||||
return fmt.Sprintf("qnap/%s", t.arch) |
||||
} |
||||
|
||||
func (t *target) Build(b *dist.Build) ([]string, error) { |
||||
// Stop early if we don't have docker running.
|
||||
if _, err := exec.LookPath("docker"); err != nil { |
||||
return nil, fmt.Errorf("docker not found, cannot build: %w", err) |
||||
} |
||||
|
||||
if t.signer != nil { |
||||
if err := t.setUpSignatureFiles(b); err != nil { |
||||
return nil, err |
||||
} |
||||
} |
||||
|
||||
qnapBuilds := getQnapBuilds(b) |
||||
inner, err := qnapBuilds.buildInnerPackage(b, t.goenv) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return t.buildQPKG(b, qnapBuilds, inner) |
||||
} |
||||
|
||||
const ( |
||||
qnapTag = "1" // currently static, we don't seem to bump this
|
||||
) |
||||
|
||||
func (t *target) buildQPKG(b *dist.Build, qnapBuilds *qnapBuilds, inner *innerPkg) ([]string, error) { |
||||
if _, err := exec.LookPath("docker"); err != nil { |
||||
return nil, fmt.Errorf("docker not found, cannot build: %w", err) |
||||
} |
||||
|
||||
if err := qnapBuilds.makeDockerImage(b); err != nil { |
||||
return nil, fmt.Errorf("makeDockerImage: %w", err) |
||||
} |
||||
|
||||
filename := fmt.Sprintf("Tailscale_%s-%s_%s.qpkg", b.Version.Short, qnapTag, t.arch) |
||||
filePath := filepath.Join(b.Out, filename) |
||||
|
||||
cmd := b.Command(b.Repo, "docker", "run", "--rm", |
||||
"-e", fmt.Sprintf("ARCH=%s", t.arch), |
||||
"-e", fmt.Sprintf("TSTAG=%s", b.Version.Short), |
||||
"-e", fmt.Sprintf("QNAPTAG=%s", qnapTag), |
||||
"-v", fmt.Sprintf("%s:/tailscale", inner.tailscalePath), |
||||
"-v", fmt.Sprintf("%s:/tailscaled", inner.tailscaledPath), |
||||
// Tailscale folder has QNAP package setup files needed for building.
|
||||
"-v", fmt.Sprintf("%s:/Tailscale", filepath.Join(b.Repo, "release/dist/qnap/Tailscale")), |
||||
"-v", fmt.Sprintf("%s:/build-qpkg.sh", filepath.Join(b.Repo, "release/dist/qnap/build-qpkg.sh")), |
||||
"-v", fmt.Sprintf("%s:/out", b.Out), |
||||
"build.tailscale.io/qdk:latest", |
||||
"/build-qpkg.sh", |
||||
) |
||||
|
||||
// dist.Build runs target builds in parallel goroutines by default.
|
||||
// For QNAP, this is an issue because the underlaying qbuild builder will
|
||||
// create tmp directories in the shared docker image that end up conflicting
|
||||
// with one another.
|
||||
// So we use a mutex to only allow one "docker run" at a time.
|
||||
qnapBuilds.dockerImageMu.Lock() |
||||
defer qnapBuilds.dockerImageMu.Unlock() |
||||
|
||||
log.Printf("Building %s", filePath) |
||||
out, err := cmd.CombinedOutput() |
||||
if err != nil { |
||||
return nil, fmt.Errorf("docker run %v: %s", err, out) |
||||
} |
||||
|
||||
return []string{filePath, filePath + ".md5"}, nil |
||||
} |
||||
|
||||
func (t *target) setUpSignatureFiles(b *dist.Build) error { |
||||
return b.Once(fmt.Sprintf("qnap-signature-%s-%s", t.signer.privateKeyPath, t.signer.certificatePath), func() error { |
||||
log.Print("Setting up qnap signature files") |
||||
|
||||
key, err := os.ReadFile(t.signer.privateKeyPath) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
cert, err := os.ReadFile(t.signer.certificatePath) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
// QNAP's qbuild command expects key and cert files to be in the root
|
||||
// of the project directory (in our case release/dist/qnap/Tailscale).
|
||||
// So here, we copy the key and cert over to the project folder for the
|
||||
// duration of qnap package building and then delete them on close.
|
||||
|
||||
keyPath := filepath.Join(b.Repo, "release/dist/qnap/Tailscale/private_key") |
||||
if err := os.WriteFile(keyPath, key, 0400); err != nil { |
||||
return err |
||||
} |
||||
certPath := filepath.Join(b.Repo, "release/dist/qnap/Tailscale/certificate") |
||||
if err := os.WriteFile(certPath, cert, 0400); err != nil { |
||||
return err |
||||
} |
||||
|
||||
b.AddOnCloseFunc(func() error { |
||||
return errors.Join(os.Remove(keyPath), os.Remove(certPath)) |
||||
}) |
||||
return nil |
||||
}) |
||||
} |
||||
|
||||
type qnapBuildsMemoizeKey struct{} |
||||
|
||||
type innerPkg struct { |
||||
tailscalePath string |
||||
tailscaledPath string |
||||
} |
||||
|
||||
// qnapBuilds holds extra build context shared by all qnap builds.
|
||||
type qnapBuilds struct { |
||||
// innerPkgs contains per-goenv compiled binary paths.
|
||||
// It is used to avoid repeated compilations for the same architecture.
|
||||
innerPkgs dist.Memoize[*innerPkg] |
||||
dockerImageMu sync.Mutex |
||||
} |
||||
|
||||
// getQnapBuilds returns the qnapBuilds for b, creating one if needed.
|
||||
func getQnapBuilds(b *dist.Build) *qnapBuilds { |
||||
return b.Extra(qnapBuildsMemoizeKey{}, func() any { return new(qnapBuilds) }).(*qnapBuilds) |
||||
} |
||||
|
||||
// buildInnerPackage builds the go binaries used for qnap packages.
|
||||
// These binaries get embedded with Tailscale package metadata to form qnap
|
||||
// releases.
|
||||
func (m *qnapBuilds) buildInnerPackage(b *dist.Build, goenv map[string]string) (*innerPkg, error) { |
||||
return m.innerPkgs.Do(goenv, func() (*innerPkg, error) { |
||||
if err := b.BuildWebClientAssets(); err != nil { |
||||
return nil, err |
||||
} |
||||
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 |
||||
} |
||||
|
||||
// The go binaries above get built and put into a /tmp directory created
|
||||
// by b.TmpDir(). But, we build QNAP with docker, which doesn't always
|
||||
// allow for mounting tmp directories (seemingly dependent on docker
|
||||
// host).
|
||||
// https://stackoverflow.com/questions/65267251/docker-bind-mount-directory-in-tmp-not-working
|
||||
//
|
||||
// So here, we move the binaries into a directory within the b.Repo
|
||||
// path and clean it up when the builder closes.
|
||||
|
||||
tmpDir := filepath.Join(b.Repo, fmt.Sprintf("/tmp-qnap-%s-%s-%s", b.Version.Short, goenv["GOOS"], goenv["GOARCH"])) |
||||
if err = os.MkdirAll(tmpDir, 0755); err != nil { |
||||
return nil, err |
||||
} |
||||
b.AddOnCloseFunc(func() error { |
||||
return os.RemoveAll(tmpDir) |
||||
}) |
||||
|
||||
tsBytes, err := os.ReadFile(ts) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
tsdBytes, err := os.ReadFile(tsd) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
tsPath := filepath.Join(tmpDir, "tailscale") |
||||
if err := os.WriteFile(tsPath, tsBytes, 0755); err != nil { |
||||
return nil, err |
||||
} |
||||
tsdPath := filepath.Join(tmpDir, "tailscaled") |
||||
if err := os.WriteFile(tsdPath, tsdBytes, 0755); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return &innerPkg{tailscalePath: tsPath, tailscaledPath: tsdPath}, nil |
||||
}) |
||||
} |
||||
|
||||
func (m *qnapBuilds) makeDockerImage(b *dist.Build) error { |
||||
return b.Once("make-qnap-docker-image", func() error { |
||||
log.Printf("Building qnapbuilder docker image") |
||||
|
||||
cmd := b.Command(b.Repo, "docker", "build", |
||||
"-f", filepath.Join(b.Repo, "release/dist/qnap/Dockerfile.qpkg"), |
||||
"-t", "build.tailscale.io/qdk:latest", |
||||
filepath.Join(b.Repo, "release/dist/qnap/"), |
||||
) |
||||
out, err := cmd.CombinedOutput() |
||||
if err != nil { |
||||
return fmt.Errorf("docker build %v: %s", err, out) |
||||
} |
||||
return nil |
||||
}) |
||||
} |
||||
@ -0,0 +1,75 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package qnap |
||||
|
||||
import "tailscale.com/release/dist" |
||||
|
||||
// Targets defines the dist.Targets for QNAP devices.
|
||||
//
|
||||
// If privateKeyPath and certificatePath are both provided non-empty,
|
||||
// these targets will be signed for QNAP app store release with built.
|
||||
func Targets(privateKeyPath, certificatePath string) []dist.Target { |
||||
var signerInfo *signer |
||||
if privateKeyPath != "" && certificatePath != "" { |
||||
signerInfo = &signer{privateKeyPath, certificatePath} |
||||
} |
||||
return []dist.Target{ |
||||
&target{ |
||||
arch: "x86", |
||||
goenv: map[string]string{ |
||||
"GOOS": "linux", |
||||
"GOARCH": "386", |
||||
}, |
||||
signer: signerInfo, |
||||
}, |
||||
&target{ |
||||
arch: "x86_ce53xx", |
||||
goenv: map[string]string{ |
||||
"GOOS": "linux", |
||||
"GOARCH": "386", |
||||
}, |
||||
signer: signerInfo, |
||||
}, |
||||
&target{ |
||||
arch: "x86_64", |
||||
goenv: map[string]string{ |
||||
"GOOS": "linux", |
||||
"GOARCH": "amd64", |
||||
}, |
||||
signer: signerInfo, |
||||
}, |
||||
&target{ |
||||
arch: "arm-x31", |
||||
goenv: map[string]string{ |
||||
"GOOS": "linux", |
||||
"GOARCH": "arm", |
||||
}, |
||||
signer: signerInfo, |
||||
}, |
||||
&target{ |
||||
arch: "arm-x41", |
||||
goenv: map[string]string{ |
||||
"GOOS": "linux", |
||||
"GOARCH": "arm", |
||||
}, |
||||
signer: signerInfo, |
||||
}, |
||||
&target{ |
||||
arch: "arm-x19", |
||||
goenv: map[string]string{ |
||||
"GOOS": "linux", |
||||
"GOARCH": "arm", |
||||
}, |
||||
signer: signerInfo, |
||||
}, |
||||
&target{ |
||||
arch: "arm_64", |
||||
goenv: map[string]string{ |
||||
"GOOS": "linux", |
||||
"GOARCH": "arm64", |
||||
}, |
||||
signer: signerInfo, |
||||
}, |
||||
} |
||||
} |
||||
Loading…
Reference in new issue