cmd/kgctl: add output options for showconf
This commit adds several output options to the `showconf` command of the `kgctl` binary: * `--as-peer`: this can be used to generate a peer configuration, which can be used to configure the selected resource as a peer of another WireGuard interface * `--output`: this can be used to select the desired output format of the peer resource, available options are: WireGuard, YAML, and JSON.
This commit is contained in:
parent
5914a9468f
commit
90e68c7735
@ -25,7 +25,6 @@ func graph() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "graph",
|
||||
Short: "Generates a graph of the Kilo network",
|
||||
Long: "",
|
||||
RunE: runGraph,
|
||||
}
|
||||
}
|
||||
|
@ -17,16 +17,42 @@ package main
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
|
||||
"github.com/squat/kilo/pkg/k8s/apis/kilo/v1alpha1"
|
||||
"github.com/squat/kilo/pkg/mesh"
|
||||
"github.com/squat/kilo/pkg/wireguard"
|
||||
)
|
||||
|
||||
const (
|
||||
outputFormatJSON = "json"
|
||||
outputFormatWireGuard = "wireguard"
|
||||
outputFormatYAML = "yaml"
|
||||
)
|
||||
|
||||
var (
|
||||
availableOutputFormats = strings.Join([]string{
|
||||
outputFormatJSON,
|
||||
outputFormatWireGuard,
|
||||
outputFormatYAML,
|
||||
}, ", ")
|
||||
asPeer bool
|
||||
output string
|
||||
serializer *json.Serializer
|
||||
)
|
||||
|
||||
func showConf() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "showconf",
|
||||
Short: "Show the WireGuard configuration for a node or peer in the Kilo network",
|
||||
Long: "",
|
||||
Use: "showconf",
|
||||
Short: "Show the WireGuard configuration for a node or peer in the Kilo network",
|
||||
PersistentPreRunE: runShowConf,
|
||||
}
|
||||
|
||||
for _, subCmd := range []*cobra.Command{
|
||||
@ -35,15 +61,29 @@ func showConf() *cobra.Command {
|
||||
} {
|
||||
cmd.AddCommand(subCmd)
|
||||
}
|
||||
cmd.PersistentFlags().BoolVar(&asPeer, "as-peer", false, "Should the resource be shown as a peer? Useful to configure this resource as a peer of another WireGuard interface.")
|
||||
cmd.PersistentFlags().StringVarP(&output, "output", "o", "wireguard", fmt.Sprintf("The output format of the resource. Only valid when combined with 'as-peer'. Possible values: %s", availableOutputFormats))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runShowConf(c *cobra.Command, args []string) error {
|
||||
switch output {
|
||||
case outputFormatJSON:
|
||||
serializer = json.NewSerializer(json.DefaultMetaFactory, peerCreatorTyper{}, peerCreatorTyper{}, true)
|
||||
case outputFormatWireGuard:
|
||||
case outputFormatYAML:
|
||||
serializer = json.NewYAMLSerializer(json.DefaultMetaFactory, peerCreatorTyper{}, peerCreatorTyper{})
|
||||
default:
|
||||
return fmt.Errorf("output format %v unknown; posible values are: %s", output, availableOutputFormats)
|
||||
}
|
||||
return runRoot(c, args)
|
||||
}
|
||||
|
||||
func showConfNode() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "node",
|
||||
Use: "node [name]",
|
||||
Short: "Show the WireGuard configuration for a node in the Kilo network",
|
||||
Long: "",
|
||||
RunE: runShowConfNode,
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
@ -51,9 +91,8 @@ func showConfNode() *cobra.Command {
|
||||
|
||||
func showConfPeer() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "peer",
|
||||
Use: "peer [name]",
|
||||
Short: "Show the WireGuard configuration for a peer in the Kilo network",
|
||||
Long: "",
|
||||
RunE: runShowConfPeer,
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
@ -93,11 +132,35 @@ func runShowConfNode(_ *cobra.Command, args []string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create topology: %v", err)
|
||||
}
|
||||
c, err := t.Conf().Bytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate configuration: %v", err)
|
||||
|
||||
if !asPeer {
|
||||
c, err := t.Conf().Bytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate configuration: %v", err)
|
||||
}
|
||||
_, err = os.Stdout.Write(c)
|
||||
return err
|
||||
}
|
||||
|
||||
switch output {
|
||||
case outputFormatJSON:
|
||||
fallthrough
|
||||
case outputFormatYAML:
|
||||
p := translatePeer(t.AsPeer())
|
||||
p.Name = hostname
|
||||
return serializer.Encode(p, os.Stdout)
|
||||
case outputFormatWireGuard:
|
||||
c, err := (&wireguard.Conf{
|
||||
Peers: []*wireguard.Peer{
|
||||
t.AsPeer(),
|
||||
},
|
||||
}).Bytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate configuration: %v", err)
|
||||
}
|
||||
_, err = os.Stdout.Write(c)
|
||||
return err
|
||||
}
|
||||
fmt.Printf(string(c))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -137,10 +200,89 @@ func runShowConfPeer(_ *cobra.Command, args []string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create topology: %v", err)
|
||||
}
|
||||
c, err := t.PeerConf(peer).Bytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate configuration: %v", err)
|
||||
if !asPeer {
|
||||
c, err := t.PeerConf(peer).Bytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate configuration: %v", err)
|
||||
}
|
||||
_, err = os.Stdout.Write(c)
|
||||
return err
|
||||
}
|
||||
|
||||
switch output {
|
||||
case outputFormatJSON:
|
||||
fallthrough
|
||||
case outputFormatYAML:
|
||||
p := translatePeer(t.AsPeer())
|
||||
p.Name = peer
|
||||
return serializer.Encode(p, os.Stdout)
|
||||
case outputFormatWireGuard:
|
||||
c, err := (&wireguard.Conf{
|
||||
Peers: []*wireguard.Peer{
|
||||
&peers[peer].Peer,
|
||||
},
|
||||
}).Bytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate configuration: %v", err)
|
||||
}
|
||||
_, err = os.Stdout.Write(c)
|
||||
return err
|
||||
}
|
||||
fmt.Printf(string(c))
|
||||
return nil
|
||||
}
|
||||
|
||||
// translatePeer translates a wireguard.Peer to a Peer CRD.
|
||||
func translatePeer(peer *wireguard.Peer) *v1alpha1.Peer {
|
||||
if peer == nil {
|
||||
return &v1alpha1.Peer{}
|
||||
}
|
||||
var aips []string
|
||||
for _, aip := range peer.AllowedIPs {
|
||||
// Skip any invalid IPs.
|
||||
if aip == nil {
|
||||
continue
|
||||
}
|
||||
aips = append(aips, aip.String())
|
||||
}
|
||||
var endpoint *v1alpha1.PeerEndpoint
|
||||
if peer.Endpoint != nil && peer.Endpoint.Port > 0 && peer.Endpoint.IP != nil {
|
||||
endpoint = &v1alpha1.PeerEndpoint{
|
||||
IP: peer.Endpoint.IP.String(),
|
||||
Port: peer.Endpoint.Port,
|
||||
}
|
||||
}
|
||||
var key string
|
||||
if len(peer.PublicKey) > 0 {
|
||||
key = string(peer.PublicKey)
|
||||
}
|
||||
var pka int
|
||||
if peer.PersistentKeepalive > 0 {
|
||||
pka = peer.PersistentKeepalive
|
||||
}
|
||||
return &v1alpha1.Peer{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: v1alpha1.PeerKind,
|
||||
APIVersion: v1alpha1.SchemeGroupVersion.String(),
|
||||
},
|
||||
Spec: v1alpha1.PeerSpec{
|
||||
AllowedIPs: aips,
|
||||
Endpoint: endpoint,
|
||||
PublicKey: key,
|
||||
PersistentKeepalive: pka,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type peerCreatorTyper struct{}
|
||||
|
||||
func (p peerCreatorTyper) New(_ schema.GroupVersionKind) (runtime.Object, error) {
|
||||
return &v1alpha1.Peer{}, nil
|
||||
}
|
||||
|
||||
func (p peerCreatorTyper) ObjectKinds(_ runtime.Object) ([]schema.GroupVersionKind, bool, error) {
|
||||
return []schema.GroupVersionKind{v1alpha1.PeerGVK}, false, nil
|
||||
}
|
||||
|
||||
func (p peerCreatorTyper) Recognizes(_ schema.GroupVersionKind) bool {
|
||||
return true
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ var (
|
||||
const GroupName = "kilo.squat.ai"
|
||||
|
||||
// SchemeGroupVersion is the group version used to register these objects.
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: Version}
|
||||
|
||||
// Resource takes an unqualified resource and returns a Group-qualified GroupResource.
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
|
@ -21,15 +21,23 @@ import (
|
||||
"net"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
// Version is the version of this API.
|
||||
Version = "v1alpha1"
|
||||
// PeerKind is the API kind for the peer resource.
|
||||
PeerKind = "Peer"
|
||||
// PeerPlural is the plural name for the peer resource.
|
||||
PeerPlural = "peers"
|
||||
)
|
||||
|
||||
var (
|
||||
// PeerGVK is the GroupVersionKind for Peers.
|
||||
PeerGVK = schema.GroupVersionKind{Group: GroupName, Version: Version, Kind: PeerKind}
|
||||
)
|
||||
|
||||
// PeerShortNames are convenient shortnames for the peer resource.
|
||||
var PeerShortNames = []string{"peer"}
|
||||
|
||||
|
@ -338,6 +338,25 @@ func (t *Topology) Conf() *wireguard.Conf {
|
||||
return c
|
||||
}
|
||||
|
||||
// AsPeer generates the WireGuard peer configuration for the local location of the given Topology.
|
||||
// This configuration can be used to configure this location as a peer of another WireGuard interface.
|
||||
func (t *Topology) AsPeer() *wireguard.Peer {
|
||||
for _, s := range t.segments {
|
||||
if s.location != t.location {
|
||||
continue
|
||||
}
|
||||
return &wireguard.Peer{
|
||||
AllowedIPs: s.allowedIPs,
|
||||
Endpoint: &wireguard.Endpoint{
|
||||
IP: s.endpoint,
|
||||
Port: uint32(t.port),
|
||||
},
|
||||
PublicKey: s.key,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PeerConf generates a WireGuard configuration file for a given peer in a Topology.
|
||||
func (t *Topology) PeerConf(name string) *wireguard.Conf {
|
||||
c := &wireguard.Conf{}
|
||||
|
Loading…
Reference in New Issue
Block a user