diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 518c5c4..47c7486 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -2,6 +2,11 @@ name: Docker on: workflow_dispatch: + inputs: + platforms: + description: 'Platforms to build the container for' + required: true + default: 'linux/amd64,linux/arm/v7,linux/arm64' jobs: multi: @@ -16,6 +21,13 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 + - name: Cache Docker layers + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- - name: Login to DockerHub uses: docker/login-action@v1 @@ -28,7 +40,7 @@ jobs: with: context: . file: ./Dockerfile - platforms: linux/amd64,linux/arm/v7,linux/arm64 + platforms: ${{github.events.inputs.platforms}} push: true tags: | trivernis/snekcloud-server:alpine \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 8a30444..9f2bcd7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,4 @@ +# syntax=docker/dockerfile:1.0-experimental FROM alpine AS builder RUN apk add --no-cache build-base cargo WORKDIR /usr/src @@ -5,15 +6,19 @@ RUN USER=root cargo new snekcloud-server WORKDIR /usr/src/snekcloud-server COPY Cargo.toml Cargo.lock ./ COPY src ./src -RUN cargo build --release -WORKDIR target/release/ +RUN --mount=type=cache,target=/usr/local/cargo/registry \ + --mount=type=cache,target=target \ + cargo build --release +RUN mkdir /tmp/snekcloud +RUN --mount=type=cache,target=target cp target/release/snekcloud-server /tmp/snekcloud/ +WORKDIR /tmp/snekcloud RUN ./snekcloud-server generate-key private_key RUN timeout 1s ./snekcloud-server || exit 0 RUN cp config/00_default.toml config/10_local.toml +RUN rm private_key FROM alpine -COPY --from=builder /usr/lib/libgcc* /usr/lib -COPY --from=builder /usr/src/snekcloud-server/target/release/snekcloud-server . -COPY --from=builder /usr/src/snekcloud-server/target/release/config / -COPY --from=builder /usr/src/snekcloud-server/target/release/private_key / +RUN apk add --no-cache build-base +COPY --from=builder /tmp/snekcloud/snekcloud-server . +COPY --from=builder /tmp/snekcloud/config / ENTRYPOINT ["/snekcloud-server"] \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 8516db5..d102b27 100644 --- a/src/main.rs +++ b/src/main.rs @@ -57,21 +57,8 @@ fn main() -> SnekcloudResult<()> { if let Some(command) = opt.sub_command { match command { - SubCommand::GenerateKey(options) => { - let key = generate_private_key(); - let string_content = armor_private_key(key); - fs::write(options.output_file, string_content)?; - } - SubCommand::WriteInfoFile(options) => { - settings.validate(); - let key = get_private_key(&settings)?; - let data = NodeData::with_addresses( - settings.node_id, - settings.listen_addresses, - key.public_key(), - ); - data.write_to_file(options.output_file)?; - } + SubCommand::GenerateKey(options) => generate_key(&options.output_file)?, + SubCommand::WriteInfoFile(options) => write_info_file(&settings, &options.output_file)?, } } else { start_server(opt, &settings)?; @@ -80,16 +67,45 @@ fn main() -> SnekcloudResult<()> { Ok(()) } -fn start_server(_options: Opt, settings: &Settings) -> SnekcloudResult<()> { +fn generate_key(output_file: &PathBuf) -> SnekcloudResult<()> { + log::info!("Generating new private key to {:?}", output_file); + let key = generate_private_key(); + let string_content = armor_private_key(key); + fs::write(output_file, string_content)?; + log::trace!("Done!"); + + Ok(()) +} + +fn write_info_file(settings: &Settings, output_file: &PathBuf) -> SnekcloudResult<()> { settings.validate(); - let keys = read_node_keys(&settings.node_data_dir)?; - let private_key = get_private_key(settings)?; + let key = get_private_key(&settings)?; let data = NodeData::with_addresses( settings.node_id.clone(), settings.listen_addresses.clone(), - private_key.public_key(), + key.public_key(), ); - data.write_to_file(settings.node_data_dir.join(PathBuf::from("local.toml")))?; + log::info!("Writing info file to {:?}", output_file); + data.write_to_file(output_file.clone())?; + log::info!("Done!"); + + Ok(()) +} + +fn start_server(_options: Opt, settings: &Settings) -> SnekcloudResult<()> { + if !settings.private_key.exists() { + generate_key(&settings.private_key)?; + } + settings.validate(); + let keys = read_node_keys(&settings.node_data_dir)?; + let private_key = get_private_key(settings)?; + write_info_file( + &settings, + &settings + .node_data_dir + .clone() + .join(PathBuf::from("local.toml")), + )?; let mut server = SnekcloudServer::new( settings.node_id.clone(), @@ -108,6 +124,7 @@ fn start_server(_options: Opt, settings: &Settings) -> SnekcloudResult<()> { Ok(()) } +#[inline] fn get_private_key(settings: &Settings) -> SnekcloudResult { extract_private_key(&fs::read_to_string(&settings.private_key)?) } diff --git a/src/utils/keys.rs b/src/utils/keys.rs index 57f3666..34e6910 100644 --- a/src/utils/keys.rs +++ b/src/utils/keys.rs @@ -47,6 +47,7 @@ pub fn read_node_keys(path: &PathBuf) -> SnekcloudResult> { } /// Reads the private key from a file +#[inline] pub fn extract_private_key(content: &str) -> SnekcloudResult { let bytes = extract_key(content, PRIVATE_KEY_HEADER_LINE, PRIVATE_KEY_FOOTER_LINE)?; @@ -54,6 +55,7 @@ pub fn extract_private_key(content: &str) -> SnekcloudResult { } /// Reads the public key from a file +#[inline] pub fn extract_public_key(content: &str) -> SnekcloudResult { let bytes = extract_key(content, PUBLIC_KEY_HEADER_LINE, PUBLIC_KEY_FOOTER_LINE)?; @@ -77,6 +79,7 @@ fn extract_key(content: &str, prefix: &str, suffix: &str) -> SnekcloudResult<[u8 } /// Encodes and encases the public key for text representation +#[inline] pub fn armor_public_key(key: PublicKey) -> String { armor_key( key.to_bytes(), @@ -86,6 +89,7 @@ pub fn armor_public_key(key: PublicKey) -> String { } /// Encodes and encases the secret key for text representation +#[inline] pub fn armor_private_key(key: SecretKey) -> String { armor_key( key.to_bytes(), @@ -95,11 +99,13 @@ pub fn armor_private_key(key: SecretKey) -> String { } /// Returns an armored key +#[inline] fn armor_key(key: [u8; 32], prefix: &str, suffix: &str) -> String { format!("{}{}{}", prefix, base64::encode(key), suffix) } /// Generates a new private key +#[inline] pub fn generate_private_key() -> SecretKey { SecretKey::generate(&mut rand::thread_rng()) }