Skip to content

Commit

Permalink
Merge pull request #38 from calvinrzachman/store-configmap
Browse files Browse the repository at this point in the history
lndinit: add ability to write to k8s configmap
  • Loading branch information
guggero authored Jan 19, 2024
2 parents 97404fa + 0238e58 commit b8348e3
Show file tree
Hide file tree
Showing 9 changed files with 367 additions and 50 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ initialization, including seed and password generation.
- [`gen-seed`](#gen-seed)
- [`load-secret`](#load-secret)
- [`store-secret`](#store-secret)
- [`store-configmap`](#store-configmap)
- [`init-wallet`](#init-wallet)
- [`wait-ready`](#wait-ready)
- [Example usage](#example-usage)
Expand Down Expand Up @@ -48,6 +49,9 @@ No `lnd` needed, but seed will be in `lnd`-specific [`aezeed` format](https://gi
### store-secret
`store-secret` interacts with kubernetes to write to secrets (no `lnd` needed)

### store-configmap
`store-configmap` interacts with kubernetes to write to configmaps (no `lnd` needed)

### init-wallet
`init-wallet` has two modes:
- `--init-type=file` creates an `lnd` specific `wallet.db` file
Expand Down
10 changes: 9 additions & 1 deletion cmd_gen_seed.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,15 @@ func (x *genSeedCommand) Execute(_ []string) error {

// Read passphrase from Kubernetes secret.
case x.PassphraseK8s.AnySet():
passPhrase, _, err = readK8s(x.PassphraseK8s)
k8sSecret := &k8sObjectOptions{
Namespace: x.PassphraseK8s.Namespace,
Name: x.PassphraseK8s.SecretName,
KeyName: x.PassphraseK8s.SecretKeyName,
Base64: x.PassphraseK8s.Base64,
ObjectType: ObjectTypeSecret,
}

passPhrase, _, err = readK8s(k8sSecret)

}
if err != nil {
Expand Down
11 changes: 6 additions & 5 deletions cmd_init_wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,12 +239,13 @@ func (x *initWalletCommand) readInput(requireSeed bool) (string, string, string,

// Read passphrase from Kubernetes secret.
case storageK8s:
k8sSecret := &k8sSecretOptions{
k8sSecret := &k8sObjectOptions{
Namespace: x.K8s.Namespace,
SecretName: x.K8s.SecretName,
Name: x.K8s.SecretName,
KeyName: x.K8s.SeedKeyName,
Base64: x.K8s.Base64,
ObjectType: ObjectTypeSecret,
}
k8sSecret.SecretKeyName = x.K8s.SeedKeyName

if requireSeed {
log("Reading seed from k8s secret %s (namespace %s)",
Expand All @@ -260,7 +261,7 @@ func (x *initWalletCommand) readInput(requireSeed bool) (string, string, string,
log("Reading seed passphrase from k8s secret %s "+
"(namespace %s)", x.K8s.SecretName,
x.K8s.Namespace)
k8sSecret.SecretKeyName = x.K8s.SeedPassphraseKeyName
k8sSecret.KeyName = x.K8s.SeedPassphraseKeyName
seedPassPhrase, _, err = readK8s(k8sSecret)
if err != nil {
return "", "", "", err
Expand All @@ -269,7 +270,7 @@ func (x *initWalletCommand) readInput(requireSeed bool) (string, string, string,

log("Reading wallet password from k8s secret %s (namespace %s)",
x.K8s.SecretName, x.K8s.Namespace)
k8sSecret.SecretKeyName = x.K8s.WalletPasswordKeyName
k8sSecret.KeyName = x.K8s.WalletPasswordKeyName
walletPassword, _, err = readK8s(k8sSecret)
if err != nil {
return "", "", "", err
Expand Down
10 changes: 9 additions & 1 deletion cmd_load_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,15 @@ func (x *loadSecretCommand) Register(parser *flags.Parser) error {
func (x *loadSecretCommand) Execute(_ []string) error {
switch x.Source {
case storageK8s:
content, secret, err := readK8s(x.K8s)
objectOpts := &k8sObjectOptions{
Namespace: x.K8s.Namespace,
Name: x.K8s.SecretName,
KeyName: x.K8s.SecretKeyName,
Base64: x.K8s.Base64,
ObjectType: ObjectTypeSecret,
}

content, secret, err := readK8s(objectOpts)
if err != nil {
return fmt.Errorf("error reading secret %s in "+
"namespace %s: %v", x.K8s.SecretName,
Expand Down
130 changes: 130 additions & 0 deletions cmd_store_configmap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package main

import (
"fmt"
"io"
"os"
"path/filepath"

"github.com/jessevdk/go-flags"
)

type targetK8sConfigmap struct {
k8sConfigmapOptions

Helm *helmOptions `group:"Flags for configuring the Helm annotations (use when --target=k8s)" namespace:"helm"`
}

type storeConfigmapCommand struct {
Batch bool `long:"batch" description:"Instead of reading one configmap from stdin, read all files of the argument list and store them as entries in the configmap"`
Overwrite bool `long:"overwrite" description:"Overwrite existing configmap entries instead of aborting"`
Target string `long:"target" short:"t" description:"Configmap storage target" choice:"k8s"`
K8s *targetK8sConfigmap `group:"Flags for storing the key/value pair inside a Kubernetes Configmap (use when --target=k8s)" namespace:"k8s"`
}

func newStoreConfigmapCommand() *storeConfigmapCommand {
return &storeConfigmapCommand{
Target: storageK8s,
K8s: &targetK8sConfigmap{
k8sConfigmapOptions: k8sConfigmapOptions{
Namespace: defaultK8sNamespace,
},
},
}
}

func (x *storeConfigmapCommand) Register(parser *flags.Parser) error {
_, err := parser.AddCommand(
"store-configmap",
"Write key/value pairs to a Kubernetes configmap",
"Read a configmap from stdin and store it to the "+
"external configmaps storage indicated by the --target "+
"flag; if the --batch flag is used, instead of "+
"reading a single configmap entry from stdin, each command "+
"line argument is treated as a file and each file's "+
"content is added to the configmap with the file's name "+
"as the key name for the configmap entry",
x,
)
return err
}

func (x *storeConfigmapCommand) Execute(args []string) error {
var entries []*entry

switch {
case x.Batch && len(args) == 0:
return fmt.Errorf("at least one command line argument is " +
"required when using --batch flag")

case x.Batch:
for _, file := range args {
log("Reading value/entry from file %s", file)
content, err := readFile(file)
if err != nil {
return fmt.Errorf("cannot read file %s: %v",
file, err)
}

entries = append(entries, &entry{
key: filepath.Base(file),
value: content,
})
}

default:
log("Reading value/entry from stdin")
value, err := io.ReadAll(os.Stdin)
if err != nil {
return fmt.Errorf("error reading entry from stdin: %v", err)
}
entries = append(entries, &entry{value: string(value)})
}

switch x.Target {
case storageK8s:
// Take the actual entry key from the options if we aren't in
// batch mode.
if len(entries) == 1 && entries[0].key == "" {
entries[0].key = x.K8s.KeyName
}

return storeConfigmapsK8s(entries, x.K8s, x.Overwrite)

default:
return fmt.Errorf("invalid configmap storage target %s", x.Target)
}
}

func storeConfigmapsK8s(entries []*entry, opts *targetK8sConfigmap,
overwrite bool) error {

if opts.Name == "" {
return fmt.Errorf("configmap name is required")
}

for _, entry := range entries {
if entry.key == "" {
return fmt.Errorf("configmap entry key name is required")
}

entryOpts := &k8sObjectOptions{
Namespace: opts.Namespace,
Name: opts.Name,
KeyName: entry.key,
ObjectType: ObjectTypeConfigMap,
}

log("Storing key with name %s to configmap %s in namespace %s",
entryOpts.KeyName, entryOpts.Name,
entryOpts.Namespace)

err := saveK8s(entry.value, entryOpts, overwrite, opts.Helm)
if err != nil {
return fmt.Errorf("error storing key %s in configmap %s: "+
"%v", entry.key, opts.Name, err)
}
}

return nil
}
35 changes: 18 additions & 17 deletions cmd_store_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,28 @@ import (
"github.com/jessevdk/go-flags"
)

type targetK8s struct {
type targetK8sSecret struct {
k8sSecretOptions

Helm *helmOptions `group:"Flags for configuring the Helm annotations (use when --target=k8s)" namespace:"helm"`
}

type secretEntry struct {
type entry struct {
key string
value string
}

type storeSecretCommand struct {
Batch bool `long:"batch" description:"Instead of reading one secret from stdin, read all files of the argument list and store them as entries in the secret"`
Overwrite bool `long:"overwrite" description:"Overwrite existing secret entries instead of aborting"`
Target string `long:"target" short:"t" description:"Secret storage target" choice:"k8s"`
K8s *targetK8s `group:"Flags for storing the secret as a value inside a Kubernetes Secret (use when --target=k8s)" namespace:"k8s"`
Batch bool `long:"batch" description:"Instead of reading one secret from stdin, read all files of the argument list and store them as entries in the secret"`
Overwrite bool `long:"overwrite" description:"Overwrite existing secret entries instead of aborting"`
Target string `long:"target" short:"t" description:"Secret storage target" choice:"k8s"`
K8s *targetK8sSecret `group:"Flags for storing the secret as a value inside a Kubernetes Secret (use when --target=k8s)" namespace:"k8s"`
}

func newStoreSecretCommand() *storeSecretCommand {
return &storeSecretCommand{
Target: storageK8s,
K8s: &targetK8s{
K8s: &targetK8sSecret{
k8sSecretOptions: k8sSecretOptions{
Namespace: defaultK8sNamespace,
},
Expand Down Expand Up @@ -59,7 +59,7 @@ func (x *storeSecretCommand) Register(parser *flags.Parser) error {
}

func (x *storeSecretCommand) Execute(args []string) error {
var entries []*secretEntry
var entries []*entry

switch {
case x.Batch && len(args) == 0:
Expand All @@ -75,7 +75,7 @@ func (x *storeSecretCommand) Execute(args []string) error {
file, err)
}

entries = append(entries, &secretEntry{
entries = append(entries, &entry{
key: filepath.Base(file),
value: content,
})
Expand All @@ -88,7 +88,7 @@ func (x *storeSecretCommand) Execute(args []string) error {
return fmt.Errorf("error reading secret from stdin: %v",
err)
}
entries = append(entries, &secretEntry{value: secret})
entries = append(entries, &entry{value: secret})
}

switch x.Target {
Expand All @@ -106,7 +106,7 @@ func (x *storeSecretCommand) Execute(args []string) error {
}
}

func storeSecretsK8s(entries []*secretEntry, opts *targetK8s,
func storeSecretsK8s(entries []*entry, opts *targetK8sSecret,
overwrite bool) error {

if opts.SecretName == "" {
Expand All @@ -118,15 +118,16 @@ func storeSecretsK8s(entries []*secretEntry, opts *targetK8s,
return fmt.Errorf("secret key name is required")
}

entryOpts := &k8sSecretOptions{
Namespace: opts.Namespace,
SecretName: opts.SecretName,
SecretKeyName: entry.key,
Base64: opts.Base64,
entryOpts := &k8sObjectOptions{
Namespace: opts.Namespace,
Name: opts.SecretName,
KeyName: entry.key,
Base64: opts.Base64,
ObjectType: ObjectTypeSecret,
}

log("Storing key with name %s to secret %s in namespace %s",
entryOpts.SecretKeyName, entryOpts.SecretName,
entryOpts.KeyName, entryOpts.Name,
entryOpts.Namespace)
err := saveK8s(entry.value, entryOpts, overwrite, opts.Helm)
if err != nil {
Expand Down
Loading

0 comments on commit b8348e3

Please sign in to comment.