...

Source file src/edge-infra.dev/hack/tools/lumberjack/utils/utils.go

Documentation: edge-infra.dev/hack/tools/lumberjack/utils

     1  package utils
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"flag"
     7  	"fmt"
     8  
     9  	containerAPI "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/container/v1beta1"
    10  	"github.com/peterbourgon/ff/v3"
    11  	"github.com/peterbourgon/ff/v3/ffcli"
    12  	"google.golang.org/api/container/v1"
    13  	"k8s.io/apimachinery/pkg/runtime"
    14  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    15  	"k8s.io/client-go/tools/clientcmd"
    16  	"k8s.io/client-go/tools/clientcmd/api"
    17  	"sigs.k8s.io/controller-runtime/pkg/client"
    18  
    19  	"edge-infra.dev/pkg/lib/cli/commands"
    20  )
    21  
    22  const (
    23  	LongHelp = `
    24  	CLI program written to append container cluster resources deployed on a banner infra cluster with a logging config. This config will tell fluentbit-gke to only forward system logs.
    25  	
    26  	The cli program can be run like so:
    27  	
    28  	lumberjack --bannerInfraCluster=someBannerInfraCluster --topLevelProjectID=someForemanProject
    29  	
    30  	The --bannerInfraCluster and --topLevelProjectID flags are required.`
    31  )
    32  
    33  type LumberjackCommand struct {
    34  	Client client.Client
    35  }
    36  
    37  func New() *LumberjackCommand {
    38  	return &LumberjackCommand{}
    39  }
    40  
    41  func (l *LumberjackCommand) SetClusterConnection(client *client.Client) *LumberjackCommand {
    42  	l.Client = *client
    43  	return l
    44  }
    45  
    46  func (l *LumberjackCommand) Exec(name, shortUsage, shortHelp string, fs *flag.FlagSet) *ffcli.Command {
    47  	return &ffcli.Command{
    48  		Name:       name,
    49  		ShortUsage: shortUsage,
    50  		ShortHelp:  shortHelp,
    51  		LongHelp:   LongHelp,
    52  		FlagSet:    fs,
    53  		Options:    []ff.Option{ff.WithEnvVarNoPrefix()},
    54  		Subcommands: []*ffcli.Command{
    55  			commands.Version(),
    56  		},
    57  		Exec: func(ctx context.Context, _ []string) error {
    58  			return l.addLoggingConfig(ctx)
    59  		},
    60  	}
    61  }
    62  
    63  func GetClient(ctx context.Context, projectID, clusterName, zone string) (*client.Client, error) {
    64  	kubeConfig, name, err := getClusterConfig(ctx, projectID, clusterName, zone)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	cfg, err := clientcmd.NewNonInteractiveClientConfig(*kubeConfig, name, &clientcmd.ConfigOverrides{CurrentContext: name}, nil).ClientConfig()
    69  	if err != nil {
    70  		fmt.Println(err)
    71  		return nil, fmt.Errorf("failed to create kube config for cluster=%s: %w", clusterName, err)
    72  	}
    73  	client, err := client.New(cfg, client.Options{Scheme: createScheme()})
    74  	if err != nil {
    75  		return nil, fmt.Errorf("failed to connect to cluster=%s: %w", clusterName, err)
    76  	}
    77  	return &client, nil
    78  }
    79  
    80  func getClusterConfig(ctx context.Context, projectID, clusterName, zone string) (*api.Config, string, error) {
    81  	svc, err := container.NewService(ctx)
    82  	if err != nil {
    83  		return nil, "", fmt.Errorf("container.NewService: %w", err)
    84  	}
    85  
    86  	containerCluster, err := svc.Projects.Zones.Clusters.Get(projectID, zone, clusterName).Context(ctx).Do()
    87  	if err != nil {
    88  		fmt.Println(err)
    89  		return nil, "", fmt.Errorf("failed to get container cluster information: %w", err)
    90  	}
    91  	name := fmt.Sprintf("gke_%s_%s_%s", projectID, containerCluster.Zone, containerCluster.Name)
    92  	cert, err := base64.StdEncoding.DecodeString(containerCluster.MasterAuth.ClusterCaCertificate)
    93  	if err != nil {
    94  		return nil, "", fmt.Errorf("invalid certificate cluster=%s cert=%s: %w", name, containerCluster.MasterAuth.ClusterCaCertificate, err)
    95  	}
    96  
    97  	ret := api.Config{
    98  		Clusters: map[string]*api.Cluster{
    99  			name: {
   100  				CertificateAuthorityData: cert,
   101  				Server:                   "https://" + containerCluster.Endpoint,
   102  			},
   103  		},
   104  		Contexts: map[string]*api.Context{
   105  			name: {
   106  				Cluster:  name,
   107  				AuthInfo: name,
   108  			},
   109  		},
   110  		AuthInfos: map[string]*api.AuthInfo{
   111  			name: {
   112  				AuthProvider: &api.AuthProviderConfig{
   113  					Name: "gcp",
   114  					Config: map[string]string{
   115  						"scopes": "https://www.googleapis.com/auth/cloud-platform",
   116  					},
   117  				},
   118  			},
   119  		},
   120  	}
   121  	return &ret, name, nil
   122  }
   123  
   124  func (l *LumberjackCommand) addLoggingConfig(ctx context.Context) error {
   125  	containerClusterList := &containerAPI.ContainerClusterList{}
   126  
   127  	if err := l.Client.List(ctx, containerClusterList, &client.ListOptions{}); err != nil {
   128  		return fmt.Errorf("failed to list namespaces for cluster, %w", err)
   129  	}
   130  	for _, cc := range containerClusterList.Items {
   131  		if cc.Spec.LoggingConfig != nil && len(cc.Spec.LoggingConfig.EnableComponents) == 1 && cc.Spec.LoggingConfig.EnableComponents[0] == "SYSTEM_COMPONENTS" {
   132  			continue
   133  		}
   134  		fmt.Println("adding logging config to", cc.Name)
   135  		if err := l.patchLoggingConfig(ctx, cc); err != nil {
   136  			return err
   137  		}
   138  	}
   139  	return nil
   140  }
   141  
   142  func (l *LumberjackCommand) patchLoggingConfig(ctx context.Context, cc containerAPI.ContainerCluster) error {
   143  	ccPatch := client.MergeFrom(cc.DeepCopy())
   144  	cc.Spec.LoggingConfig = &containerAPI.ClusterLoggingConfig{
   145  		EnableComponents: []string{"SYSTEM_COMPONENTS"},
   146  	}
   147  	return l.Client.Patch(ctx, &cc, ccPatch)
   148  }
   149  
   150  func createScheme() *runtime.Scheme {
   151  	scheme := runtime.NewScheme()
   152  	utilruntime.Must(containerAPI.AddToScheme(scheme))
   153  	return scheme
   154  }
   155  

View as plain text