...

Source file src/edge-infra.dev/pkg/edge/edgecli/commands/clusterconfig/modifyclusterconfig/modify_clusterconfig.go

Documentation: edge-infra.dev/pkg/edge/edgecli/commands/clusterconfig/modifyclusterconfig

     1  package modifyclusterconfig
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"regexp"
     7  	"strings"
     8  	"time"
     9  
    10  	"edge-infra.dev/pkg/edge/api/graph/model"
    11  	"edge-infra.dev/pkg/edge/api/utils"
    12  	"edge-infra.dev/pkg/edge/edgeadmin/edgecliutils"
    13  	"edge-infra.dev/pkg/edge/edgecli"
    14  	"edge-infra.dev/pkg/edge/edgecli/constructors"
    15  	"edge-infra.dev/pkg/edge/edgecli/flagutil"
    16  	"edge-infra.dev/pkg/lib/cli/command"
    17  	"edge-infra.dev/pkg/lib/cli/rags"
    18  )
    19  
    20  func NewCmd(cfg *edgecli.Config) *command.Command {
    21  	var cmd *command.Command
    22  	flagsets := flagutil.GetConnectionFlags(cfg)
    23  	var storeName, bannerName string
    24  	config := model.UpdateClusterConfig{}
    25  
    26  	cmd = &command.Command{
    27  		ShortUsage: "edge clusterconfig modify",
    28  		ShortHelp:  "Update cluster config",
    29  		Flags: append(
    30  			flagsets,
    31  			&rags.Rag{
    32  				Name:     flagutil.StoreFlag,
    33  				Usage:    "Name of the Store",
    34  				Value:    &rags.String{Var: &storeName},
    35  				Required: true,
    36  			},
    37  			&rags.Rag{
    38  				Name:     flagutil.BannerFlag,
    39  				Usage:    "Banner name",
    40  				Value:    &rags.String{Var: &bannerName},
    41  				Required: true,
    42  			},
    43  			&rags.Rag{
    44  				Name:     flagutil.PxeEnabledFlag,
    45  				Value:    &rags.Bool{Var: config.PxeEnabled},
    46  				Usage:    "Enable pxe booting",
    47  				Required: false,
    48  			},
    49  			&rags.Rag{
    50  				Name:  flagutil.AcRelayFlag,
    51  				Value: &rags.Bool{Var: config.AcRelay},
    52  
    53  				Usage:    "Enable activation code relaying for pxe-boot",
    54  				Required: false,
    55  			},
    56  			&rags.Rag{
    57  				Name:     edgecliutils.BootstrapAckFlag,
    58  				Value:    &rags.Bool{Var: config.BootstrapAck},
    59  				Usage:    "Bootstrap acknowledgement - require user confirmation for terminal bootstrap",
    60  				Required: false,
    61  			},
    62  			&rags.Rag{
    63  				Name:     flagutil.VpnEnabledmentFlag,
    64  				Value:    &rags.Bool{Var: config.VpnEnabled},
    65  				Usage:    "Enable vpn access on the cluster",
    66  				Required: false,
    67  			},
    68  			&rags.Rag{
    69  				Name:     flagutil.ThickPosFlag,
    70  				Value:    &rags.Bool{Var: config.ThickPos, Default: true},
    71  				Usage:    "Enable thick pos mode",
    72  				Required: false,
    73  			},
    74  			&rags.Rag{
    75  				Name:     flagutil.EgressGatewayFlag,
    76  				Value:    &rags.Bool{Var: config.EgressGatewayEnabled},
    77  				Usage:    "Enable egress gateway",
    78  				Required: false,
    79  			},
    80  			&rags.Rag{
    81  				Name:     flagutil.GatewayRateLimitingFlag,
    82  				Value:    &rags.Bool{Var: config.GatewayRateLimitingEnabled},
    83  				Usage:    "Enable gateway rate limiting",
    84  				Required: false,
    85  			},
    86  			&rags.Rag{
    87  				Name:     flagutil.UplinkRateLimitFlag,
    88  				Value:    &rags.String{Var: config.UplinkRateLimit},
    89  				Usage:    "A limit on the rate data can be uploaded",
    90  				Required: false,
    91  			},
    92  			&rags.Rag{
    93  				Name:     flagutil.DownlinkRateLimitFlag,
    94  				Value:    &rags.String{Var: config.DownlinkRateLimit},
    95  				Usage:    "A limit on the rate date can be downloaded",
    96  				Required: false,
    97  			},
    98  			&rags.Rag{
    99  				Name:     flagutil.ClusterLogLevel,
   100  				Value:    &rags.String{Var: config.ClusterLogLevel},
   101  				Usage:    "Cluster Level Log level for severity filtering",
   102  				Required: false,
   103  			},
   104  			&rags.Rag{
   105  				Name:     flagutil.MaximumLanOutageHours,
   106  				Value:    &rags.Int{Var: config.MaximumLanOutageHours, Default: 96},
   107  				Usage:    "Maximum LAN outage duration in hours",
   108  				Required: false,
   109  			},
   110  		),
   111  		Exec: func(_ context.Context, _ []string) error {
   112  			//validates required field value, value cannot be empty or space
   113  			if err := flagutil.ValidateRequiredFlags(cmd.Rags); err != nil {
   114  				return err
   115  			}
   116  
   117  			registrar, err := constructors.BuildRegistrar(cmd.Rags)
   118  			if err != nil {
   119  				return err
   120  			}
   121  
   122  			reqCtx, cancelReq := context.WithTimeout(context.Background(), time.Duration(30)*time.Second)
   123  			defer cancelReq()
   124  
   125  			cluster, err := registrar.GetCluster(reqCtx, storeName, bannerName)
   126  			if err != nil {
   127  				return err
   128  			}
   129  
   130  			if flagutil.GetBoolFlag(cmd.Rags, flagutil.AcRelayFlag) {
   131  				acRelay := flagutil.GetBoolFlag(cmd.Rags, flagutil.AcRelayFlag)
   132  				config.AcRelay = &acRelay
   133  			}
   134  
   135  			if flagutil.GetBoolFlag(cmd.Rags, flagutil.PxeEnabledFlag) {
   136  				pxeEnabled := flagutil.GetBoolFlag(cmd.Rags, flagutil.PxeEnabledFlag)
   137  				config.PxeEnabled = &pxeEnabled
   138  			}
   139  
   140  			if flagutil.GetBoolFlag(cmd.Rags, flagutil.BootstrapAckFlag) {
   141  				bootstrapAck := flagutil.GetBoolFlag(cmd.Rags, flagutil.BootstrapAckFlag)
   142  				config.BootstrapAck = &bootstrapAck
   143  			}
   144  
   145  			if flagutil.GetBoolFlag(cmd.Rags, flagutil.VpnEnabledmentFlag) {
   146  				vpnEnabled := flagutil.GetBoolFlag(cmd.Rags, flagutil.VpnEnabledmentFlag)
   147  				config.VpnEnabled = &vpnEnabled
   148  			}
   149  
   150  			if flagutil.GetBoolFlag(cmd.Rags, flagutil.ThickPosFlag) {
   151  				thickPos := flagutil.GetBoolFlag(cmd.Rags, flagutil.ThickPosFlag)
   152  				config.ThickPos = &thickPos
   153  			}
   154  
   155  			if flagutil.GetBoolFlag(cmd.Rags, flagutil.EgressGatewayFlag) {
   156  				egressGatewayEnabled := flagutil.GetBoolFlag(cmd.Rags, flagutil.EgressGatewayFlag)
   157  				config.EgressGatewayEnabled = &egressGatewayEnabled
   158  			}
   159  
   160  			if flagutil.GetBoolFlag(cmd.Rags, flagutil.GatewayRateLimitingFlag) {
   161  				gatewayRateLimitingEnabled := flagutil.GetBoolFlag(cmd.Rags, flagutil.GatewayRateLimitingFlag)
   162  				config.GatewayRateLimitingEnabled = &gatewayRateLimitingEnabled
   163  			}
   164  
   165  			if flagutil.GetStringFlag(cmd.Rags, flagutil.UplinkRateLimitFlag) != "" {
   166  				uplinkRateLimit := flagutil.GetStringFlag(cmd.Rags, flagutil.UplinkRateLimitFlag)
   167  				config.UplinkRateLimit = &uplinkRateLimit
   168  				if err := validateRateLimit(config.UplinkRateLimit); err != nil && config.UplinkRateLimit != nil {
   169  					return fmt.Errorf("uplink validation failed: %w", err)
   170  				}
   171  			}
   172  
   173  			if flagutil.GetStringFlag(cmd.Rags, flagutil.DownlinkRateLimitFlag) != "" {
   174  				downlinkRateLimit := flagutil.GetStringFlag(cmd.Rags, flagutil.DownlinkRateLimitFlag)
   175  				config.DownlinkRateLimit = &downlinkRateLimit
   176  				if err := validateRateLimit(config.DownlinkRateLimit); err != nil && config.DownlinkRateLimit != nil {
   177  					return fmt.Errorf("downlink validation failed: %w", err)
   178  				}
   179  			}
   180  
   181  			if flagutil.GetStringFlag(cmd.Rags, flagutil.ClusterLogLevel) != "" {
   182  				clusterLogLevel := flagutil.GetStringFlag(cmd.Rags, flagutil.ClusterLogLevel)
   183  				config.ClusterLogLevel = &clusterLogLevel
   184  				if err := validateLogLevel(config.ClusterLogLevel); err != nil {
   185  					return fmt.Errorf("cluster Log Level Validation failed: %w", err)
   186  				}
   187  			}
   188  
   189  			if flagutil.GetIntFlag(cmd.Rags, flagutil.MaximumLanOutageHours) >= 0 {
   190  				maximumLanOutageHours := flagutil.GetIntFlag(cmd.Rags, flagutil.MaximumLanOutageHours)
   191  				config.MaximumLanOutageHours = &maximumLanOutageHours
   192  				if *config.MaximumLanOutageHours < 24 {
   193  					return fmt.Errorf("maximum LAN outage duration must be at least 24 hours")
   194  				}
   195  			}
   196  
   197  			reqCtx, cancelReq = context.WithTimeout(context.Background(), time.Duration(30)*time.Second)
   198  			defer cancelReq()
   199  
   200  			return registrar.UpdateClusterConfig(reqCtx, cluster.ClusterEdgeID, config)
   201  		},
   202  	}
   203  	return cmd
   204  }
   205  
   206  // Adding these validate function here, so if it fails, it doesn't have to wait til the end
   207  // and make another API call to validate
   208  func validateLogLevel(level *string) error {
   209  	if utils.IsNullOrEmpty(level) {
   210  		return nil
   211  	}
   212  	validLogLevels := map[string]bool{
   213  		"DEBUG":     true,
   214  		"INFO":      true,
   215  		"NOTICE":    true,
   216  		"WARNING":   true,
   217  		"ERROR":     true,
   218  		"CRITICAL":  true,
   219  		"ALERT":     true,
   220  		"EMERGENCY": true,
   221  	}
   222  	_, levelExists := validLogLevels[strings.ToUpper(*level)]
   223  
   224  	var keys string
   225  	for i := range validLogLevels {
   226  		keys = keys + " " + i
   227  	}
   228  
   229  	if !levelExists {
   230  		return fmt.Errorf("%s is not a valid log level. Please make sure it is one of the following levels: %s", *level, keys)
   231  	}
   232  
   233  	return nil
   234  }
   235  
   236  func validateRateLimit(rateLimit *string) error {
   237  	if rateLimit == nil {
   238  		return nil
   239  	}
   240  
   241  	rateLimitRegExp, err := regexp.Compile("^[1-9][0-9]*([kK]bit$|[mM]bit$)")
   242  	if err != nil {
   243  		return err
   244  	}
   245  	if !rateLimitRegExp.MatchString(*rateLimit) {
   246  		return fmt.Errorf("rate limit does not match expected format in mbit or kbit. Example: 4mbit")
   247  	}
   248  	return nil
   249  }
   250  

View as plain text