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{
|
return &cobra.Command{
|
||||||
Use: "graph",
|
Use: "graph",
|
||||||
Short: "Generates a graph of the Kilo network",
|
Short: "Generates a graph of the Kilo network",
|
||||||
Long: "",
|
|
||||||
RunE: runGraph,
|
RunE: runGraph,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,16 +17,42 @@ package main
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"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/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 {
|
func showConf() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "showconf",
|
Use: "showconf",
|
||||||
Short: "Show the WireGuard configuration for a node or peer in the Kilo network",
|
Short: "Show the WireGuard configuration for a node or peer in the Kilo network",
|
||||||
Long: "",
|
PersistentPreRunE: runShowConf,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, subCmd := range []*cobra.Command{
|
for _, subCmd := range []*cobra.Command{
|
||||||
@ -35,15 +61,29 @@ func showConf() *cobra.Command {
|
|||||||
} {
|
} {
|
||||||
cmd.AddCommand(subCmd)
|
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
|
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 {
|
func showConfNode() *cobra.Command {
|
||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "node",
|
Use: "node [name]",
|
||||||
Short: "Show the WireGuard configuration for a node in the Kilo network",
|
Short: "Show the WireGuard configuration for a node in the Kilo network",
|
||||||
Long: "",
|
|
||||||
RunE: runShowConfNode,
|
RunE: runShowConfNode,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
}
|
}
|
||||||
@ -51,9 +91,8 @@ func showConfNode() *cobra.Command {
|
|||||||
|
|
||||||
func showConfPeer() *cobra.Command {
|
func showConfPeer() *cobra.Command {
|
||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "peer",
|
Use: "peer [name]",
|
||||||
Short: "Show the WireGuard configuration for a peer in the Kilo network",
|
Short: "Show the WireGuard configuration for a peer in the Kilo network",
|
||||||
Long: "",
|
|
||||||
RunE: runShowConfPeer,
|
RunE: runShowConfPeer,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
}
|
}
|
||||||
@ -93,11 +132,35 @@ func runShowConfNode(_ *cobra.Command, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create topology: %v", err)
|
return fmt.Errorf("failed to create topology: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !asPeer {
|
||||||
c, err := t.Conf().Bytes()
|
c, err := t.Conf().Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to generate configuration: %v", err)
|
return fmt.Errorf("failed to generate configuration: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Printf(string(c))
|
_, 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
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,10 +200,89 @@ func runShowConfPeer(_ *cobra.Command, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create topology: %v", err)
|
return fmt.Errorf("failed to create topology: %v", err)
|
||||||
}
|
}
|
||||||
|
if !asPeer {
|
||||||
c, err := t.PeerConf(peer).Bytes()
|
c, err := t.PeerConf(peer).Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to generate configuration: %v", err)
|
return fmt.Errorf("failed to generate configuration: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Printf(string(c))
|
_, 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
|
||||||
|
}
|
||||||
return nil
|
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"
|
const GroupName = "kilo.squat.ai"
|
||||||
|
|
||||||
// SchemeGroupVersion is the group version used to register these objects.
|
// 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.
|
// Resource takes an unqualified resource and returns a Group-qualified GroupResource.
|
||||||
func Resource(resource string) schema.GroupResource {
|
func Resource(resource string) schema.GroupResource {
|
||||||
|
@ -21,15 +21,23 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// Version is the version of this API.
|
||||||
|
Version = "v1alpha1"
|
||||||
// PeerKind is the API kind for the peer resource.
|
// PeerKind is the API kind for the peer resource.
|
||||||
PeerKind = "Peer"
|
PeerKind = "Peer"
|
||||||
// PeerPlural is the plural name for the peer resource.
|
// PeerPlural is the plural name for the peer resource.
|
||||||
PeerPlural = "peers"
|
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.
|
// PeerShortNames are convenient shortnames for the peer resource.
|
||||||
var PeerShortNames = []string{"peer"}
|
var PeerShortNames = []string{"peer"}
|
||||||
|
|
||||||
|
@ -338,6 +338,25 @@ func (t *Topology) Conf() *wireguard.Conf {
|
|||||||
return c
|
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.
|
// PeerConf generates a WireGuard configuration file for a given peer in a Topology.
|
||||||
func (t *Topology) PeerConf(name string) *wireguard.Conf {
|
func (t *Topology) PeerConf(name string) *wireguard.Conf {
|
||||||
c := &wireguard.Conf{}
|
c := &wireguard.Conf{}
|
||||||
|
Loading…
Reference in New Issue
Block a user