Merge pull request #35 from erikarvstedt/fix-ssh-port

target: use default port from SSH config
This commit is contained in:
tv 2021-11-20 15:46:09 +01:00 committed by GitHub
commit 13ae434b14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 78 additions and 55 deletions

View File

@ -6,7 +6,7 @@ krops is a lightweight toolkit to deploy NixOS systems, remotely or locally.
## Some Features ## Some Features
- store your secrets in [password store](https://www.passwordstore.org/) - store your secrets in [password store](https://www.passwordstore.org/)
- build your system remotely - build your systems remotely
- minimal overhead (it's basically just `nixos-rebuild switch`!) - minimal overhead (it's basically just `nixos-rebuild switch`!)
- run from custom nixpkgs branch/checkout/fork - run from custom nixpkgs branch/checkout/fork
@ -19,8 +19,8 @@ Create a file named `krops.nix` (name doesn't matter) with following content:
let let
krops = (import <nixpkgs> {}).fetchgit { krops = (import <nixpkgs> {}).fetchgit {
url = https://cgit.krebsco.de/krops/; url = https://cgit.krebsco.de/krops/;
rev = "v1.17.0"; rev = "v1.25.0";
sha256 = "150jlz0hlb3ngf9a1c9xgcwzz1zz8v2lfgnzw08l3ajlaaai8smd"; sha256 = "07mg3iaqjf1w49vmwfchi7b1w55bh7rvsbgicp2m47gnj9alwdb6";
}; };
lib = import "${krops}/lib"; lib = import "${krops}/lib";
@ -185,6 +185,10 @@ pkgs.krops.writeCommand "deploy-with-swap" {
[see `writeDeploy`](#writeDeploy) [see `writeDeploy`](#writeDeploy)
### `allocateTTY` (optional, defaults to false)
whether the ssh session should do a pseudo-terminal allocation.
sets `-t` on the ssh command.
## Source Types ## Source Types
@ -206,13 +210,15 @@ using [`rsync`](https://rsync.samba.org/).
Supported attributes: Supported attributes:
* `path` - * `path` -
absolute path to files that should by transfered absolute path to files that should by transferred.
* `useChecksum` (optional) - * `useChecksum` (optional) -
boolean that controls whether file contents should be checked to decide boolean that controls whether file contents should be checked to decide
whether a file has changed. This is useful when `path` points at files whether a file has changed. This is useful when `path` points at files
with mangled timestamps, e.g. the Nix store. with mangled timestamps, e.g. the Nix store.
The default value is `true` if `path` is a derivation, and `false` otherwise.
* `filters` (optional) * `filters` (optional)
List of filters that should be passed to [`rsync`](https://rsync.samba.org/). List of filters that should be passed to [`rsync`](https://rsync.samba.org/).
Filters are specified as attribute sets with the attributes `type` and Filters are specified as attribute sets with the attributes `type` and

4
ci.nix
View File

@ -5,7 +5,7 @@ let
pkgs = import "${krops}/pkgs" {}; pkgs = import "${krops}/pkgs" {};
source = lib.evalSource [{ source = lib.evalSource [{
nixos-config.file = toString (pkgs.writeText "nixos-config" '' nixos-config.file = pkgs.writeText "nixos-config" ''
{ pkgs, ... }: { { pkgs, ... }: {
fileSystems."/" = { device = "/dev/sda1"; }; fileSystems."/" = { device = "/dev/sda1"; };
@ -13,7 +13,7 @@ let
services.openssh.enable = true; services.openssh.enable = true;
environment.systemPackages = [ pkgs.git ]; environment.systemPackages = [ pkgs.git ];
} }
''); '';
nixpkgs.symlink = toString <nixpkgs>; nixpkgs.symlink = toString <nixpkgs>;
}]; }];
in { in {

View File

@ -57,9 +57,9 @@ let {
elemAt' = xs: i: if lib.length xs > i then lib.elemAt xs i else null; elemAt' = xs: i: if lib.length xs > i then lib.elemAt xs i else null;
filterNull = lib.filterAttrs (n: v: v != null); filterNull = lib.filterAttrs (n: v: v != null);
in { in {
user = lib.getEnv "LOGNAME"; user = lib.maybeEnv "LOGNAME" null;
host = lib.maybeEnv "HOSTNAME" (lib.maybeHostName "localhost"); host = lib.maybeEnv "HOSTNAME" (lib.maybeHostName "localhost");
port = "22"; port = null;
path = "/var/src"; path = "/var/src";
sudo = false; sudo = false;
extraOptions = []; extraOptions = [];
@ -70,6 +70,10 @@ let {
path = elemAt' parse 6; path = elemAt' parse 6;
} else s); } else s);
mkUserPortSSHOpts = target:
(lib.optionals (target.user != null) ["-l" target.user]) ++
(lib.optionals (target.port != null) ["-p" target.port]);
shell = let shell = let
isSafeChar = lib.testString "[-+./0-9:=A-Z_a-z]"; isSafeChar = lib.testString "[-+./0-9:=A-Z_a-z]";
quoteChar = c: quoteChar = c:

View File

@ -21,11 +21,15 @@
}; };
file = lib.mkOption { file = lib.mkOption {
apply = x: apply = x:
if lib.types.absolute-pathname.check x if lib.types.absolute-pathname.check x || lib.types.package.check x
then { path = x; } then { path = x; }
else x; else x;
default = null; default = null;
type = lib.types.nullOr (lib.types.either lib.types.absolute-pathname source-types.file); type = lib.types.nullOr (lib.types.oneOf [
lib.types.absolute-pathname
lib.types.package
source-types.file
]);
}; };
git = lib.mkOption { git = lib.mkOption {
default = null; default = null;

View File

@ -4,20 +4,14 @@ in
{ nix, openssh, populate, writers }: rec { { nix, openssh, populate, writers }: rec {
build = target:
runShell target (lib.concatStringsSep " " [
"nix build"
"-I ${lib.escapeShellArg target.path}"
"--no-link -f '<nixpkgs/nixos>'"
"config.system.build.toplevel"
]);
rebuild = args: target: rebuild = args: target:
runShell target "nixos-rebuild -I ${lib.escapeShellArg target.path} ${ runShell target {} "nixos-rebuild -I ${lib.escapeShellArg target.path} ${
lib.concatMapStringsSep " " lib.escapeShellArg args lib.concatMapStringsSep " " lib.escapeShellArg args
}"; }";
runShell = target: command: runShell = target: {
allocateTTY ? false
}: command:
let let
command' = if target.sudo then "sudo ${command}" else command; command' = if target.sudo then "sudo ${command}" else command;
in in
@ -26,9 +20,8 @@ in
else else
writers.writeDash "krops.${target.host}.${lib.firstWord command}" '' writers.writeDash "krops.${target.host}.${lib.firstWord command}" ''
exec ${openssh}/bin/ssh ${lib.escapeShellArgs (lib.flatten [ exec ${openssh}/bin/ssh ${lib.escapeShellArgs (lib.flatten [
(lib.optionals (target.user != "") ["-l" target.user]) (lib.mkUserPortSSHOpts target)
"-p" target.port (if allocateTTY then "-t" else "-T")
"-T"
target.extraOptions target.extraOptions
target.host target.host
command'])} command'])}
@ -38,6 +31,7 @@ in
command ? (targetPath: "echo ${targetPath}"), command ? (targetPath: "echo ${targetPath}"),
backup ? false, backup ? false,
force ? false, force ? false,
allocateTTY ? false,
source, source,
target target
}: let }: let
@ -46,14 +40,14 @@ in
writers.writeDash name '' writers.writeDash name ''
set -efu set -efu
${populate { inherit backup force source; target = target'; }} ${populate { inherit backup force source; target = target'; }}
${runShell target' (command target'.path)} ${runShell target' { inherit allocateTTY; } (command target'.path)}
''; '';
writeDeploy = name: { writeDeploy = name: {
backup ? false, backup ? false,
buildTarget ? null, buildTarget ? null,
crossDeploy ? false, crossDeploy ? false,
fast ? false, fast ? null,
force ? false, force ? false,
source, source,
target target
@ -64,26 +58,24 @@ in
else lib.mkTarget buildTarget; else lib.mkTarget buildTarget;
target' = lib.mkTarget target; target' = lib.mkTarget target;
in in
writers.writeDash name '' lib.traceIf (fast != null) "writeDeploy: it's now always fast, setting the `fast` attribute is deprecated and will be removed in future" (
set -efu writers.writeDash name ''
${lib.optionalString (buildTarget' != target') set -efu
(populate { inherit backup force source; target = buildTarget'; })} ${lib.optionalString (buildTarget' != target')
${populate { inherit backup force source; target = target'; }} (populate { inherit backup force source; target = buildTarget'; })}
${lib.optionalString (! fast) '' ${populate { inherit backup force source; target = target'; }}
${rebuild ["dry-build"] buildTarget'} ${rebuild ([
${build buildTarget'} "switch"
''} ] ++ lib.optionals crossDeploy [
${rebuild ([ "--no-build-nix"
"switch" ] ++ lib.optionals (buildTarget' != target') [
] ++ lib.optionals crossDeploy [ "--build-host" "${buildTarget'.user}@${buildTarget'.host}"
"--no-build-nix" "--target-host" "${target'.user}@${target'.host}"
] ++ lib.optionals (buildTarget' != target') [ ] ++ lib.optionals target'.sudo [
"--build-host" "${buildTarget'.user}@${buildTarget'.host}" "--use-remote-sudo"
"--target-host" "${target'.user}@${target'.host}" ]) buildTarget'}
] ++ lib.optionals target'.sudo [ ''
"--use-remote-sudo" );
]) buildTarget'}
'';
writeTest = name: { writeTest = name: {
backup ? false, backup ? false,

View File

@ -45,10 +45,21 @@ let
''; '';
pop.file = target: source: let pop.file = target: source: let
configAttrs = ["useChecksum" "exclude" "filters" "deleteExcluded"]; config = rsyncDefaultConfig // derivedConfig // sourceConfig;
config = filterAttrs (name: _: elem name configAttrs) source; derivedConfig = {
useChecksum =
if isStorePath source.path
then true
else rsyncDefaultConfig.useChecksum;
};
sourceConfig =
filterAttrs (name: _: elem name (attrNames rsyncDefaultConfig)) source;
sourcePath =
if isStorePath source.path
then quote (toString source.path)
else quote source.path;
in in
rsync' target config (quote source.path); rsync' target config sourcePath;
pop.git = target: source: runShell target /* sh */ '' pop.git = target: source: runShell target /* sh */ ''
set -efu set -efu
@ -144,7 +155,7 @@ let
echo "$local_pass_info" > "$tmp_dir"/.pass_info echo "$local_pass_info" > "$tmp_dir"/.pass_info
fi fi
${rsync' target {} /* sh */ "$tmp_dir"} ${rsync' target rsyncDefaultConfig /* sh */ "$tmp_dir"}
''; '';
pop.pipe = target: source: /* sh */ '' pop.pipe = target: source: /* sh */ ''
@ -172,17 +183,17 @@ let
source_path=$source_path/ source_path=$source_path/
fi fi
${rsync}/bin/rsync \ ${rsync}/bin/rsync \
${optionalString (config.useChecksum or false) /* sh */ "--checksum"} \ ${optionalString config.useChecksum /* sh */ "--checksum"} \
${optionalString target.sudo /* sh */ "--rsync-path=\"sudo rsync\""} \ ${optionalString target.sudo /* sh */ "--rsync-path=\"sudo rsync\""} \
${concatMapStringsSep " " ${concatMapStringsSep " "
(pattern: /* sh */ "--exclude ${quote pattern}") (pattern: /* sh */ "--exclude ${quote pattern}")
(config.exclude or [])} \ config.exclude} \
${concatMapStringsSep " " ${concatMapStringsSep " "
(filter: /* sh */ "--${filter.type} ${quote filter.pattern}") (filter: /* sh */ "--${filter.type} ${quote filter.pattern}")
(config.filters or [])} \ config.filters} \
-e ${quote (ssh' target)} \ -e ${quote (ssh' target)} \
-vFrlptD \ -vFrlptD \
${optionalString (config.deleteExcluded or true) /* sh */ "--delete-excluded"} \ ${optionalString config.deleteExcluded /* sh */ "--delete-excluded"} \
"$source_path" \ "$source_path" \
${quote ( ${quote (
optionalString (!isLocalTarget target) ( optionalString (!isLocalTarget target) (
@ -194,6 +205,13 @@ let
>&2 >&2
''; '';
rsyncDefaultConfig = {
useChecksum = false;
exclude = [];
filters = [];
deleteExcluded = true;
};
runShell = target: command: runShell = target: command:
if isLocalTarget target if isLocalTarget target
then command then command
@ -206,8 +224,7 @@ let
ssh' = target: concatMapStringsSep " " quote (flatten [ ssh' = target: concatMapStringsSep " " quote (flatten [
"${openssh}/bin/ssh" "${openssh}/bin/ssh"
(optionals (target.user != "") ["-l" target.user]) (mkUserPortSSHOpts target)
"-p" target.port
"-T" "-T"
target.extraOptions target.extraOptions
]); ]);