mirror of
				https://github.com/StackExchange/dnscontrol.git
				synced 2025-10-31 16:43:17 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			173 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package commands
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"log"
 | |
| 	"os"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/StackExchange/dnscontrol/v4/models"
 | |
| 	"github.com/StackExchange/dnscontrol/v4/pkg/js"
 | |
| 	"github.com/StackExchange/dnscontrol/v4/pkg/normalize"
 | |
| 	"github.com/urfave/cli/v2"
 | |
| )
 | |
| 
 | |
| var _ = cmd(catDebug, func() *cli.Command {
 | |
| 	var args PrintIRArgs
 | |
| 	return &cli.Command{
 | |
| 		Name:  "print-ir",
 | |
| 		Usage: "Output intermediate representation (IR) after running validation and normalization logic.",
 | |
| 		Action: func(c *cli.Context) error {
 | |
| 			return exit(PrintIR(args))
 | |
| 		},
 | |
| 		Flags: args.flags(),
 | |
| 	}
 | |
| }())
 | |
| 
 | |
| // CheckArgs encapsulates the flags/arguments for the check command.
 | |
| type CheckArgs struct {
 | |
| 	GetDNSConfigArgs
 | |
| }
 | |
| 
 | |
| var _ = cmd(catDebug, func() *cli.Command {
 | |
| 	var args CheckArgs
 | |
| 	// This is the same as print-ir with the following changes:
 | |
| 	// - no JSON is output
 | |
| 	// - error messages are sent to stdout.
 | |
| 	// - prints "No errors." if there were no errors.
 | |
| 	return &cli.Command{
 | |
| 		Name:  "check",
 | |
| 		Usage: "Check and validate dnsconfig.js. Output to stdout.  Do not access providers.",
 | |
| 		Action: func(c *cli.Context) error {
 | |
| 
 | |
| 			// Create a PrintIRArgs struct and copy our args to the
 | |
| 			// appropriate fields.
 | |
| 			var pargs PrintIRArgs
 | |
| 			// Copy these verbatim:
 | |
| 			pargs.JSFile = args.JSFile
 | |
| 			pargs.JSONFile = args.JSONFile
 | |
| 			pargs.DevMode = args.DevMode
 | |
| 			pargs.Variable = args.Variable
 | |
| 			// Force these settings:
 | |
| 			pargs.Pretty = false
 | |
| 			pargs.Output = os.DevNull
 | |
| 
 | |
| 			// "check" sends all errors to stdout, not stderr.
 | |
| 			cli.ErrWriter = os.Stdout
 | |
| 			log.SetOutput(os.Stdout)
 | |
| 
 | |
| 			err := exit(PrintIR(pargs))
 | |
| 			if err == nil {
 | |
| 				fmt.Fprintf(os.Stdout, "No errors.\n")
 | |
| 			}
 | |
| 			return err
 | |
| 		},
 | |
| 		Flags: args.flags(),
 | |
| 	}
 | |
| }())
 | |
| 
 | |
| // PrintIRArgs encapsulates the flags/arguments for the print-ir command.
 | |
| type PrintIRArgs struct {
 | |
| 	GetDNSConfigArgs
 | |
| 	PrintJSONArgs
 | |
| 	Raw bool
 | |
| }
 | |
| 
 | |
| func (args *PrintIRArgs) flags() []cli.Flag {
 | |
| 	flags := append(args.GetDNSConfigArgs.flags(), args.PrintJSONArgs.flags()...)
 | |
| 	flags = append(flags, &cli.BoolFlag{
 | |
| 		Name:        "raw",
 | |
| 		Usage:       "Skip validation and normalization. Just print js result.",
 | |
| 		Destination: &args.Raw,
 | |
| 	})
 | |
| 	return flags
 | |
| }
 | |
| 
 | |
| // PrintIR implements the print-ir subcommand.
 | |
| func PrintIR(args PrintIRArgs) error {
 | |
| 	cfg, err := GetDNSConfig(args.GetDNSConfigArgs)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if !args.Raw {
 | |
| 		errs := normalize.ValidateAndNormalizeConfig(cfg)
 | |
| 		if PrintValidationErrors(errs) {
 | |
| 			return fmt.Errorf("exiting due to validation errors")
 | |
| 		}
 | |
| 	}
 | |
| 	return PrintJSON(args.PrintJSONArgs, cfg)
 | |
| }
 | |
| 
 | |
| // PrintValidationErrors formats and prints the validation errors and warnings.
 | |
| func PrintValidationErrors(errs []error) (fatal bool) {
 | |
| 	if len(errs) == 0 {
 | |
| 		return false
 | |
| 	}
 | |
| 	log.Printf("%d Validation errors:\n", len(errs))
 | |
| 	for _, err := range errs {
 | |
| 		if _, ok := err.(normalize.Warning); ok {
 | |
| 			log.Printf("WARNING: %s\n", err)
 | |
| 		} else {
 | |
| 			fatal = true
 | |
| 			log.Printf("ERROR: %s\n", err)
 | |
| 		}
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // ExecuteDSL executes the dnsconfig.js contents.
 | |
| func ExecuteDSL(args ExecuteDSLArgs) (*models.DNSConfig, error) {
 | |
| 	if args.JSFile == "" {
 | |
| 		return nil, fmt.Errorf("no config specified")
 | |
| 	}
 | |
| 
 | |
| 	dnsConfig, err := js.ExecuteJavaScript(args.JSFile, args.DevMode, stringSliceToMap(args.Variable))
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("executing %s: %w", args.JSFile, err)
 | |
| 	}
 | |
| 	return dnsConfig, nil
 | |
| }
 | |
| 
 | |
| // PrintJSON outputs/prettyprints the IR data.
 | |
| func PrintJSON(args PrintJSONArgs, config *models.DNSConfig) (err error) {
 | |
| 	var dat []byte
 | |
| 	if args.Pretty {
 | |
| 		dat, err = json.MarshalIndent(config, "", "  ")
 | |
| 	} else {
 | |
| 		dat, err = json.Marshal(config)
 | |
| 	}
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if args.Output != "" {
 | |
| 		f, err := os.Create(args.Output)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		defer f.Close()
 | |
| 		_, err = f.Write(dat)
 | |
| 		return err
 | |
| 	}
 | |
| 	fmt.Println(string(dat))
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func exit(err error) error {
 | |
| 	if err == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return cli.Exit(err, 1)
 | |
| }
 | |
| 
 | |
| // stringSliceToMap converts cli.StringSlice to map[string]string for further processing
 | |
| func stringSliceToMap(stringSlice cli.StringSlice) map[string]string {
 | |
| 	mapString := make(map[string]string, len(stringSlice.Value()))
 | |
| 	for _, values := range stringSlice.Value() {
 | |
| 		parts := strings.SplitN(values, "=", 2)
 | |
| 		if len(parts) == 2 {
 | |
| 			mapString[parts[0]] = parts[1]
 | |
| 		}
 | |
| 	}
 | |
| 	return mapString
 | |
| }
 |