pkg/cmd/cmdutil/cmdutil.go (98 lines of code) (raw):
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
package cmdutil
import (
"fmt"
"strings"
"time"
cfg "github.com/aws/amazon-ec2-metadata-mock/pkg/config"
e "github.com/aws/amazon-ec2-metadata-mock/pkg/error"
"github.com/aws/amazon-ec2-metadata-mock/pkg/mock/asglifecycle"
"github.com/aws/amazon-ec2-metadata-mock/pkg/mock/dynamic"
"github.com/aws/amazon-ec2-metadata-mock/pkg/mock/events"
"github.com/aws/amazon-ec2-metadata-mock/pkg/mock/handlers"
"github.com/aws/amazon-ec2-metadata-mock/pkg/mock/imdsv2"
"github.com/aws/amazon-ec2-metadata-mock/pkg/mock/spot"
"github.com/aws/amazon-ec2-metadata-mock/pkg/mock/static"
"github.com/aws/amazon-ec2-metadata-mock/pkg/mock/userdata"
"github.com/aws/amazon-ec2-metadata-mock/pkg/server"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
// BinName is the name of this tool's binary
const BinName = "ec2-metadata-mock"
// handlerPair holds a tuple of a path and its associated handler
type handlerPair struct {
path string
handler server.HandlerType
}
// Contains finds a string in the given array
func Contains(slice []string, val string) bool {
for _, item := range slice {
if item == val {
return true
}
}
return false
}
// PrintFlags prints all flags of a command, if set
func PrintFlags(flags *pflag.FlagSet) {
f := make(map[string]interface{})
flags.Visit(func(flag *pflag.Flag) {
f[flag.Name] = flag.Value
})
if len(f) > 0 {
fmt.Println("\nFlags:")
for key, value := range f {
fmt.Printf("%s: %s\n", key, value)
}
fmt.Println()
}
}
// ValidateRFC3339TimeFormat validates an input time matches RFC3339 format
func ValidateRFC3339TimeFormat(flagName string, input string) error {
if _, err := time.Parse(time.RFC3339, input); err != nil {
return e.FlagValidationError{
FlagName: flagName,
Allowed: "time in RFC3339 format, e.g. 2020-01-07T01:03:47Z",
InvalidValue: input}
}
return nil
}
// RegisterHandlers binds paths to handlers for ALL commands
func RegisterHandlers(cmd *cobra.Command, config cfg.Config) {
handlerPairsToRegister := getHandlerPairs(cmd, config)
for _, handlerPair := range handlerPairsToRegister {
if config.Imdsv2Required {
server.HandleFunc(handlerPair.path, imdsv2.ValidateToken(handlerPair.handler))
} else {
server.HandleFunc(handlerPair.path, handlerPair.handler)
}
}
static.RegisterHandlers(config)
dynamic.RegisterHandlers(config)
userdata.RegisterHandlers(config)
// paths without explicit handler bindings will fallback to CatchAllHandler
server.HandleFuncPrefix("/", handlers.CatchAllHandler)
}
// getHandlerPairs returns a slice of {paths, handlers} to register
func getHandlerPairs(cmd *cobra.Command, config cfg.Config) []handlerPair {
// always register these paths
handlerPairs := []handlerPair{
{path: "/", handler: handlers.ListRoutesHandler},
{path: "/latest", handler: handlers.ListRoutesHandler},
{path: static.ServicePath, handler: handlers.ListRoutesHandler},
{path: dynamic.ServicePath, handler: handlers.ListRoutesHandler},
}
isSpot := strings.Contains(cmd.Name(), "spot")
isEvents := strings.Contains(cmd.Name(), "events")
isASGLifecycle := strings.Contains(cmd.Name(), "asglifecycle")
subCommandHandlers := map[string][]handlerPair{
"spot": {{path: config.Metadata.Paths.Spot, handler: spot.Handler},
{path: config.Metadata.Paths.SpotTerminationTime, handler: spot.Handler},
{path: config.Metadata.Paths.RebalanceRecTime, handler: spot.Handler}},
"events": {{path: config.Metadata.Paths.Events, handler: events.Handler}},
"asglifecycle": {{path: config.Metadata.Paths.ASGLifecycle, handler: asglifecycle.Handler}},
}
if isSpot {
handlerPairs = append(handlerPairs, subCommandHandlers["spot"]...)
} else if isEvents {
handlerPairs = append(handlerPairs, subCommandHandlers["events"]...)
} else if isASGLifecycle {
handlerPairs = append(handlerPairs, subCommandHandlers["asglifecycle"]...)
} else {
// root registers all subcommands
for k := range subCommandHandlers {
handlerPairs = append(handlerPairs, subCommandHandlers[k]...)
}
}
return handlerPairs
}