Compare commits

...

12 Commits

Author SHA1 Message Date
Dimitris Karakasilis
44ccb84dfb Merge pull request #4 from kairos-io/create-info-file-if-not-exists
Create the partition file if it doesn't exist
2022-11-15 12:39:00 +02:00
Dimitris Karakasilis
a0a7c1269f Create the partition file if id doesn't exist
so that the caller doesn't have to care if it's the first time the
partition is encrypted or not.

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2022-11-15 12:17:32 +02:00
Dimitris Karakasilis
14664b6644 Merge pull request #3 from kairos-io/380-return-partition-mapping-data
Make `kcrypt encrypt` return useful lable/uuid mapping data
2022-11-11 15:13:16 +02:00
Dimitris Karakasilis
29f22e7f92 Update partition label with the store one before asking for a passphrase
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2022-11-11 13:14:31 +02:00
Dimitris Karakasilis
4a6c79f6a6 Change to a more object-oriented approach
Now the code can simply initialize a PartitionInfo from a file and then
call LookupUUIDForLabel on it.

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2022-11-11 13:06:00 +02:00
Dimitris Karakasilis
8ca95e953b Add functions to produce a string representation of a partition
so that we encapsulate all the logic in the same package

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2022-11-11 12:11:43 +02:00
Dimitris Karakasilis
c0d6b81b5d Add github action pipeline to run unit tests
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2022-11-11 11:47:18 +02:00
Dimitris Karakasilis
82c6e8fcd0 Create parition info parsing library
to be used both here (when trying to find the partition UUID using a
label) and on the kairos side when updating the file after calling
kcrypt to encrypt a partition (which causes the UUID to change).

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2022-11-11 10:55:46 +02:00
Dimitris Karakasilis
d84b1ea2c2 Make kcrypt encrypt return useful lable/uuid mapping data
part of: https://github.com/kairos-io/kairos/issues/380

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2022-11-10 16:21:48 +02:00
Ettore Di Giacinto
aa620714a5 Add /oem/system/discovery 2022-10-17 19:15:40 +00:00
Ettore Di Giacinto
c9680590bf Conditionals bring still deps in systemd
Generate instead of enabling both services
2022-10-15 21:14:06 +00:00
Ettore Di Giacinto
d496900927 Add online service 2022-10-15 17:17:10 +00:00
13 changed files with 447 additions and 35 deletions

26
.github/workflows/unit-tests.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Unit tests
on:
push:
branches:
- master
pull_request:
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '^1.18'
- name: Install Ginkgo
run: go install github.com/onsi/ginkgo/v2/ginkgo@v2.5.0
- name: Run tests
run: |
ginkgo run ./...

40
dracut/29kcrypt/generator.sh Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/bash
type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
GENERATOR_DIR="$2"
[ -z "$GENERATOR_DIR" ] && exit 1
[ -d "$GENERATOR_DIR" ] || mkdir "$GENERATOR_DIR"
if getargbool 0 rd.neednet; then
{
echo "[Unit]"
echo "DefaultDependencies=no"
echo "Description=kcrypt online mount"
echo "Before=cos-immutable-rootfs.service"
echo "After=network-online.target"
echo "Wants=network-online.target"
echo "[Service]"
echo "Type=oneshot"
echo "RemainAfterExit=no"
echo "ExecStart=/sbin/kcrypt-mount-local"
} > "$GENERATOR_DIR"/kcrypt.service
else
{
echo "[Unit]"
echo "DefaultDependencies=no"
echo "Description=kcrypt mount"
echo "Before=cos-immutable-rootfs.service"
echo "[Service]"
echo "Type=oneshot"
echo "RemainAfterExit=no"
echo "ExecStart=/sbin/kcrypt-mount-local"
} > "$GENERATOR_DIR"/kcrypt.service
fi
if [ ! -e "$GENERATOR_DIR/initrd-fs.target.requires/kcrypt.service" ]; then
mkdir -p "$GENERATOR_DIR"/initrd-fs.target.requires
ln -s "$GENERATOR_DIR"/kcrypt.service \
"$GENERATOR_DIR"/initrd-fs.target.requires/kcrypt.service
fi

View File

@@ -1,9 +0,0 @@
[Unit]
Description=kcrypt mount
DefaultDependencies=no
Before=cos-immutable-rootfs.service
[Service]
Type=oneshot
RemainAfterExit=no
ExecStart=/sbin/kcrypt-mount-local

View File

@@ -29,10 +29,8 @@ install() {
kcrypt
inst_script "${moddir}/mount-local.sh" "/sbin/kcrypt-mount-local"
#inst_hook pre-trigger 10 "$moddir/mount-local.sh"
inst_simple "${moddir}/kcrypt.service" \
"${systemdsystemunitdir}/kcrypt.service"
mkdir -p "${initdir}/${systemdsystemunitdir}/initrd-fs.target.requires"
ln_r "../kcrypt.service" \
"${systemdsystemunitdir}/initrd-fs.target.requires/kcrypt.service"
inst_script "${moddir}/generator.sh" \
"${systemdutildir}/system-generators/dracut-kcrypt-generator"
dracut_need_initqueue
}

View File

@@ -2,6 +2,10 @@
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh
type getarg > /dev/null 2>&1 || . /lib/dracut-lib.sh
PATH=/usr/sbin:/usr/bin:/sbin:/bin
OEM=$(blkid -L COS_OEM)
if [ "$OEM" != "" ]; then
mkdir /oem

12
go.mod
View File

@@ -7,8 +7,12 @@ require (
github.com/hashicorp/go-multierror v1.1.1
github.com/jaypipes/ghw v0.9.0
github.com/mudler/go-pluggable v0.0.0-20220716112424-189d463e3ff3
github.com/onsi/ginkgo/v2 v2.5.0
github.com/onsi/gomega v1.24.0
github.com/otiai10/copy v1.7.0
github.com/pkg/errors v0.9.1
github.com/urfave/cli v1.22.9
gopkg.in/yaml.v3 v3.0.1
)
require (
@@ -17,16 +21,18 @@ require (
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/jaypipes/pcidb v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/sys v0.0.0-20220803195053-6e608f9ce704 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/net v0.1.0 // indirect
golang.org/x/sys v0.1.0 // indirect
golang.org/x/text v0.4.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
howett.net/plist v1.0.0 // indirect
)

24
go.sum
View File

@@ -16,6 +16,8 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
@@ -26,9 +28,12 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
@@ -57,10 +62,13 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M=
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo/v2 v2.5.0 h1:TRtrvv2vdQqzkwrQ1ke6vtXf7IK34RBUJafIy1wMwls=
github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/onsi/gomega v1.24.0 h1:+0glovB9Jd6z3VR+ScSwQqXVTIfJcGA9UBM8yzQxhqg=
github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
@@ -90,7 +98,8 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -103,15 +112,14 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220803195053-6e608f9ce704 h1:Y7NOhdqIOU8kYI7BxsgL38d0ot0raxvcW+EMQU2QrT4=
golang.org/x/sys v0.0.0-20220803195053-6e608f9ce704/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -119,6 +127,7 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -132,5 +141,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=

38
main.go
View File

@@ -17,6 +17,8 @@ import (
"github.com/mudler/go-pluggable"
cp "github.com/otiai10/copy"
"github.com/urfave/cli"
pi "github.com/kairos-io/kcrypt/pkg/partition_info"
)
func waitdevice(device string, attempts int) error {
@@ -109,45 +111,50 @@ func createDiskImage() (*os.File, error) {
// this function should delete COS_PERSISTENT. delete the partition and create a luks+type in place.
// Take a part label, and recreates it with LUKS. IT OVERWRITES DATA!
func luksify(label string) error {
// On success, it returns a machine parseable string with the partition information
// (label:name:uuid) so that it can be stored by the caller for later use.
// This is because the label of the encrypted partition is not accessible unless
// the partition is decrypted first and the uuid changed after encryption so
// any stored information needs to be updated (by the caller).
func luksify(label string) (string, error) {
// blkid
persistent, b, err := findPartition(label)
if err != nil {
return err
return "", err
}
pass, err := getPassword(b)
if err != nil {
return err
return "", err
}
persistent = fmt.Sprintf("/dev/%s", persistent)
devMapper := fmt.Sprintf("/dev/mapper/%s", b.Name)
if err := createLuks(persistent, pass, "luks1"); err != nil {
return err
return "", err
}
if err := luksUnlock(persistent, b.Name, pass); err != nil {
return err
return "", err
}
if err := waitdevice(devMapper, 10); err != nil {
return err
return "", err
}
out, err := sh(fmt.Sprintf("mkfs.ext4 -L %s %s", label, devMapper))
if err != nil {
return fmt.Errorf("err: %w, out: %s", err, out)
return "", fmt.Errorf("err: %w, out: %s", err, out)
}
out2, err := sh(fmt.Sprintf("cryptsetup close %s", b.Name))
if err != nil {
return fmt.Errorf("err: %w, out: %s", err, out2)
return "", fmt.Errorf("err: %w, out: %s", err, out2)
}
return nil
return pi.PartitionToString(b), nil
}
func findPartition(label string) (string, *block.Partition, error) {
@@ -272,11 +279,17 @@ func injectInitrd(initrd string, file, dst string) error {
func unlockAll() error {
bus.Manager.Initialize()
partitionInfo, err := pi.NewPartitionInfoFromFile(pi.DefaultPartitionInfoFile)
if err != nil {
return err
}
block, err := ghw.Block()
if err == nil {
for _, disk := range block.Disks {
for _, p := range disk.Partitions {
if p.Type == "crypto_LUKS" {
p.Label = partitionInfo.LookupLabelForUUID(p.UUID)
fmt.Printf("Unmounted Luks found at '%s' LABEL '%s' \n", p.Name, p.Label)
err = multierror.Append(err, unlockDisk(p))
if err != nil {
@@ -318,7 +331,12 @@ func main() {
if c.NArg() != 1 {
return fmt.Errorf("requires 1 arg, the partition label")
}
return luksify(c.Args().First())
out, err := luksify(c.Args().First())
if err != nil {
return err
}
fmt.Println(out)
return nil
},
},
{

View File

@@ -28,7 +28,7 @@ type Bus struct {
func (b *Bus) LoadProviders() {
wd, _ := os.Getwd()
b.Manager.Autoload("kcrypt-discovery", "/system/discovery", "/oem/kcrypt", wd).Register()
b.Manager.Autoload("kcrypt-discovery", "/system/discovery", "/oem/kcrypt", "/oem/system/discovery", wd).Register()
}
func (b *Bus) Initialize() {

View File

@@ -0,0 +1,125 @@
package partition_info
import (
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/jaypipes/ghw/pkg/block"
"github.com/pkg/errors"
"gopkg.in/yaml.v3"
)
const DefaultPartitionInfoFile = "/oem/partition_info.yaml"
// PartitionInfo maps a partition label to a partition UUID.
// It's used in order to be able to ask the kcrypt-challenger for the passphrase
// using the partition label, even when the label is not accessible (e.g. before
// decrypting the partition). The UUID can be used to lookup the partition label
// and make the request.
type PartitionInfo struct {
file string
mapping map[string]string
}
// NewPartitionInfoFromFile reads the given partition info file (if one exists)
// and returns a pointer to a PartitionInfo object.
// If a file doesn't exist, the function will create one and return an "empty"
// PartitionInfo object.
// The boolean return value indicates whether a file existed or not (true means,
// a file existed already).
func NewPartitionInfoFromFile(file string) (*PartitionInfo, bool, error) {
existed, err := createInfoFileIfNotExists(file)
if err != nil {
return nil, existed, err
}
mapping, err := ParsePartitionInfoFile(file)
if err != nil {
return nil, existed, err
}
return &PartitionInfo{
file: file,
mapping: mapping,
}, existed, nil
}
func (pi PartitionInfo) LookupUUIDForLabel(l string) string {
return pi.mapping[l]
}
func (pi PartitionInfo) LookupLabelForUUID(uuid string) string {
for k, v := range pi.mapping {
if v == uuid {
return k
}
}
return ""
}
// UpdatePartitionLabelMapping takes partition information as a string argument
// the the form: `label:name:uuid` (that's what the `kcrypt encrypt` command returns
// on success. This function stores it in the PartitionInfoFile yaml file for
// later use.
func (pi PartitionInfo) UpdateMapping(partitionData string) error {
label, uuid := PartitionDataFromString(partitionData)
pi.mapping[label] = uuid
return pi.save()
}
func (pi PartitionInfo) save() error {
data, err := yaml.Marshal(&pi.mapping)
if err != nil {
return errors.Wrap(err, "marshalling the new partition info to yaml")
}
err = ioutil.WriteFile(pi.file, data, 0)
if err != nil {
return errors.Wrap(err, "writing back the partition info file")
}
return nil
}
func PartitionToString(p *block.Partition) string {
return fmt.Sprintf("%s:%s:%s", p.Label, p.Name, p.UUID)
}
// Takes a partition info string (as returned by PartitionToString) and return
// the partition label and the UUID
func PartitionDataFromString(partitionStr string) (string, string) {
parts := strings.Split(partitionStr, ":")
return parts[0], parts[2]
}
func ParsePartitionInfoFile(file string) (map[string]string, error) {
var result map[string]string
yamlFile, err := ioutil.ReadFile(file)
if err != nil {
return result, errors.Wrap(err, "reading the partition info file")
}
err = yaml.Unmarshal(yamlFile, &result)
if err != nil {
return result, errors.Wrap(err, "unmarshalling partition info file")
}
return result, nil
}
// createInfoFileIfNotExists returns true if file already exists or creates the
// the file if it doesn't exist and returns false.
func createInfoFileIfNotExists(fileName string) (bool, error) {
_, err := os.Stat(fileName)
if errors.Is(err, os.ErrNotExist) {
if _, err := os.Create(fileName); err != nil {
return false, err
}
return false, nil
}
return true, nil
}

View File

@@ -0,0 +1,179 @@
package partition_info_test
import (
"fmt"
"io/ioutil"
"os"
"path"
"time"
"github.com/jaypipes/ghw/pkg/block"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
pi "github.com/kairos-io/kcrypt/pkg/partition_info"
)
var _ = Describe("Partition Info file parsing", func() {
Describe("NewPartitionInfoFromFile", func() {
var file string
BeforeEach(func() {
file = "../../tests/assets/partition_info.yaml"
})
When("the files exists already", func() {
It("returns 'true' and a PartitionInfo object", func() {
result, existed, err := pi.NewPartitionInfoFromFile(file)
Expect(err).ToNot(HaveOccurred())
Expect(result).ToNot(BeNil())
Expect(existed).To(BeTrue())
})
})
When("a file doesn't exist", func() {
var fileName string
BeforeEach(func() {
fileName = path.Join(
os.TempDir(),
fmt.Sprintf("partition-info-%d.yaml", time.Now().UnixNano()))
})
It("creates the file and returns 'false' and an (empty) mapping", func() {
result, existed, err := pi.NewPartitionInfoFromFile(fileName)
Expect(err).ToNot(HaveOccurred())
Expect(result).ToNot(BeNil())
Expect(existed).To(BeFalse())
_, err = os.Stat(fileName)
Expect(err).ToNot(HaveOccurred())
})
})
})
Describe("ParsePartitionInfoFile", func() {
var file string
BeforeEach(func() {
file = "../../tests/assets/partition_info.yaml"
})
It("parses the file correctly", func() {
info, err := pi.ParsePartitionInfoFile(file)
Expect(err).ToNot(HaveOccurred())
Expect(len(info)).To(Equal(2))
Expect(info["COS_PERSISTENT"]).To(Equal("some_uuid_1"))
Expect(info["COS_OTHER"]).To(Equal("some_uuid_2"))
})
})
Describe("PartitionToString", func() {
var partition *block.Partition
BeforeEach(func() {
partition = &block.Partition{
Disk: nil,
Name: "sda1",
Label: "COS_PERSISTENT",
MountPoint: "/mnt/sda1",
UUID: "some_uuid_here",
}
})
It("returns a string representation of the partition data", func() {
Expect(pi.PartitionToString(partition)).To(Equal("COS_PERSISTENT:sda1:some_uuid_here"))
})
})
Describe("PartitionDataFromString", func() {
var partitionData string
BeforeEach(func() {
partitionData = "THE_LABEL:the_name:the_uuid"
})
It("returns the label and the uuid", func() {
label, uuid := pi.PartitionDataFromString(partitionData)
Expect(label).To(Equal("THE_LABEL"))
Expect(uuid).To(Equal("the_uuid"))
})
})
Describe("UpdateMapping", func() {
var file *os.File
var err error
var partitionInfo *pi.PartitionInfo
BeforeEach(func() {
file, err = ioutil.TempFile("", "partition-info.*.yaml")
Expect(err).ToNot(HaveOccurred())
_, err = file.Write([]byte("TO_KEEP: old_uuid_1"))
Expect(err).ToNot(HaveOccurred())
partitionInfo, _, err = pi.NewPartitionInfoFromFile(file.Name())
Expect(err).ToNot(HaveOccurred())
})
AfterEach(func() {
os.Remove(file.Name())
})
It("Updates the file correctly from a `kcrypt encrypt` return value", func() {
partitionData := "TO_BE_ADDED:some_name:new_uuid"
err = partitionInfo.UpdateMapping(partitionData)
Expect(err).ToNot(HaveOccurred())
dat, err := os.ReadFile(file.Name())
Expect(err).ToNot(HaveOccurred())
expectedContent := `TO_BE_ADDED: new_uuid
TO_KEEP: old_uuid_1
`
Expect(string(dat)).To(Equal(expectedContent))
})
})
Describe("LookupUUIDForLabel", func() {
var file string
var partitionInfo *pi.PartitionInfo
var err error
BeforeEach(func() {
file = "../../tests/assets/partition_info.yaml"
partitionInfo, _, err = pi.NewPartitionInfoFromFile(file)
Expect(err).ToNot(HaveOccurred())
})
It("returns the correct UUID", func() {
uuid := partitionInfo.LookupUUIDForLabel("COS_PERSISTENT")
Expect(uuid).To(Equal("some_uuid_1"))
})
It("returns an empty UUID when the label is not found", func() {
uuid := partitionInfo.LookupUUIDForLabel("DOESNT_EXIST")
Expect(uuid).To(Equal(""))
})
})
Describe("LookupLabelForUUID", func() {
var file string
var partitionInfo *pi.PartitionInfo
var err error
BeforeEach(func() {
file = "../../tests/assets/partition_info.yaml"
partitionInfo, _, err = pi.NewPartitionInfoFromFile(file)
Expect(err).ToNot(HaveOccurred())
})
It("returns the correct label", func() {
uuid := partitionInfo.LookupLabelForUUID("some_uuid_1")
Expect(uuid).To(Equal("COS_PERSISTENT"))
})
It("returns an empty label when UUID doesn't exist", func() {
uuid := partitionInfo.LookupLabelForUUID("doesnt_exist")
Expect(uuid).To(Equal(""))
})
})
})

View File

@@ -0,0 +1,13 @@
package partition_info
import (
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
func TestPartitionINfo(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "PartitionInfo file parser test suite")
}

View File

@@ -0,0 +1,2 @@
COS_PERSISTENT: some_uuid_1
COS_OTHER: some_uuid_2