mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 10:27:26 +08:00
working link, update, and testing docker container and scripts
This commit is contained in:
parent
947f3f565f
commit
fc8682668b
@ -142,3 +142,8 @@ tasks:
|
||||
cmds:
|
||||
- docker push ${QUILIBRIUM_IMAGE_NAME:-quilibrium}:{{.VERSION}}
|
||||
- docker push ${QUILIBRIUM_IMAGE_NAME:-quilibrium}:latest
|
||||
|
||||
test:qclient:
|
||||
desc: Test the Quilibrium docker image.
|
||||
cmds:
|
||||
- client/test/run_tests.sh -d 'ubuntu' -v '24.04'
|
||||
|
||||
51
client/cmd/download-signatures.go
Normal file
51
client/cmd/download-signatures.go
Normal file
@ -0,0 +1,51 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"source.quilibrium.com/quilibrium/monorepo/client/utils"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||
)
|
||||
|
||||
var versionFlag string
|
||||
|
||||
var downloadSignaturesCmd = &cobra.Command{
|
||||
Use: "download-signatures",
|
||||
Short: "Download signature files for the current binary",
|
||||
Long: `Download signature files for the current binary. This command will download
|
||||
the digest file and all signature files needed for verification. If --version is specified,
|
||||
it will download signatures for that version. Otherwise, it will download signatures for
|
||||
the latest version.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var version string
|
||||
|
||||
if versionFlag != "" {
|
||||
// Use specified version
|
||||
version = versionFlag
|
||||
} else {
|
||||
// Get the current version
|
||||
version = config.GetVersionString()
|
||||
}
|
||||
|
||||
// Download signature files
|
||||
if err := utils.DownloadReleaseSignatures(utils.ReleaseTypeQClient, version); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error downloading signature files: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully downloaded signature files for version %s\n", version)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
downloadSignaturesCmd.Flags().StringVarP(
|
||||
&versionFlag,
|
||||
"version",
|
||||
"v",
|
||||
"",
|
||||
"Version to download signatures for (defaults to latest version)",
|
||||
)
|
||||
rootCmd.AddCommand(downloadSignaturesCmd)
|
||||
}
|
||||
@ -45,18 +45,6 @@ Example: qclient link --path /usr/local/bin`),
|
||||
return err
|
||||
}
|
||||
|
||||
// Save the symlink path to ClientConfig
|
||||
config := utils.ClientConfig{
|
||||
SymlinkPath: targetPath,
|
||||
}
|
||||
|
||||
// Use the UpdateClientConfig function to save the config
|
||||
if err := utils.UpdateClientConfig(&config); err != nil {
|
||||
fmt.Printf("Warning: Failed to save symlink path to config: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Saved symlink path %s to client configuration\n", targetPath)
|
||||
}
|
||||
|
||||
fmt.Printf("Symlink created at %s\n", targetPath)
|
||||
return nil
|
||||
},
|
||||
@ -71,7 +59,7 @@ func determineSymlinkLocation() (string, string, error) {
|
||||
}
|
||||
|
||||
// Otherwise, find a suitable directory in PATH
|
||||
return utils.NodeDefaultSymlinkDir, utils.DefaultQClientSymlinkPath, nil
|
||||
return utils.DefaultSymlinkDir, utils.DefaultQClientSymlinkPath, nil
|
||||
}
|
||||
|
||||
// isDirectoryInPath checks if a directory is in the PATH environment variable
|
||||
|
||||
@ -85,11 +85,11 @@ func installNode(version string) {
|
||||
|
||||
if err := installByVersion(version); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error installing specific version: %v\n", err)
|
||||
return
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Finish installation
|
||||
nodeBinaryPath := filepath.Join(installPath, version, "node")
|
||||
nodeBinaryPath := filepath.Join(installPath, string(utils.ReleaseTypeNode), version)
|
||||
finishInstallation(nodeBinaryPath, version)
|
||||
}
|
||||
|
||||
|
||||
@ -15,10 +15,10 @@ var (
|
||||
// Default symlink path for the node binary
|
||||
defaultSymlinkPath = "/usr/local/bin/quilibrium-node"
|
||||
|
||||
// Default installation directory base paths in order of preference
|
||||
// Default installation directory base path
|
||||
installPath = "/opt/quilibrium"
|
||||
|
||||
// Default data directory paths in order of preference
|
||||
// Default data directory paths
|
||||
dataPath = "/var/lib/quilibrium"
|
||||
|
||||
logPath = "/var/log/quilibrium"
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@ -30,6 +31,8 @@ var simulateFail bool
|
||||
var LightNode bool = false
|
||||
var DryRun bool = false
|
||||
var publicRPC bool = false
|
||||
|
||||
var standardizedQClientFileName string = "qclient-" + config.GetVersionString() + "-" + osType + "-" + arch
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "qclient",
|
||||
Short: "Quilibrium client",
|
||||
@ -52,23 +55,37 @@ It provides commands for installing, updating, and managing Quilibrium nodes.`,
|
||||
}
|
||||
|
||||
checksum := sha3.Sum256(b)
|
||||
digest, err := os.ReadFile(ex + ".dgst")
|
||||
|
||||
// First check var data path for signatures
|
||||
varDataPath := filepath.Join(utils.ClientDataPath, config.GetVersionString())
|
||||
digestPath := filepath.Join(varDataPath, standardizedQClientFileName+".dgst")
|
||||
|
||||
fmt.Printf("Checking signature for %s\n", digestPath)
|
||||
|
||||
// Try to read digest from var data path first
|
||||
digest, err := os.ReadFile(digestPath)
|
||||
if err != nil {
|
||||
fmt.Println("The digest file was not found. Do you want to continue without signature verification? (y/n)")
|
||||
fmt.Println("You can also use --signature-check=false in your command to skip this prompt")
|
||||
// Fall back to checking next to executable
|
||||
digest, err = os.ReadFile(ex + ".dgst")
|
||||
if err != nil {
|
||||
fmt.Println("The digest file was not found. Do you want to continue without signature verification? (y/n)")
|
||||
fmt.Println("You can also use --signature-check=false in your command to skip this prompt")
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
response, _ := reader.ReadString('\n')
|
||||
response = strings.TrimSpace(strings.ToLower(response))
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
response, _ := reader.ReadString('\n')
|
||||
response = strings.TrimSpace(strings.ToLower(response))
|
||||
|
||||
if response != "y" && response != "yes" {
|
||||
fmt.Println("Exiting due to missing digest file")
|
||||
os.Exit(1)
|
||||
if response != "y" && response != "yes" {
|
||||
fmt.Println("Exiting due to missing digest file")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("Continuing without signature verification")
|
||||
signatureCheck = false
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Continuing without signature verification")
|
||||
signatureCheck = false
|
||||
} else {
|
||||
if signatureCheck {
|
||||
parts := strings.Split(string(digest), " ")
|
||||
if len(parts) != 2 {
|
||||
fmt.Println("Invalid digest file format")
|
||||
@ -89,10 +106,16 @@ It provides commands for installing, updating, and managing Quilibrium nodes.`,
|
||||
count := 0
|
||||
|
||||
for i := 1; i <= len(config.Signatories); i++ {
|
||||
signatureFile := fmt.Sprintf(ex+".dgst.sig.%d", i)
|
||||
// Try var data path first for signature files
|
||||
signatureFile := filepath.Join(varDataPath, fmt.Sprintf("%s.dgst.sig.%d", filepath.Base(ex), i))
|
||||
sig, err := os.ReadFile(signatureFile)
|
||||
if err != nil {
|
||||
continue
|
||||
// Fall back to checking next to executable
|
||||
signatureFile = fmt.Sprintf(ex+".dgst.sig.%d", i)
|
||||
sig, err = os.ReadFile(signatureFile)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
pubkey, _ := hex.DecodeString(config.Signatories[i-1])
|
||||
@ -219,8 +242,8 @@ func init() {
|
||||
|
||||
// Create config directory if it doesn't exist
|
||||
rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
|
||||
// Skip for help command
|
||||
if cmd.Name() == "help" {
|
||||
// Skip for help command and download-signatures command
|
||||
if cmd.Name() == "help" || cmd.Name() == "download-signatures" {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -235,20 +258,37 @@ func init() {
|
||||
return fmt.Errorf("failed to get executable path: %v", err)
|
||||
}
|
||||
|
||||
digestPath := ex + ".dgst"
|
||||
// First check var data path for signatures
|
||||
version := config.GetVersionString()
|
||||
varDataPath := filepath.Join(utils.ClientDataPath, version)
|
||||
digestPath := filepath.Join(varDataPath, standardizedQClientFileName+".dgst")
|
||||
fmt.Printf("Checking signature for %s\n", digestPath)
|
||||
if signatureCheck && !utils.FileExists(digestPath) {
|
||||
fmt.Println("Signature file not found. Would you like to download it? (y/n)")
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
response, _ := reader.ReadString('\n')
|
||||
response = strings.TrimSpace(strings.ToLower(response))
|
||||
// Fall back to checking next to executable
|
||||
digestPath = ex + ".dgst"
|
||||
if !utils.FileExists(digestPath) {
|
||||
fmt.Println("Signature file not found. Would you like to download it? (y/n)")
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
response, _ := reader.ReadString('\n')
|
||||
response = strings.TrimSpace(strings.ToLower(response))
|
||||
|
||||
if response == "y" || response == "yes" {
|
||||
fmt.Println("Downloading signature file...")
|
||||
// TODO: Implement signature download logic
|
||||
fmt.Println("Signature download not implemented yet. Please download manually.")
|
||||
} else {
|
||||
fmt.Println("Continuing without signature verification")
|
||||
signatureCheck = false
|
||||
if response == "y" || response == "yes" {
|
||||
fmt.Println("Downloading signature files...")
|
||||
if version == "" {
|
||||
fmt.Println("Could not determine version from executable name")
|
||||
return fmt.Errorf("could not determine version from executable name")
|
||||
}
|
||||
|
||||
// Download signature files
|
||||
if err := utils.DownloadReleaseSignatures(utils.ReleaseTypeQClient, version); err != nil {
|
||||
fmt.Printf("Error downloading signature files: %v\n", err)
|
||||
return fmt.Errorf("failed to download signature files: %v", err)
|
||||
}
|
||||
fmt.Println("Successfully downloaded signature files")
|
||||
} else {
|
||||
fmt.Println("Continuing without signature verification")
|
||||
signatureCheck = false
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"source.quilibrium.com/quilibrium/monorepo/client/utils"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -23,6 +24,8 @@ var updateCmd = &cobra.Command{
|
||||
Long: `Update Quilibrium client to a specified version or the latest version.
|
||||
If no version is specified, the latest version will be installed.
|
||||
|
||||
If the current version is already the latest version, the command will exit with a message.
|
||||
|
||||
Examples:
|
||||
# Update to the latest version
|
||||
qclient update
|
||||
@ -65,6 +68,25 @@ func determineVersion(args []string) string {
|
||||
|
||||
// updateClient handles the client update process
|
||||
func updateClient(version string) {
|
||||
|
||||
currentVersion := config.GetVersionString()
|
||||
|
||||
// If version is "latest", get the latest version
|
||||
if version == "latest" {
|
||||
latestVersion, err := utils.GetLatestVersion(utils.ReleaseTypeQClient)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error getting latest version: %v\n", err)
|
||||
return
|
||||
}
|
||||
version = latestVersion
|
||||
fmt.Fprintf(os.Stdout, "Latest version: %s\n", version)
|
||||
}
|
||||
|
||||
if version == currentVersion {
|
||||
fmt.Fprintf(os.Stdout, "Already on version %s\n", currentVersion)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if we need sudo privileges
|
||||
if err := utils.CheckAndRequestSudo(fmt.Sprintf("Updating client at %s requires root privileges", utils.ClientInstallPath)); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
@ -85,17 +107,6 @@ func updateClient(version string) {
|
||||
return
|
||||
}
|
||||
|
||||
// If version is "latest", get the latest version
|
||||
if version == "latest" {
|
||||
latestVersion, err := utils.GetLatestVersion(utils.ReleaseTypeQClient)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error getting latest version: %v\n", err)
|
||||
return
|
||||
}
|
||||
version = latestVersion
|
||||
fmt.Fprintf(os.Stdout, "Latest version: %s\n", version)
|
||||
}
|
||||
|
||||
// Construct the expected filename for the specified version
|
||||
// Remove 'v' prefix if present for filename construction
|
||||
versionWithoutV := strings.TrimPrefix(version, "v")
|
||||
@ -123,22 +134,9 @@ func updateClient(version string) {
|
||||
|
||||
// finishInstallation completes the update process
|
||||
func finishInstallation(version string) {
|
||||
// Read current config
|
||||
config, err := utils.ReadClientConfig()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error reading config: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Update config with new version
|
||||
config.Version = version
|
||||
if err := utils.UpdateClientConfig(config); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error updating config: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Construct executable path
|
||||
execPath := filepath.Join(utils.ClientInstallPath, version, "qclient")
|
||||
execPath := filepath.Join(utils.ClientDataPath, version, "qclient-"+version+"-"+osType+"-"+arch)
|
||||
|
||||
// Make the binary executable
|
||||
if err := os.Chmod(execPath, 0755); err != nil {
|
||||
@ -148,9 +146,6 @@ func finishInstallation(version string) {
|
||||
|
||||
// Create symlink to the new version
|
||||
symlinkPath := utils.DefaultQClientSymlinkPath
|
||||
if config.SymlinkPath != "" {
|
||||
symlinkPath = config.SymlinkPath
|
||||
}
|
||||
|
||||
// Check if we need sudo privileges for creating symlink in system directory
|
||||
if strings.HasPrefix(symlinkPath, "/usr/") || strings.HasPrefix(symlinkPath, "/bin/") || strings.HasPrefix(symlinkPath, "/sbin/") {
|
||||
|
||||
@ -8,11 +8,12 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"source.quilibrium.com/quilibrium/monorepo/client/utils"
|
||||
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||
)
|
||||
|
||||
// Version information - fallback if executable name doesn't contain version
|
||||
const (
|
||||
DefaultVersion = "1.0.0"
|
||||
var (
|
||||
DefaultVersion = config.GetVersionString()
|
||||
)
|
||||
|
||||
// VersionInfo holds version and hash information
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
ARG DISTRO=ubuntu
|
||||
ARG VERSION=24.04
|
||||
|
||||
# Use the specified distribution as the base image
|
||||
FROM --platform=$BUILDPLATFORM ${DISTRO}:${VERSION}
|
||||
# Base stage with common setup
|
||||
FROM --platform=$BUILDPLATFORM ${DISTRO}:${VERSION} AS base
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG TARGETOS
|
||||
@ -22,18 +22,9 @@ RUN apt-get update && apt-get install -y \
|
||||
RUN useradd -m -s /bin/bash testuser && \
|
||||
echo "testuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
|
||||
# Set working directory
|
||||
# Final test stage
|
||||
FROM base AS qclient-test
|
||||
WORKDIR /app
|
||||
|
||||
# Copy the client binary and test script
|
||||
COPY build/qclient/${TARGETARCH}_${TARGETOS}/qclient /opt/quilibrium/bin/qclient
|
||||
COPY test_install.sh /app/
|
||||
|
||||
# Set permissions
|
||||
RUN chmod +x /opt/quilibrium/bin/qclient /app/test_install.sh
|
||||
|
||||
# Switch to test user
|
||||
USER testuser
|
||||
|
||||
# Run the test script
|
||||
CMD ["/app/test_install.sh"]
|
||||
@ -1,87 +0,0 @@
|
||||
FROM ubuntu:24.04 AS build-base
|
||||
|
||||
ENV PATH="${PATH}:/root/.cargo/bin/"
|
||||
|
||||
# Install GMP 6.2 (6.3 which MacOS is using only available on Debian unstable)
|
||||
RUN apt-get update && apt-get install -y \
|
||||
build-essential \
|
||||
curl \
|
||||
git \
|
||||
cmake \
|
||||
libgmp-dev \
|
||||
libmpfr-dev \
|
||||
libmpfr6 \
|
||||
wget \
|
||||
m4 \
|
||||
pkg-config \
|
||||
gcc \
|
||||
g++ \
|
||||
make \
|
||||
autoconf \
|
||||
automake \
|
||||
libtool \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Go 1.22.5 for amd64
|
||||
RUN wget https://go.dev/dl/go1.22.5.linux-amd64.tar.gz && \
|
||||
rm -rf /usr/local/go && \
|
||||
tar -C /usr/local -xzf go1.22.5.linux-amd64.tar.gz && \
|
||||
rm go1.22.5.linux-amd64.tar.gz
|
||||
|
||||
ENV PATH=$PATH:/usr/local/go/bin
|
||||
|
||||
# Install FLINT library
|
||||
RUN git clone https://github.com/flintlib/flint.git && \
|
||||
cd flint && \
|
||||
git checkout flint-3.0 && \
|
||||
./bootstrap.sh && \
|
||||
./configure \
|
||||
--prefix=/usr/local \
|
||||
--with-gmp=/usr/local \
|
||||
--with-mpfr=/usr/local \
|
||||
--enable-static \
|
||||
--disable-shared \
|
||||
CFLAGS="-O3" && \
|
||||
make && \
|
||||
make install && \
|
||||
cd .. && \
|
||||
rm -rf flint
|
||||
|
||||
# Install Rust toolchain
|
||||
COPY docker/rustup-init.sh /opt/rustup-init.sh
|
||||
RUN /opt/rustup-init.sh -y --profile minimal
|
||||
|
||||
# Install uniffi-bindgen-go
|
||||
RUN cargo install uniffi-bindgen-go --git https://github.com/NordSecurity/uniffi-bindgen-go --tag v0.2.1+v0.25.0
|
||||
|
||||
FROM build-base AS build
|
||||
|
||||
ENV GOEXPERIMENT=arenas
|
||||
ENV QUILIBRIUM_SIGNATURE_CHECK=false
|
||||
|
||||
WORKDIR /opt/ceremonyclient
|
||||
|
||||
COPY . .
|
||||
|
||||
## Generate Rust bindings for VDF
|
||||
WORKDIR /opt/ceremonyclient/vdf
|
||||
RUN ./generate.sh
|
||||
|
||||
## Generate Rust bindings for BLS48581
|
||||
WORKDIR /opt/ceremonyclient/bls48581
|
||||
RUN ./generate.sh
|
||||
|
||||
## Generate Rust bindings for VerEnc
|
||||
WORKDIR /opt/ceremonyclient/verenc
|
||||
RUN ./generate.sh
|
||||
|
||||
# Build and install qclient
|
||||
WORKDIR /opt/ceremonyclient/client
|
||||
RUN ./build.sh -o qclient
|
||||
|
||||
# Create final stage to copy the binary
|
||||
FROM scratch AS export-stage
|
||||
COPY --from=build /opt/ceremonyclient/client/qclient ./client/test/
|
||||
|
||||
|
||||
|
||||
@ -141,10 +141,12 @@ If you just want to build the qclient in a Docker container without running the
|
||||
```bash
|
||||
# in the project root directory
|
||||
## Will take awhile to build flint on initial build
|
||||
docker build -f client/test/Dockerfile.qclient -t qclient .
|
||||
sudo task build_qclient_amd64_linux
|
||||
sudo task build_qclient_arm64_linux
|
||||
# for mac, you will need to build on a mac
|
||||
```
|
||||
|
||||
This command builds the Docker image with the qclient binary according to the specifications in `Dockerfile.qclient`. The resulting image will be tagged as `qclient`.
|
||||
This command builds the Docker image with the qclient binary according to the specifications in `Dockerfile.source`. The resulting image will be tagged as `qclient`.
|
||||
|
||||
## Contributing
|
||||
|
||||
@ -152,4 +154,3 @@ When adding new distributions or versions:
|
||||
1. Update the default test configurations in the script
|
||||
2. Ensure the corresponding Dockerfile supports the new distribution/version
|
||||
3. Test the changes thoroughly before committing
|
||||
4. Verify that all dependencies in `Dockerfile.qclient` are available in the target distribution
|
||||
@ -1,5 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
CLIENT_DIR="${CLIENT_DIR:-$( cd "$(dirname "$(realpath "$( dirname "${BASH_SOURCE[0]}" )")")" >/dev/null 2>&1 && pwd )}"
|
||||
|
||||
echo "CLIENT_DIR: $CLIENT_DIR"
|
||||
|
||||
# Help function
|
||||
show_help() {
|
||||
@ -11,6 +14,7 @@ show_help() {
|
||||
echo " -v, --version VERSION Specify the version (e.g., 22.04, 12)"
|
||||
echo " -t, --tag TAG Specify a custom tag for the test container"
|
||||
echo " -h, --help Show this help message"
|
||||
echo " --no-cache Disable all Docker build cache"
|
||||
echo ""
|
||||
echo "If no arguments are provided, runs tests on all supported distributions"
|
||||
exit 0
|
||||
@ -20,6 +24,7 @@ show_help() {
|
||||
DISTRO=""
|
||||
VERSION=""
|
||||
TAG=""
|
||||
NO_CACHE=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-d|--distro)
|
||||
@ -34,6 +39,10 @@ while [[ $# -gt 0 ]]; do
|
||||
TAG="$2"
|
||||
shift 2
|
||||
;;
|
||||
--no-cache)
|
||||
NO_CACHE="--no-cache"
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
;;
|
||||
@ -44,25 +53,43 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
# Build the client binary using Dockerfile.qclient
|
||||
echo "Building client binary using Dockerfile.qclient..."
|
||||
docker build -t quil-qclient-builder -f Dockerfile.qclient ..
|
||||
docker create --name quil-qclient-temp quil-qclient-builder
|
||||
docker cp quil-qclient-temp:/usr/local/bin/qclient ./qclient
|
||||
docker rm quil-qclient-temp
|
||||
|
||||
# Function to run tests for a specific distribution
|
||||
run_distro_test() {
|
||||
local distro=$1
|
||||
local version=$2
|
||||
local tag=$3
|
||||
echo "Testing on $distro $version..."
|
||||
|
||||
# Build the base stage first (this can be cached)
|
||||
docker build \
|
||||
$NO_CACHE \
|
||||
--build-arg DISTRO=$distro \
|
||||
--build-arg VERSION=$version \
|
||||
-t quil-test-$tag-base \
|
||||
--target base \
|
||||
-f client/test/Dockerfile .
|
||||
|
||||
# Build the final test stage
|
||||
docker build \
|
||||
--build-arg DISTRO=$distro \
|
||||
--build-arg VERSION=$version \
|
||||
-t quil-test-$tag \
|
||||
-f Dockerfile .
|
||||
docker run --rm quil-test-$tag
|
||||
--target qclient-test \
|
||||
-f client/test/Dockerfile .
|
||||
|
||||
# Ensure test files are executable
|
||||
chmod +x "$CLIENT_DIR/test/test_install.sh"
|
||||
chmod +x "$CLIENT_DIR/test/test_utils.sh"
|
||||
chmod +x "$CLIENT_DIR/build/amd64_linux/qclient"
|
||||
|
||||
# Set ownership to match testuser (uid:gid 1000:1000)
|
||||
chown 1000:1000 "$CLIENT_DIR/build/amd64_linux/qclient"
|
||||
|
||||
# Run the container with mounted test directory and binary
|
||||
docker run --rm \
|
||||
-v "$CLIENT_DIR/test:/app" \
|
||||
-v "$CLIENT_DIR/build/amd64_linux/qclient:/opt/quilibrium/bin/qclient" \
|
||||
quil-test-$tag
|
||||
}
|
||||
|
||||
# If custom distro/version/tag is provided, run single test
|
||||
|
||||
109
client/test/test_install.sh
Normal file → Executable file
109
client/test/test_install.sh
Normal file → Executable file
@ -1,115 +1,90 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
|
||||
# Source the test utilities
|
||||
source "$(dirname "$0")/test_utils.sh"
|
||||
|
||||
# Get distribution information
|
||||
DISTRO=$(lsb_release -si 2>/dev/null || echo "Unknown")
|
||||
VERSION=$(lsb_release -sr 2>/dev/null || echo "Unknown")
|
||||
|
||||
echo "Starting Quilibrium node installation test on $DISTRO $VERSION..."
|
||||
|
||||
# Test: Link the qclient binary to ensure it's in the PATH
|
||||
echo "Linking qclient binary for testing..."
|
||||
if [ -f "/opt/quilibrium/bin/qclient" ]; then
|
||||
echo "qclient binary already exists at /opt/quilibrium/bin/qclient"
|
||||
else
|
||||
echo "qclient binary not found at /opt/quilibrium/bin/qclient"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test: Ensure qclient is in the PATH
|
||||
echo "Testing qclient in PATH..."
|
||||
run_test_with_format "sudo /opt/quilibrium/bin/qclient link --signature-check=false"
|
||||
run_test_with_format "which qclient"
|
||||
run_test_with_format "qclient version --signature-check=false"
|
||||
|
||||
|
||||
# Test 0: Install latest version
|
||||
# Check if download-signatures command exists in qclient help
|
||||
run_test_with_format "qclient help | grep -q 'download-signatures'"
|
||||
|
||||
# Test downloading signatures
|
||||
run_test_with_format "sudo qclient download-signatures"
|
||||
|
||||
# Test 1: Install latest version
|
||||
echo "Test 1: Installing latest version..."
|
||||
qclient node install
|
||||
run_test_with_format "sudo qclient node install"
|
||||
|
||||
get_latest_version() {
|
||||
# Fetch the latest version from the releases API
|
||||
local latest_version=$(curl -s https://releases.quilibrium.com/release | head -n 1 | cut -d'-' -f2)
|
||||
|
||||
echo "$latest_version"
|
||||
}
|
||||
|
||||
LATEST_VERSION=$(get_latest_version)
|
||||
|
||||
# Verify installation
|
||||
echo "Verifying installation..."
|
||||
if [ ! -f "/opt/quilibrium/$LATEST_VERSION/node-$LATEST_VERSION-linux-amd64" ]; then
|
||||
echo "Error: Latest version binary not found"
|
||||
exit 1
|
||||
fi
|
||||
run_test_with_format "test -f /opt/quilibrium/$LATEST_VERSION/node-$LATEST_VERSION-linux-amd64"
|
||||
|
||||
# Verify latest version matches
|
||||
echo "Verifying latest version matches..."
|
||||
get_latest_version
|
||||
run_test_with_format "get_latest_version"
|
||||
|
||||
# Test 2: Install specific version
|
||||
echo "Test 2: Installing specific version..."
|
||||
qclient node install "2.0.6.2"
|
||||
run_test_with_format "qclient node install '2.0.6.2' --signature-check=false"
|
||||
|
||||
# Verify specific version installation
|
||||
echo "Verifying specific version installation..."
|
||||
if [ ! -f "/opt/quilibrium/2.0.6.2/node-2.0.6.2-linux-amd64" ]; then
|
||||
echo "Error: Specific version binary not found"
|
||||
exit 1
|
||||
fi
|
||||
run_test_with_format "test -f /opt/quilibrium/2.0.6.2/node-2.0.6.2-linux-amd64"
|
||||
|
||||
# Test 3: Verify service file creation
|
||||
echo "Test 3: Verifying service file creation..."
|
||||
if [ ! -f "/etc/systemd/system/quilibrium-node.service" ]; then
|
||||
echo "Error: Service file not found"
|
||||
exit 1
|
||||
fi
|
||||
run_test_with_format "test -f /etc/systemd/system/quilibrium-node.service"
|
||||
|
||||
# Verify service file content
|
||||
echo "Verifying service file content..."
|
||||
if ! grep -q "EnvironmentFile=/etc/default/quilibrium-node" /etc/systemd/system/quilibrium-node.service; then
|
||||
echo "Error: Service file missing EnvironmentFile directive"
|
||||
exit 1
|
||||
fi
|
||||
run_test_with_format "grep -q 'EnvironmentFile=/etc/default/quilibrium-node' /etc/systemd/system/quilibrium-node.service"
|
||||
|
||||
# Test 4: Verify environment file
|
||||
echo "Test 4: Verifying environment file..."
|
||||
if [ ! -f "/etc/default/quilibrium-node" ]; then
|
||||
echo "Error: Environment file not found"
|
||||
exit 1
|
||||
fi
|
||||
run_test_with_format "test -f /etc/default/quilibrium-node"
|
||||
|
||||
# Verify environment file permissions
|
||||
echo "Verifying environment file permissions..."
|
||||
if [ "$(stat -c %a /etc/default/quilibrium-node)" != "640" ]; then
|
||||
echo "Error: Environment file has incorrect permissions"
|
||||
exit 1
|
||||
fi
|
||||
run_test_with_format "test '$(stat -c %a /etc/default/quilibrium-node)' = '640'"
|
||||
|
||||
# Test 5: Verify data directory
|
||||
echo "Test 5: Verifying data directory..."
|
||||
if [ ! -d "/var/lib/quilibrium" ]; then
|
||||
echo "Error: Data directory not found"
|
||||
exit 1
|
||||
fi
|
||||
run_test_with_format "test -d /var/lib/quilibrium"
|
||||
|
||||
# Verify data directory permissions
|
||||
echo "Verifying data directory permissions..."
|
||||
if [ "$(stat -c %a /var/lib/quilibrium)" != "755" ]; then
|
||||
echo "Error: Data directory has incorrect permissions"
|
||||
exit 1
|
||||
fi
|
||||
run_test_with_format "test '$(stat -c %a /var/lib/quilibrium)' = '755'"
|
||||
|
||||
# Test 6: Verify config file
|
||||
echo "Test 6: Verifying config file..."
|
||||
if [ ! -f "/var/lib/quilibrium/config/node.yaml" ]; then
|
||||
echo "Error: Config file not found"
|
||||
exit 1
|
||||
fi
|
||||
run_test_with_format "test -f /var/lib/quilibrium/config/node.yaml"
|
||||
|
||||
# Verify config file permissions
|
||||
echo "Verifying config file permissions..."
|
||||
if [ "$(stat -c %a /var/lib/quilibrium/config/node.yaml)" != "644" ]; then
|
||||
echo "Error: Config file has incorrect permissions"
|
||||
exit 1
|
||||
fi
|
||||
run_test_with_format "test '$(stat -c %a /var/lib/quilibrium/config/node.yaml)' = '644'"
|
||||
|
||||
# Test 7: Verify binary symlink
|
||||
echo "Test 7: Verifying binary symlink..."
|
||||
if [ ! -L "/usr/local/bin/quilibrium-node" ]; then
|
||||
echo "Error: Binary symlink not found"
|
||||
exit 1
|
||||
fi
|
||||
run_test_with_format "test -L /usr/local/bin/quilibrium-node"
|
||||
|
||||
# Test 8: Verify binary execution
|
||||
echo "Test 8: Verifying binary execution..."
|
||||
if ! quilibrium-node --version > /dev/null 2>&1; then
|
||||
echo "Error: Binary execution failed"
|
||||
exit 1
|
||||
fi
|
||||
run_test_with_format "quilibrium-node --version"
|
||||
|
||||
echo "All tests passed successfully on $DISTRO $VERSION!"
|
||||
49
client/test/test_utils.sh
Executable file
49
client/test/test_utils.sh
Executable file
@ -0,0 +1,49 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ANSI color codes
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to run a test command and format its output
|
||||
run_test_with_format() {
|
||||
local test_cmd="$1"
|
||||
local indent=" " # 4 spaces for indentation
|
||||
|
||||
echo -e "${BLUE}Running test: $test_cmd${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
# Run the command and capture stdout and stderr separately
|
||||
local stdout
|
||||
local stderr
|
||||
stdout=$(eval "$test_cmd" 2> >(tee /dev/stderr))
|
||||
exit_code=$?
|
||||
stderr=$(cat)
|
||||
|
||||
# Format and print the stdout with indentation
|
||||
if [ -n "$stdout" ]; then
|
||||
echo "$stdout" | while IFS= read -r line; do
|
||||
echo -e "${GREEN}$indent$line${NC}"
|
||||
done
|
||||
fi
|
||||
|
||||
# Check for stderr output and exit code
|
||||
if [ -n "$stderr" ] || [ $exit_code -ne 0 ]; then
|
||||
echo -e "${RED}${indent}Test failed:${NC}"
|
||||
if [ -n "$stderr" ]; then
|
||||
echo "$stderr" | while IFS= read -r line; do
|
||||
echo -e "${RED}${indent}$line${NC}"
|
||||
done
|
||||
fi
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
echo -e "${RED}${indent}Exit code: $exit_code${NC}"
|
||||
fi
|
||||
echo "----------------------------------------"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}${indent}Test completed successfully${NC}"
|
||||
echo "----------------------------------------"
|
||||
return 0
|
||||
}
|
||||
@ -53,7 +53,11 @@ func GetLatestVersion(releaseType ReleaseType) (string, error) {
|
||||
// DownloadReleaseFile downloads a release file from the Quilibrium releases server
|
||||
func DownloadReleaseFile(releaseType ReleaseType, fileName string, version string, showError bool) error {
|
||||
url := fmt.Sprintf("%s/%s", BaseReleaseURL, fileName)
|
||||
destPath := filepath.Join(DataPath, string(releaseType), version, fileName)
|
||||
destDir := filepath.Join(DataPath, string(releaseType), version)
|
||||
os.MkdirAll(destDir, 0755)
|
||||
destPath := filepath.Join(destDir, fileName)
|
||||
|
||||
fmt.Printf("Downloading %s to %s\n", url, destPath)
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
@ -87,6 +91,7 @@ func DownloadReleaseFile(releaseType ReleaseType, fileName string, version strin
|
||||
func DownloadReleaseSignatures(releaseType ReleaseType, version string) error {
|
||||
var files []string
|
||||
baseName := fmt.Sprintf("%s-%s-%s-%s", releaseType, version, osType, arch)
|
||||
fmt.Printf("Downloading signatures for %s\n", baseName)
|
||||
|
||||
// Add digest file URL
|
||||
files = append(files, baseName+".dgst")
|
||||
@ -94,9 +99,28 @@ func DownloadReleaseSignatures(releaseType ReleaseType, version string) error {
|
||||
// Add signature file URLs
|
||||
signerNums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}
|
||||
for _, num := range signerNums {
|
||||
// Check if the remote signature file exists
|
||||
sigFile := fmt.Sprintf("%s.dgst.sig.%d", baseName, num)
|
||||
remoteURL := fmt.Sprintf("%s/%s", BaseReleaseURL, sigFile)
|
||||
|
||||
// Make a HEAD request to check if the file exists
|
||||
resp, err := http.Head(remoteURL)
|
||||
if err != nil || resp.StatusCode != http.StatusOK {
|
||||
// Skip this file if it doesn't exist on the server
|
||||
fmt.Printf("Signature file %s not found on server, skipping\n", sigFile)
|
||||
continue
|
||||
}
|
||||
if resp != nil && resp.Body != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
files = append(files, fmt.Sprintf("%s.dgst.sig.%d", baseName, num))
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
fmt.Printf("No signature files found for %s\n", baseName)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
err := DownloadReleaseFile(releaseType, file, version, false)
|
||||
if err != nil {
|
||||
|
||||
@ -17,14 +17,14 @@ import (
|
||||
// DefaultNodeUser is the default user name for node operations
|
||||
var DefaultNodeUser = "quilibrium"
|
||||
var ClientConfigDir = filepath.Join("/etc/quilibrium/", "config")
|
||||
var ClientConfigPath = filepath.Join(ClientConfigDir, "client.yaml")
|
||||
var ClientInstallPath = filepath.Join("/opt/quilibrium/", "client")
|
||||
var ClientConfigPath = filepath.Join(ClientConfigDir, string(ReleaseTypeQClient)+".yaml")
|
||||
var ClientInstallPath = filepath.Join("/opt/quilibrium/", string(ReleaseTypeQClient))
|
||||
var DataPath = filepath.Join("/var/quilibrium/", "data")
|
||||
var ClientDataPath = filepath.Join(DataPath, "client")
|
||||
var NodeDataPath = filepath.Join(DataPath, "node")
|
||||
var NodeDefaultSymlinkDir = "/usr/local/bin"
|
||||
var DefaultNodeSymlinkPath = filepath.Join(NodeDefaultSymlinkDir, "quilibrium-node")
|
||||
var DefaultQClientSymlinkPath = filepath.Join(NodeDefaultSymlinkDir, "qclient")
|
||||
var ClientDataPath = filepath.Join(DataPath, string(ReleaseTypeQClient))
|
||||
var NodeDataPath = filepath.Join(DataPath, string(ReleaseTypeNode))
|
||||
var DefaultSymlinkDir = "/usr/local/bin"
|
||||
var DefaultNodeSymlinkPath = filepath.Join(DefaultSymlinkDir, string(ReleaseTypeNode))
|
||||
var DefaultQClientSymlinkPath = filepath.Join(DefaultSymlinkDir, string(ReleaseTypeQClient))
|
||||
var osType = runtime.GOOS
|
||||
var arch = runtime.GOARCH
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user