-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Alexej Disterhoft <[email protected]>
- Loading branch information
Showing
3 changed files
with
228 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package cli | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/nobbs/kubectl-mapr-ticket/internal/util" | ||
"github.com/nobbs/kubectl-mapr-ticket/internal/volumes" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
type UsedByOptions struct { | ||
*rootCmdOptions | ||
|
||
// Args are the arguments passed to the command | ||
args []string | ||
|
||
// SecretName is the name of the secret to find persistent volumes for | ||
SecretName string | ||
} | ||
|
||
func NewUsedByOptions(rootOpts *rootCmdOptions) *UsedByOptions { | ||
return &UsedByOptions{ | ||
rootCmdOptions: rootOpts, | ||
} | ||
} | ||
|
||
func newUsedByCmd(rootOpts *rootCmdOptions) *cobra.Command { | ||
o := NewUsedByOptions(rootOpts) | ||
|
||
cmd := &cobra.Command{ | ||
Use: "used-by secret", | ||
Short: "List all persistent volumes that use the specified MapR ticket secret", | ||
Long: `List all persistent volumes that use the specified MapR ticket secret and print | ||
some information about them.`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
if err := o.Complete(cmd, args); err != nil { | ||
return err | ||
} | ||
|
||
if err := o.Validate(); err != nil { | ||
return err | ||
} | ||
|
||
if err := o.Run(cmd, args); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
}, | ||
} | ||
|
||
// set IOStreams for the command | ||
cmd.SetIn(o.IOStreams.In) | ||
cmd.SetOut(o.IOStreams.Out) | ||
cmd.SetErr(o.IOStreams.ErrOut) | ||
|
||
return cmd | ||
} | ||
|
||
func (o *UsedByOptions) Complete(cmd *cobra.Command, args []string) error { | ||
o.args = args | ||
|
||
if len(args) > 0 { | ||
o.SecretName = args[0] | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (o *UsedByOptions) Validate() error { | ||
// ensure that the secret name was provided | ||
if o.SecretName == "" { | ||
return fmt.Errorf("secret name must be provided") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (o *UsedByOptions) Run(cmd *cobra.Command, args []string) error { | ||
client, err := util.ClientFromFlags(o.kubernetesConfigFlags) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// create list options | ||
opts := []volumes.ListerOption{} | ||
|
||
// create lister | ||
lister := volumes.NewLister(client, o.SecretName, *o.kubernetesConfigFlags.Namespace, opts...) | ||
|
||
// run the lister | ||
volumes, err := lister.Run() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// print the volumes | ||
// if err := volumes.Print(cmd); err != nil { | ||
// return err | ||
// } | ||
|
||
fmt.Printf("%+v\n", volumes) | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package volumes | ||
|
||
import ( | ||
"context" | ||
|
||
coreV1 "k8s.io/api/core/v1" | ||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/client-go/kubernetes" | ||
typedV1 "k8s.io/client-go/kubernetes/typed/core/v1" | ||
) | ||
|
||
var ( | ||
// maprCSIProvisioners is a list of the default MapR CSI provisioners | ||
// that we support. | ||
maprCSIProvisioners = []string{ | ||
"com.mapr.csi-kdf", | ||
"com.mapr.csi-nfskdf", | ||
} | ||
) | ||
|
||
type Lister struct { | ||
client typedV1.PersistentVolumeInterface | ||
secretName string | ||
namespace string | ||
} | ||
|
||
type ListerOption func(*Lister) | ||
|
||
func NewLister(client kubernetes.Interface, secretName string, namespace string, opts ...ListerOption) *Lister { | ||
l := &Lister{ | ||
client: client.CoreV1().PersistentVolumes(), | ||
secretName: secretName, | ||
namespace: namespace, | ||
} | ||
|
||
for _, opt := range opts { | ||
opt(l) | ||
} | ||
|
||
return l | ||
} | ||
|
||
func (l *Lister) Run() ([]coreV1.PersistentVolume, error) { | ||
// Unfortunately, we have to list all persistent volumes and filter them | ||
// ourselves, because there is no way to filter them by label selector. | ||
volumes, err := l.client.List(context.TODO(), metaV1.ListOptions{}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Filter the volumes to only MapR CSI-based ones | ||
filtered := l.filterVolumesToMaprCSI(volumes.Items) | ||
|
||
// Filter the volumes to only ones that use the specified secret | ||
filtered = l.filterVolumeUsesTicket(filtered) | ||
|
||
return filtered, nil | ||
} | ||
|
||
func (l *Lister) filterVolumesToMaprCSI(volumes []coreV1.PersistentVolume) []coreV1.PersistentVolume { | ||
var filtered []coreV1.PersistentVolume | ||
|
||
for _, volume := range volumes { | ||
if l.volumeIsMaprCSIBased(&volume) { | ||
filtered = append(filtered, volume) | ||
} | ||
} | ||
|
||
return filtered | ||
} | ||
|
||
func (l *Lister) filterVolumeUsesTicket(volumes []coreV1.PersistentVolume) []coreV1.PersistentVolume { | ||
var filtered []coreV1.PersistentVolume | ||
|
||
for _, volume := range volumes { | ||
if l.volumeUsesTicket(&volume) { | ||
filtered = append(filtered, volume) | ||
} | ||
} | ||
|
||
return filtered | ||
} | ||
|
||
func (l *Lister) volumeUsesTicket(volume *coreV1.PersistentVolume) bool { | ||
// Check if the volume uses a CSI driver | ||
if volume.Spec.CSI == nil { | ||
return false | ||
} | ||
|
||
// Check if the volume uses a NodePublishSecretRef | ||
if volume.Spec.CSI.NodePublishSecretRef == nil { | ||
return false | ||
} | ||
|
||
// Check if the volume uses the specified secret | ||
if volume.Spec.CSI.NodePublishSecretRef.Name != l.secretName { | ||
return false | ||
} | ||
|
||
// Check if the volume uses the specified namespace | ||
if volume.Spec.CSI.NodePublishSecretRef.Namespace != l.namespace { | ||
return false | ||
} | ||
|
||
return true | ||
} | ||
|
||
func (l *Lister) volumeIsMaprCSIBased(volume *coreV1.PersistentVolume) bool { | ||
// Check if the volume is MapR CSI-based | ||
if volume.Spec.CSI == nil { | ||
return false | ||
} | ||
|
||
// Check if the volume is provisioned by one of the MapR CSI provisioners | ||
for _, provisioner := range maprCSIProvisioners { | ||
if volume.Spec.CSI.Driver == provisioner { | ||
return true | ||
} | ||
} | ||
|
||
return false | ||
} |