Add interface with json schema, fix flake-less issues, put setActivate and jsonSchema check in flake lib

This commit is contained in:
notgne2 2020-10-05 19:46:28 -07:00
parent 5674670a59
commit 7c00fd2761
No known key found for this signature in database
GPG Key ID: BB661E172B42A7F8
8 changed files with 371 additions and 71 deletions

View File

@ -1,6 +1,73 @@
{
"nodes": {
"deploy-rs": {
"inputs": {
"naersk": "naersk",
"nixpkgs": "nixpkgs_2",
"utils": "utils"
},
"locked": {
"lastModified": 1601668691,
"narHash": "sha256-1mWf71DPRNgTIUKJ4Dy+CjoyZo4JkPdrwjYJy2UzqZE=",
"type": "git",
"url": "file:///home/notgne2/Dev/Serokell/deploy-rs"
},
"original": {
"owner": "serokell",
"repo": "deploy-rs",
"type": "github"
}
},
"naersk": {
"inputs": {
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1597138680,
"narHash": "sha256-3pDN/W17wjVDbrkgo60xQSb24+QAPQ7ulsUq5atNni0=",
"owner": "nmattia",
"repo": "naersk",
"rev": "529e910a3f423a8211f8739290014b754b2555b6",
"type": "github"
},
"original": {
"owner": "nmattia",
"ref": "master",
"repo": "naersk",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1601091160,
"narHash": "sha256-26UI9LGjRO8Sv253zJZkoapP260QkJPQ2+vRyC1i+kI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2768436826543af2b1540e4fe6b5afa15850e155",
"type": "github"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1600387253,
"narHash": "sha256-WtdpHuiunPF9QMlcXrWJkESuIjSSjP9WMOKvYQS/D7M=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "72b9660dc18ba347f7cd41a9504fc181a6d87dc3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1592491430,
"narHash": "sha256-7WNpr16iUyjG4caad137nCqxXNTdct202jy05lslZXA=",
@ -16,7 +83,23 @@
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
"deploy-rs": "deploy-rs",
"nixpkgs": "nixpkgs_3"
}
},
"utils": {
"locked": {
"lastModified": 1600209923,
"narHash": "sha256-zoOWauTliFEjI++esk6Jzk7QO5EKpddWXQm9yQK24iM=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "3cd06d3c1df6879c9e41cb2c33113df10566c760",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
}
},

View File

@ -5,7 +5,9 @@
{
description = "Deploy GNU hello to localhost";
outputs = { self, nixpkgs }:
inputs.deploy-rs.url = "github:serokell/deploy-rs";
outputs = { self, nixpkgs, deploy-rs }:
let
setActivate = base: activate: nixpkgs.legacyPackages.x86_64-linux.symlinkJoin {
name = ("activatable-" + base.name);
@ -29,16 +31,10 @@
hostname = "localhost";
profiles.hello = {
user = "balsoft";
path = setActivate nixpkgs.legacyPackages.x86_64-linux.hello "./bin/hello";
path = deploy-rs.lib.x86_64-linux.setActivate nixpkgs.legacyPackages.x86_64-linux.hello "./bin/hello";
};
};
checks = builtins.mapAttrs
(_: pkgs: {
jsonschema = pkgs.runCommandNoCC "jsonschema-deploy-simple" { }
"${pkgs.python3.pkgs.jsonschema}/bin/jsonschema -i ${
pkgs.writeText "deploy.json" (builtins.toJSON self.deploy)
} ${../../interface/deploy.json} && touch $out";
})
nixpkgs.legacyPackages;
checks = { "x86_64-linux" = { jsonSchema = deploy-rs.lib.x86_64-linux.checkSchema self.deploy; }; };
};
}

View File

@ -1,6 +1,73 @@
{
"nodes": {
"deploy-rs": {
"inputs": {
"naersk": "naersk",
"nixpkgs": "nixpkgs_2",
"utils": "utils"
},
"locked": {
"lastModified": 1601668691,
"narHash": "sha256-HvzPMsgSOQfCRoPtkwLRv09CkNjOsLHjcZtyHF+8Zbs=",
"type": "git",
"url": "file:///home/notgne2/Dev/Serokell/deploy-rs"
},
"original": {
"owner": "serokell",
"repo": "deploy-rs",
"type": "github"
}
},
"naersk": {
"inputs": {
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1597138680,
"narHash": "sha256-3pDN/W17wjVDbrkgo60xQSb24+QAPQ7ulsUq5atNni0=",
"owner": "nmattia",
"repo": "naersk",
"rev": "529e910a3f423a8211f8739290014b754b2555b6",
"type": "github"
},
"original": {
"owner": "nmattia",
"ref": "master",
"repo": "naersk",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1601091160,
"narHash": "sha256-26UI9LGjRO8Sv253zJZkoapP260QkJPQ2+vRyC1i+kI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2768436826543af2b1540e4fe6b5afa15850e155",
"type": "github"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1600387253,
"narHash": "sha256-WtdpHuiunPF9QMlcXrWJkESuIjSSjP9WMOKvYQS/D7M=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "72b9660dc18ba347f7cd41a9504fc181a6d87dc3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1592491430,
"narHash": "sha256-7WNpr16iUyjG4caad137nCqxXNTdct202jy05lslZXA=",
@ -16,7 +83,23 @@
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
"deploy-rs": "deploy-rs",
"nixpkgs": "nixpkgs_3"
}
},
"utils": {
"locked": {
"lastModified": 1600209923,
"narHash": "sha256-zoOWauTliFEjI++esk6Jzk7QO5EKpddWXQm9yQK24iM=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "3cd06d3c1df6879c9e41cb2c33113df10566c760",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
}
},

View File

@ -5,65 +5,42 @@
{
description = "Deploy a full system with hello service as a separate profile";
outputs = { self, nixpkgs }:
let
setActivate = base: activate: nixpkgs.legacyPackages.x86_64-linux.symlinkJoin {
name = ("activatable-" + base.name);
paths = [
base
(nixpkgs.legacyPackages.x86_64-linux.writeTextFile {
name = base.name + "-activate-path";
text = ''
#!${nixpkgs.legacyPackages.x86_64-linux.runtimeShell}
${activate}
'';
executable = true;
destination = "/activate";
})
];
};
in
{
nixosConfigurations.example-nixos-system = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [ ./configuration.nix ];
};
inputs.deploy-rs.url = "github:serokell/deploy-rs";
nixosConfigurations.bare = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules =
[ ./bare.nix "${nixpkgs}/nixos/modules/virtualisation/qemu-vm.nix" ];
};
outputs = { self, nixpkgs, deploy-rs }: {
nixosConfigurations.example-nixos-system = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [ ./configuration.nix ];
};
# This is the application we actually want to run
defaultPackage.x86_64-linux = import ./hello.nix nixpkgs;
nixosConfigurations.bare = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules =
[ ./bare.nix "${nixpkgs}/nixos/modules/virtualisation/qemu-vm.nix" ];
};
deploy.nodes.example = {
sshOpts = [ "-p" "2221" ];
hostname = "localhost";
fastConnection = true;
profiles = {
system = {
sshUser = "admin";
path =
setActivate self.nixosConfigurations.example-nixos-system.config.system.build.toplevel "./bin/switch-to-configuration switch";
user = "root";
};
hello = {
sshUser = "hello";
path = setActivate self.defaultPackage.x86_64-linux "./bin/activate";
user = "hello";
};
# This is the application we actually want to run
defaultPackage.x86_64-linux = import ./hello.nix nixpkgs;
deploy.nodes.example = {
sshOpts = [ "-p" "2221" ];
hostname = "localhost";
fastConnection = true;
profiles = {
system = {
sshUser = "admin";
path =
deploy-rs.lib.x86_64-linux.setActivate self.nixosConfigurations.example-nixos-system.config.system.build.toplevel "./bin/switch-to-configuration switch";
user = "root";
};
hello = {
sshUser = "hello";
path = deploy-rs.lib.x86_64-linux.setActivate self.defaultPackage.x86_64-linux "./bin/activate";
user = "hello";
};
};
checks = builtins.mapAttrs
(_: pkgs: {
jsonschema = pkgs.runCommandNoCC "jsonschema-deploy-system" { }
"${pkgs.python3.pkgs.jsonschema}/bin/jsonschema -i ${
pkgs.writeText "deploy.json" (builtins.toJSON self.deploy)
} ${../../interface/deploy.json} && touch $out";
})
nixpkgs.legacyPackages;
};
checks = { "x86_64-linux" = { jsonSchema = deploy-rs.lib.x86_64-linux.checkSchema self.deploy; }; };
};
}

View File

@ -14,12 +14,35 @@
let
pkgs = import nixpkgs { inherit system; };
naersk-lib = pkgs.callPackage naersk { };
in {
setActivate = base: activate: pkgs.symlinkJoin {
name = ("activatable-" + base.name);
paths = [
base
(pkgs.writeTextFile {
name = base.name + "-activate-path";
text = ''
#!${pkgs.runtimeShell}
${activate}
'';
executable = true;
destination = "/activate";
})
];
};
in
{
defaultPackage = naersk-lib.buildPackage ./.;
defaultApp = {
type = "app";
program = "${self.defaultPackage."${system}"}/bin/deploy";
};
lib = {
inherit setActivate;
checkSchema = deploy: pkgs.runCommandNoCC "jsonschema-deploy-system" { }
"${pkgs.python3.pkgs.jsonschema}/bin/jsonschema -i ${pkgs.writeText "deploy.json" (builtins.toJSON deploy)} ${./interface/deploy.json} && touch $out";
};
});
}

32
interface/README.md Normal file
View File

@ -0,0 +1,32 @@
A flake must have a `deploy` output with the following structure:
```
deploy
├── <generic args>
└── nodes
├── <NODE>
│   ├── <generic args>
│   ├── hostname
│   └── profiles
│   ├── <PROFILE>
│   │   ├── <generic args>
│   │   ├── bootstrap
│   │   └── path
│   └── <PROFILE>...
└── <NODE>...
```
Where `<generic args>` are all optional and can be one or multiple of:
- `sshUser` -- user to connect as
- `user` -- user to install and activate profiles with
- `sshOpts` -- options passed to `nix copy` and `ssh`
- `fastConnection` -- whether the connection from this host to the target one is fast (if it is, don't substitute on target and copy the entire closure) [default: `false`]
- `autoRollback` -- whether to roll back when the deployment fails [default: `false`]
A formal definition for the structure can be found in [the JSON schema](./deploy.json)
For every profile of every node, arguments are merged with `<PROFILE>` taking precedence over `<NODE>` and `<NODE>` taking precedence over top-level.
Values can be overridden for all the profiles deployed by setting environment variables with the same names as the profile, for example `sshUser=foobar nix run github:serokell/deploy .` will connect to all nodes as `foobar@<NODE>.hostname`.

103
interface/deploy.json Normal file
View File

@ -0,0 +1,103 @@
{
"$schema": "http://json-schema.org/draft/2019-09/schema#",
"title": "Deploy",
"description": "Matches a correct deploy attribute of a flake",
"definitions": {
"generic_settings": {
"type": "object",
"properties": {
"sshUser": {
"type": "string"
},
"user": {
"type": "string"
},
"sshOpts": {
"type": "array",
"items": {
"type": "string"
}
},
"fastConnection": {
"type": "boolean"
},
"autoRollback": {
"type": "boolean"
}
}
},
"node_settings": {
"type": "object",
"properties": {
"hostname": {
"type": "string"
}
},
"required": [
"hostname"
]
},
"profile_settings": {
"type": "object",
"properties": {
"path": {
"type": "string"
},
"bootstrap": {
"type": "string"
}
},
"required": [
"path"
]
}
},
"type": "object",
"allOf": [
{
"$ref": "#/definitions/generic_settings"
},
{
"type": "object",
"properties": {
"nodes": {
"type": "object",
"patternProperties": {
"[A-z][A-z0-9_-]*": {
"allOf": [
{
"$ref": "#/definitions/generic_settings"
},
{
"$ref": "#/definitions/node_settings"
},
{
"type": "object",
"properties": {
"profiles": {
"type": "object",
"patternProperties": {
"[A-z][A-z0-9_-]*": {
"allOf": [
{
"$ref": "#/definitions/generic_settings"
},
{
"$ref": "#/definitions/profile_settings"
}
]
}
},
"additionalProperties": false
}
}
}
]
}
},
"additionalProperties": false
}
}
}
]
}

View File

@ -10,6 +10,7 @@ use tokio::process::Command;
use merge::Merge;
extern crate pretty_env_logger;
#[macro_use]
extern crate log;
@ -177,12 +178,14 @@ async fn get_deployment_data(
let mut c = match supports_flakes {
true => Command::new("nix"),
false => Command::new("nix-instanciate"),
false => Command::new("nix-instantiate"),
};
let mut build_command = match supports_flakes {
true => {
c.arg("eval").arg("--json").arg(format!("{}#deploy", repo))
c.arg("eval")
.arg("--json")
.arg(format!("{}#deploy", repo))
}
false => {
c
@ -190,7 +193,7 @@ async fn get_deployment_data(
.arg("--read-write-mode")
.arg("--json")
.arg("--eval")
.arg("--E")
.arg("-E")
.arg(format!("let r = import {}/.; in if builtins.isFunction r then (r {{}}).deploy else r.deploy", repo))
}
};