<commit_before>package main

import (
	"bytes"
	"crypto/rand"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"

	"github.com/cloudfoundry/bosh-bootloader/application"
	"github.com/cloudfoundry/bosh-bootloader/aws"
	"github.com/cloudfoundry/bosh-bootloader/azure"
	"github.com/cloudfoundry/bosh-bootloader/backends"
	"github.com/cloudfoundry/bosh-bootloader/bosh"
	"github.com/cloudfoundry/bosh-bootloader/certs"
	"github.com/cloudfoundry/bosh-bootloader/cloudconfig"
	"github.com/cloudfoundry/bosh-bootloader/commands"
	"github.com/cloudfoundry/bosh-bootloader/config"
	"github.com/cloudfoundry/bosh-bootloader/gcp"
	"github.com/cloudfoundry/bosh-bootloader/helpers"
	"github.com/cloudfoundry/bosh-bootloader/renderers"
	"github.com/cloudfoundry/bosh-bootloader/runtimeconfig"
	"github.com/cloudfoundry/bosh-bootloader/ssh"
	"github.com/cloudfoundry/bosh-bootloader/storage"
	"github.com/cloudfoundry/bosh-bootloader/terraform"
	"github.com/spf13/afero"

	awscloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/aws"
	azurecloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/azure"
	gcpcloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/gcp"
	openstackcloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/openstack"
	vspherecloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/vsphere"

	awsterraform "github.com/cloudfoundry/bosh-bootloader/terraform/aws"
	azureterraform "github.com/cloudfoundry/bosh-bootloader/terraform/azure"
	gcpterraform "github.com/cloudfoundry/bosh-bootloader/terraform/gcp"
	openstackterraform "github.com/cloudfoundry/bosh-bootloader/terraform/openstack"
	vsphereterraform "github.com/cloudfoundry/bosh-bootloader/terraform/vsphere"

	awsleftovers "github.com/genevieve/leftovers/aws"
	azureleftovers "github.com/genevieve/leftovers/azure"
	gcpleftovers "github.com/genevieve/leftovers/gcp"
	vsphereleftovers "github.com/genevieve/leftovers/vsphere"
)

var Version = "dev"

func main() {
	log.SetFlags(0)

	logger := application.NewLogger(os.Stdout, os.Stdin)
	stderrLogger := application.NewLogger(os.Stderr, os.Stdin)
	stateBootstrap := storage.NewStateBootstrap(stderrLogger, Version)
	envRendererFactory := renderers.NewFactory(helpers.NewEnvGetter())

	globals, remainingArgs, err := config.ParseArgs(os.Args)
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}
	if globals.NoConfirm {
		logger.NoConfirm()
	}

	// File IO
	fs := afero.NewOsFs()
	afs := &afero.Afero{Fs: fs}

	// bbl Configuration
	garbageCollector := storage.NewGarbageCollector(afs)
	stateStore := storage.NewStore(globals.StateDir, afs, garbageCollector)
	patchDetector := storage.NewPatchDetector(globals.StateDir, logger)
	stateMigrator := storage.NewMigrator(stateStore, afs)
	stateMerger := config.NewMerger(afs)
	storageProvider := backends.NewProvider()
	stateDownloader := config.NewDownloader(storageProvider)
	newConfig := config.NewConfig(stateBootstrap, stateMigrator, stateMerger, stateDownloader, stderrLogger, afs)

	appConfig, err := newConfig.Bootstrap(globals, remainingArgs, len(os.Args))
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}

	// Utilities
	envIDGenerator := helpers.NewEnvIDGenerator(rand.Reader)
	stateValidator := application.NewStateValidator(appConfig.Global.StateDir)
	certificateValidator := certs.NewValidator()
	lbArgsHandler := commands.NewLBArgsHandler(certificateValidator)
	sshCLI := ssh.NewCLI(os.Stdin, os.Stdout, os.Stderr)
	pathFinder := helpers.NewPathFinder()

	// Terraform
	terraformOutputBuffer := bytes.NewBuffer([]byte{})
	dotTerraformDir := filepath.Join(appConfig.Global.StateDir, "terraform", ".terraform")
	bufferingCLI := terraform.NewCLI(terraformOutputBuffer, terraformOutputBuffer, dotTerraformDir)
	var (
		terraformCLI terraform.CLI
		out          io.Writer
	)
	if appConfig.Global.Debug {
		errBuffer := io.MultiWriter(os.Stderr, terraformOutputBuffer)
		terraformCLI = terraform.NewCLI(errBuffer, terraformOutputBuffer, dotTerraformDir)
		out = os.Stdout
	} else {
		terraformCLI = bufferingCLI
		out = ioutil.Discard
	}
	terraformExecutor := terraform.NewExecutor(terraformCLI, bufferingCLI, stateStore, afs, appConfig.Global.Debug, out)

	// BOSH
	boshPath, err := config.GetBOSHPath()
	if err != nil {
		log.Fatal(err)
	}
	boshCommand := bosh.NewCLI(os.Stderr, boshPath)
	boshExecutor := bosh.NewExecutor(boshCommand, afs)
	sshKeyGetter := bosh.NewSSHKeyGetter(stateStore, afs)
	allProxyGetter := bosh.NewAllProxyGetter(sshKeyGetter, afs)
	credhubGetter := bosh.NewCredhubGetter(stateStore, afs)
	boshCLIProvider := bosh.NewCLIProvider(allProxyGetter, boshPath)
	boshManager := bosh.NewManager(boshExecutor, logger, stateStore, sshKeyGetter, afs, boshCLIProvider)

	configUpdater := bosh.NewConfigUpdater(boshCLIProvider)

	// Clients that require IAAS credentials.
	var (
		// function extract InitializeNetworkClients
		networkClient            helpers.NetworkClient
		networkDeletionValidator commands.NetworkDeletionValidator

		// function extract InitializeLeftovers
		leftovers commands.FilteredDeleter

		awsClient aws.Client
	)
	// IF we could push this whole block down out of main somehow
	if appConfig.CommandModifiesState {
		switch appConfig.State.IAAS {
		case "aws":
			awsClient = aws.NewClient(appConfig.State.AWS, logger)

			networkDeletionValidator = awsClient
			networkClient = awsClient

			leftovers, err = awsleftovers.NewLeftovers(logger, appConfig.State.AWS.AccessKeyID, appConfig.State.AWS.SecretAccessKey, appConfig.State.AWS.Region)
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}

		case "gcp":
			gcpClient, err := gcp.NewClient(appConfig.State.GCP, "")
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}

			networkDeletionValidator = gcpClient
			networkClient = gcpClient

			gcpZonerHack := config.NewGCPZonerHack(gcpClient)
			stateWithZones, err := gcpZonerHack.SetZones(appConfig.State)
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}
			appConfig.State = stateWithZones

			leftovers, err = gcpleftovers.NewLeftovers(logger, appConfig.State.GCP.ServiceAccountKeyPath)
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}

		case "azure":
			azureClient, err := azure.NewClient(appConfig.State.Azure)
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}

			networkDeletionValidator = azureClient
			networkClient = azureClient

			leftovers, err = azureleftovers.NewLeftovers(logger, appConfig.State.Azure.ClientID, appConfig.State.Azure.ClientSecret, appConfig.State.Azure.SubscriptionID, appConfig.State.Azure.TenantID)
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}
		case "vsphere":
			vSphereLogger := application.NewLogger(os.Stdout, os.Stdin)
			leftovers, err = vsphereleftovers.NewLeftovers(vSphereLogger, appConfig.State.VSphere.VCenterIP, appConfig.State.VSphere.VCenterUser, appConfig.State.VSphere.VCenterPassword, appConfig.State.VSphere.VCenterDC)
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}
		}
	}

	// Objects that do not require IAAS credentials.
	var (
		inputGenerator    terraform.InputGenerator
		templateGenerator terraform.TemplateGenerator

		terraformManager        terraform.Manager
		cloudConfigOpsGenerator cloudconfig.OpsGenerator

		lbsCmd commands.LBsCmd
	)
	switch appConfig.State.IAAS {
	case "aws":
		templateGenerator = awsterraform.NewTemplateGenerator()
		inputGenerator = awsterraform.NewInputGenerator(awsClient)

		terraformManager = terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

		cloudConfigOpsGenerator = awscloudconfig.NewOpsGenerator(terraformManager, awsClient)

		lbsCmd = commands.NewAWSLBs(terraformManager, logger)
	case "azure":
		templateGenerator = azureterraform.NewTemplateGenerator()
		inputGenerator = azureterraform.NewInputGenerator()

		terraformManager = terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

		cloudConfigOpsGenerator = azurecloudconfig.NewOpsGenerator(terraformManager)

		lbsCmd = commands.NewAzureLBs(terraformManager, logger)
	case "gcp":
		templateGenerator = gcpterraform.NewTemplateGenerator()
		inputGenerator = gcpterraform.NewInputGenerator()

		terraformManager = terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

		cloudConfigOpsGenerator = gcpcloudconfig.NewOpsGenerator(terraformManager)

		lbsCmd = commands.NewGCPLBs(terraformManager, logger)
	case "vsphere":
		templateGenerator = vsphereterraform.NewTemplateGenerator()
		inputGenerator = vsphereterraform.NewInputGenerator()

		terraformManager = terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

		cloudConfigOpsGenerator = vspherecloudconfig.NewOpsGenerator(terraformManager)

	case "openstack":
		templateGenerator = openstackterraform.NewTemplateGenerator()
		inputGenerator = openstackterraform.NewInputGenerator()

		terraformManager = terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

		cloudConfigOpsGenerator = openstackcloudconfig.NewOpsGenerator(terraformManager)
	}

	cloudConfigManager := cloudconfig.NewManager(logger, configUpdater, stateStore, cloudConfigOpsGenerator, terraformManager, afs)
	runtimeConfigManager := runtimeconfig.NewManager(logger, stateStore, configUpdater, afs)

	// Commands
	var envIDManager helpers.EnvIDManager
	if appConfig.State.IAAS != "" {
		envIDManager = helpers.NewEnvIDManager(envIDGenerator, networkClient)
	}
	plan := commands.NewPlan(boshManager, cloudConfigManager, runtimeConfigManager, stateStore, patchDetector, envIDManager, terraformManager, lbArgsHandler, stderrLogger, Version)
	up := commands.NewUp(plan, boshManager, cloudConfigManager, runtimeConfigManager, stateStore, terraformManager)
	usage := commands.NewUsage(logger)

	commandSet := application.CommandSet{}
	commandSet["help"] = usage
	commandSet["version"] = commands.NewVersion(Version, logger)
	commandSet["outputs"] = commands.NewOutputs(logger, terraformManager, stateValidator)
	commandSet["up"] = up
	commandSet["plan"] = plan
	sshKeyDeleter := bosh.NewSSHKeyDeleter(stateStore, afs)
	commandSet["rotate"] = commands.NewRotate(stateValidator, sshKeyDeleter, up)
	commandSet["destroy"] = commands.NewDestroy(plan, logger, boshManager, stateStore, stateValidator, terraformManager, networkDeletionValidator)
	commandSet["down"] = commandSet["destroy"]
	commandSet["cleanup-leftovers"] = commands.NewCleanupLeftovers(leftovers)
	commandSet["leftovers"] = commandSet["cleanup-leftovers"]
	commandSet["lbs"] = commands.NewLBs(lbsCmd, stateValidator)
	commandSet["jumpbox-address"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.JumpboxAddressPropertyName)
	commandSet["director-address"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorAddressPropertyName)
	commandSet["director-username"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorUsernamePropertyName)
	commandSet["director-password"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorPasswordPropertyName)
	commandSet["director-ca-cert"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorCACertPropertyName)
	commandSet["ssh-key"] = commands.NewSSHKey(logger, stateValidator, sshKeyGetter)
	commandSet["validate"] = commands.NewValidate(plan, stateStore, terraformManager)
	commandSet["director-ssh-key"] = commands.NewDirectorSSHKey(logger, stateValidator, sshKeyGetter)
	commandSet["env-id"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.EnvIDPropertyName)
	commandSet["latest-error"] = commands.NewLatestError(logger, stateValidator)
	commandSet["print-env"] = commands.NewPrintEnv(logger, stderrLogger, stateValidator, allProxyGetter, credhubGetter, terraformManager, afs, envRendererFactory)
	commandSet["ssh"] = commands.NewSSH(logger, sshCLI, sshKeyGetter, pathFinder, afs, ssh.RandomPort{})

	app := application.New(commandSet, appConfig, usage)

	err = app.Run()
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}
}
<commit_msg>need to account for new aws leftovers<commit_after>package main

import (
	"bytes"
	"crypto/rand"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"

	"github.com/cloudfoundry/bosh-bootloader/application"
	"github.com/cloudfoundry/bosh-bootloader/aws"
	"github.com/cloudfoundry/bosh-bootloader/azure"
	"github.com/cloudfoundry/bosh-bootloader/backends"
	"github.com/cloudfoundry/bosh-bootloader/bosh"
	"github.com/cloudfoundry/bosh-bootloader/certs"
	"github.com/cloudfoundry/bosh-bootloader/cloudconfig"
	"github.com/cloudfoundry/bosh-bootloader/commands"
	"github.com/cloudfoundry/bosh-bootloader/config"
	"github.com/cloudfoundry/bosh-bootloader/gcp"
	"github.com/cloudfoundry/bosh-bootloader/helpers"
	"github.com/cloudfoundry/bosh-bootloader/renderers"
	"github.com/cloudfoundry/bosh-bootloader/runtimeconfig"
	"github.com/cloudfoundry/bosh-bootloader/ssh"
	"github.com/cloudfoundry/bosh-bootloader/storage"
	"github.com/cloudfoundry/bosh-bootloader/terraform"
	"github.com/spf13/afero"

	awscloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/aws"
	azurecloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/azure"
	gcpcloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/gcp"
	openstackcloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/openstack"
	vspherecloudconfig "github.com/cloudfoundry/bosh-bootloader/cloudconfig/vsphere"

	awsterraform "github.com/cloudfoundry/bosh-bootloader/terraform/aws"
	azureterraform "github.com/cloudfoundry/bosh-bootloader/terraform/azure"
	gcpterraform "github.com/cloudfoundry/bosh-bootloader/terraform/gcp"
	openstackterraform "github.com/cloudfoundry/bosh-bootloader/terraform/openstack"
	vsphereterraform "github.com/cloudfoundry/bosh-bootloader/terraform/vsphere"

	awsleftovers "github.com/genevieve/leftovers/aws"
	azureleftovers "github.com/genevieve/leftovers/azure"
	gcpleftovers "github.com/genevieve/leftovers/gcp"
	vsphereleftovers "github.com/genevieve/leftovers/vsphere"
)

var Version = "dev"

func main() {
	log.SetFlags(0)

	logger := application.NewLogger(os.Stdout, os.Stdin)
	stderrLogger := application.NewLogger(os.Stderr, os.Stdin)
	stateBootstrap := storage.NewStateBootstrap(stderrLogger, Version)
	envRendererFactory := renderers.NewFactory(helpers.NewEnvGetter())

	globals, remainingArgs, err := config.ParseArgs(os.Args)
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}
	if globals.NoConfirm {
		logger.NoConfirm()
	}

	// File IO
	fs := afero.NewOsFs()
	afs := &afero.Afero{Fs: fs}

	// bbl Configuration
	garbageCollector := storage.NewGarbageCollector(afs)
	stateStore := storage.NewStore(globals.StateDir, afs, garbageCollector)
	patchDetector := storage.NewPatchDetector(globals.StateDir, logger)
	stateMigrator := storage.NewMigrator(stateStore, afs)
	stateMerger := config.NewMerger(afs)
	storageProvider := backends.NewProvider()
	stateDownloader := config.NewDownloader(storageProvider)
	newConfig := config.NewConfig(stateBootstrap, stateMigrator, stateMerger, stateDownloader, stderrLogger, afs)

	appConfig, err := newConfig.Bootstrap(globals, remainingArgs, len(os.Args))
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}

	// Utilities
	envIDGenerator := helpers.NewEnvIDGenerator(rand.Reader)
	stateValidator := application.NewStateValidator(appConfig.Global.StateDir)
	certificateValidator := certs.NewValidator()
	lbArgsHandler := commands.NewLBArgsHandler(certificateValidator)
	sshCLI := ssh.NewCLI(os.Stdin, os.Stdout, os.Stderr)
	pathFinder := helpers.NewPathFinder()

	// Terraform
	terraformOutputBuffer := bytes.NewBuffer([]byte{})
	dotTerraformDir := filepath.Join(appConfig.Global.StateDir, "terraform", ".terraform")
	bufferingCLI := terraform.NewCLI(terraformOutputBuffer, terraformOutputBuffer, dotTerraformDir)
	var (
		terraformCLI terraform.CLI
		out          io.Writer
	)
	if appConfig.Global.Debug {
		errBuffer := io.MultiWriter(os.Stderr, terraformOutputBuffer)
		terraformCLI = terraform.NewCLI(errBuffer, terraformOutputBuffer, dotTerraformDir)
		out = os.Stdout
	} else {
		terraformCLI = bufferingCLI
		out = ioutil.Discard
	}
	terraformExecutor := terraform.NewExecutor(terraformCLI, bufferingCLI, stateStore, afs, appConfig.Global.Debug, out)

	// BOSH
	boshPath, err := config.GetBOSHPath()
	if err != nil {
		log.Fatal(err)
	}
	boshCommand := bosh.NewCLI(os.Stderr, boshPath)
	boshExecutor := bosh.NewExecutor(boshCommand, afs)
	sshKeyGetter := bosh.NewSSHKeyGetter(stateStore, afs)
	allProxyGetter := bosh.NewAllProxyGetter(sshKeyGetter, afs)
	credhubGetter := bosh.NewCredhubGetter(stateStore, afs)
	boshCLIProvider := bosh.NewCLIProvider(allProxyGetter, boshPath)
	boshManager := bosh.NewManager(boshExecutor, logger, stateStore, sshKeyGetter, afs, boshCLIProvider)

	configUpdater := bosh.NewConfigUpdater(boshCLIProvider)

	// Clients that require IAAS credentials.
	var (
		// function extract InitializeNetworkClients
		networkClient            helpers.NetworkClient
		networkDeletionValidator commands.NetworkDeletionValidator

		// function extract InitializeLeftovers
		leftovers commands.FilteredDeleter

		awsClient aws.Client
	)
	// IF we could push this whole block down out of main somehow
	if appConfig.CommandModifiesState {
		switch appConfig.State.IAAS {
		case "aws":
			awsClient = aws.NewClient(appConfig.State.AWS, logger)

			networkDeletionValidator = awsClient
			networkClient = awsClient

			sessionToken := ""
			leftovers, err = awsleftovers.NewLeftovers(logger, appConfig.State.AWS.AccessKeyID, appConfig.State.AWS.SecretAccessKey, appConfig.State.AWS.Region, sessionToken)
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}

		case "gcp":
			gcpClient, err := gcp.NewClient(appConfig.State.GCP, "")
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}

			networkDeletionValidator = gcpClient
			networkClient = gcpClient

			gcpZonerHack := config.NewGCPZonerHack(gcpClient)
			stateWithZones, err := gcpZonerHack.SetZones(appConfig.State)
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}
			appConfig.State = stateWithZones

			leftovers, err = gcpleftovers.NewLeftovers(logger, appConfig.State.GCP.ServiceAccountKeyPath)
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}

		case "azure":
			azureClient, err := azure.NewClient(appConfig.State.Azure)
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}

			networkDeletionValidator = azureClient
			networkClient = azureClient

			leftovers, err = azureleftovers.NewLeftovers(logger, appConfig.State.Azure.ClientID, appConfig.State.Azure.ClientSecret, appConfig.State.Azure.SubscriptionID, appConfig.State.Azure.TenantID)
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}
		case "vsphere":
			vSphereLogger := application.NewLogger(os.Stdout, os.Stdin)
			leftovers, err = vsphereleftovers.NewLeftovers(vSphereLogger, appConfig.State.VSphere.VCenterIP, appConfig.State.VSphere.VCenterUser, appConfig.State.VSphere.VCenterPassword, appConfig.State.VSphere.VCenterDC)
			if err != nil {
				log.Fatalf("\n\n%s\n", err)
			}
		}
	}

	// Objects that do not require IAAS credentials.
	var (
		inputGenerator    terraform.InputGenerator
		templateGenerator terraform.TemplateGenerator

		terraformManager        terraform.Manager
		cloudConfigOpsGenerator cloudconfig.OpsGenerator

		lbsCmd commands.LBsCmd
	)
	switch appConfig.State.IAAS {
	case "aws":
		templateGenerator = awsterraform.NewTemplateGenerator()
		inputGenerator = awsterraform.NewInputGenerator(awsClient)

		terraformManager = terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

		cloudConfigOpsGenerator = awscloudconfig.NewOpsGenerator(terraformManager, awsClient)

		lbsCmd = commands.NewAWSLBs(terraformManager, logger)
	case "azure":
		templateGenerator = azureterraform.NewTemplateGenerator()
		inputGenerator = azureterraform.NewInputGenerator()

		terraformManager = terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

		cloudConfigOpsGenerator = azurecloudconfig.NewOpsGenerator(terraformManager)

		lbsCmd = commands.NewAzureLBs(terraformManager, logger)
	case "gcp":
		templateGenerator = gcpterraform.NewTemplateGenerator()
		inputGenerator = gcpterraform.NewInputGenerator()

		terraformManager = terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

		cloudConfigOpsGenerator = gcpcloudconfig.NewOpsGenerator(terraformManager)

		lbsCmd = commands.NewGCPLBs(terraformManager, logger)
	case "vsphere":
		templateGenerator = vsphereterraform.NewTemplateGenerator()
		inputGenerator = vsphereterraform.NewInputGenerator()

		terraformManager = terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

		cloudConfigOpsGenerator = vspherecloudconfig.NewOpsGenerator(terraformManager)

	case "openstack":
		templateGenerator = openstackterraform.NewTemplateGenerator()
		inputGenerator = openstackterraform.NewInputGenerator()

		terraformManager = terraform.NewManager(terraformExecutor, templateGenerator, inputGenerator, terraformOutputBuffer, logger)

		cloudConfigOpsGenerator = openstackcloudconfig.NewOpsGenerator(terraformManager)
	}

	cloudConfigManager := cloudconfig.NewManager(logger, configUpdater, stateStore, cloudConfigOpsGenerator, terraformManager, afs)
	runtimeConfigManager := runtimeconfig.NewManager(logger, stateStore, configUpdater, afs)

	// Commands
	var envIDManager helpers.EnvIDManager
	if appConfig.State.IAAS != "" {
		envIDManager = helpers.NewEnvIDManager(envIDGenerator, networkClient)
	}
	plan := commands.NewPlan(boshManager, cloudConfigManager, runtimeConfigManager, stateStore, patchDetector, envIDManager, terraformManager, lbArgsHandler, stderrLogger, Version)
	up := commands.NewUp(plan, boshManager, cloudConfigManager, runtimeConfigManager, stateStore, terraformManager)
	usage := commands.NewUsage(logger)

	commandSet := application.CommandSet{}
	commandSet["help"] = usage
	commandSet["version"] = commands.NewVersion(Version, logger)
	commandSet["outputs"] = commands.NewOutputs(logger, terraformManager, stateValidator)
	commandSet["up"] = up
	commandSet["plan"] = plan
	sshKeyDeleter := bosh.NewSSHKeyDeleter(stateStore, afs)
	commandSet["rotate"] = commands.NewRotate(stateValidator, sshKeyDeleter, up)
	commandSet["destroy"] = commands.NewDestroy(plan, logger, boshManager, stateStore, stateValidator, terraformManager, networkDeletionValidator)
	commandSet["down"] = commandSet["destroy"]
	commandSet["cleanup-leftovers"] = commands.NewCleanupLeftovers(leftovers)
	commandSet["leftovers"] = commandSet["cleanup-leftovers"]
	commandSet["lbs"] = commands.NewLBs(lbsCmd, stateValidator)
	commandSet["jumpbox-address"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.JumpboxAddressPropertyName)
	commandSet["director-address"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorAddressPropertyName)
	commandSet["director-username"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorUsernamePropertyName)
	commandSet["director-password"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorPasswordPropertyName)
	commandSet["director-ca-cert"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.DirectorCACertPropertyName)
	commandSet["ssh-key"] = commands.NewSSHKey(logger, stateValidator, sshKeyGetter)
	commandSet["validate"] = commands.NewValidate(plan, stateStore, terraformManager)
	commandSet["director-ssh-key"] = commands.NewDirectorSSHKey(logger, stateValidator, sshKeyGetter)
	commandSet["env-id"] = commands.NewStateQuery(logger, stateValidator, terraformManager, commands.EnvIDPropertyName)
	commandSet["latest-error"] = commands.NewLatestError(logger, stateValidator)
	commandSet["print-env"] = commands.NewPrintEnv(logger, stderrLogger, stateValidator, allProxyGetter, credhubGetter, terraformManager, afs, envRendererFactory)
	commandSet["ssh"] = commands.NewSSH(logger, sshCLI, sshKeyGetter, pathFinder, afs, ssh.RandomPort{})

	app := application.New(commandSet, appConfig, usage)

	err = app.Run()
	if err != nil {
		log.Fatalf("\n\n%s\n", err)
	}
}
<|endoftext|>


<commit_before>package pages

import (
	"encoding/gob"
	"net/http"
	"strconv"
	"strings"

	"database/sql"

	"github.com/gorilla/sessions"
	"github.com/upframe/fest/models"
)

type cartItem struct {
	*models.Product
	Quantity int
}

type cart struct {
	Products map[int]*cartItem
	Total    int
}

func init() {
	gob.Register(cartItem{})
	gob.Register(cart{})
}

// CartGET returns the list of items in the cart
func CartGET(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	if !IsLoggedIn(s) {
		return Redirect(w, r, "/login")
	}

	// Initialize our data variable and the map of products.
	data := &cart{
		Products: map[int]*cartItem{},
	}

	for _, id := range s.Values["Cart"].([]int) {
		// Gets the product, checks if it exists and checks for errors.
		generic, err := models.GetProduct(id)
		if err == sql.ErrNoRows {
			continue
		}
		if err != nil {
			return http.StatusInternalServerError, err
		}

		product := generic.(*models.Product)
		if product.Deactivated {
			continue
		}

		if val, ok := data.Products[id]; ok {
			// If the Product is already in the cart, increment the quantity
			// Notice that in order for this to work, we have to use pointers
			// (check line 20) and not "normal" values
			val.Quantity++
		} else {
			// Otherwise, we just create a new Cart item, with the product
			data.Products[id] = &cartItem{
				Product:  product,
				Quantity: 1,
			}
		}

		// Increments the total
		data.Total += product.Price
	}

	return RenderHTML(w, s, data, "cart")
}

// CartPOST adds a product to the cart
func CartPOST(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	if !IsLoggedIn(s) {
		return http.StatusUnauthorized, nil
	}

	id, err := strconv.Atoi(strings.Replace(r.URL.Path, "/cart/", "", -1))
	if err != nil {
		return http.StatusInternalServerError, err
	}

	product, err := models.GetProduct(id)
	if err == sql.ErrNoRows {
		return http.StatusNotFound, err
	}
	if err != nil {
		return http.StatusInternalServerError, err
	}
	if product.(*models.Product).Deactivated {
		return http.StatusNotFound, nil
	}

	s.Values["Cart"] = append(s.Values["Cart"].([]int), id)
	err = s.Save(r, w)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	return http.StatusOK, nil
}

// CartDELETE removes a product from the cart
func CartDELETE(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	if !IsLoggedIn(s) {
		return http.StatusUnauthorized, nil
	}

	id, err := strconv.Atoi(strings.Replace(r.URL.Path, "/cart/", "", 1))
	if err != nil {
		return http.StatusInternalServerError, err
	}

	return http.StatusOK, nil
}
<commit_msg>updateji<commit_after>package pages

import (
	"encoding/gob"
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"database/sql"

	"github.com/gorilla/sessions"
	"github.com/upframe/fest/models"
)

type cartItem struct {
	*models.Product
	Quantity int
}

type cart struct {
	Products map[int]*cartItem
	Total    int
}

func init() {
	gob.Register(cartItem{})
	gob.Register(cart{})
}

// CartGET returns the list of items in the cart
func CartGET(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	if !IsLoggedIn(s) {
		return Redirect(w, r, "/login")
	}

	return RenderHTML(w, s, s.Values["Cart"], "cart")
}

// CartPOST adds a product to the cart
func CartPOST(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	if !IsLoggedIn(s) {
		return http.StatusUnauthorized, nil
	}

	id, err := strconv.Atoi(strings.Replace(r.URL.Path, "/cart/", "", -1))
	if err != nil {
		return http.StatusInternalServerError, err
	}

	// Gets the product, checks if it exists and checks for errors.
	generic, err := models.GetProduct(id)
	if err == sql.ErrNoRows {
		return http.StatusNotFound, err
	}
	if err != nil {
		return http.StatusInternalServerError, err
	}

	product := generic.(*models.Product)
	if product.Deactivated {
		return http.StatusNotFound, err
	}

	cart := s.Values["Cart"].(cart)

	if val, ok := cart.Products[id]; ok {
		// If the Product is already in the cart, increment the quantity
		// Notice that in order for this to work, we have to use pointers
		// (check line 20) and not "normal" values
		val.Quantity++
	} else {
		// Otherwise, we just create a new Cart item, with the product
		cart.Products[id] = &cartItem{
			Product:  product,
			Quantity: 1,
		}
	}

	// Increments the total
	cart.Total += product.Price

	s.Values["Cart"] = cart
	err = s.Save(r, w)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	return http.StatusOK, nil
}

// CartDELETE removes a product from the cart
func CartDELETE(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	if !IsLoggedIn(s) {
		return http.StatusUnauthorized, nil
	}

	id, err := strconv.Atoi(strings.Replace(r.URL.Path, "/cart/", "", 1))
	if err != nil {
		return http.StatusInternalServerError, err
	}

	fmt.Println(id)

	return http.StatusOK, nil
}
<|endoftext|>


<commit_before>package pages

import (
	"encoding/gob"
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"database/sql"

	"github.com/gorilla/sessions"
	"github.com/upframe/fest/models"
)

type cartItem struct {
	*models.Product
	Quantity int
}

type cart struct {
	Products map[int]*cartItem
	Total    int
}

func init() {
	gob.Register(cartItem{})
	gob.Register(cart{})
}

// CartGET returns the list of items in the cart
func CartGET(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	if !IsLoggedIn(s) {
		return Redirect(w, r, "/login")
	}

	return RenderHTML(w, s, s.Values["Cart"], "cart")
}

// CartPOST adds a product to the cart
func CartPOST(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	if !IsLoggedIn(s) {
		return http.StatusUnauthorized, nil
	}

	id, err := strconv.Atoi(strings.Replace(r.URL.Path, "/cart/", "", -1))
	if err != nil {
		return http.StatusInternalServerError, err
	}

	// Gets the product, checks if it exists and checks for errors.
	generic, err := models.GetProduct(id)
	if err == sql.ErrNoRows {
		return http.StatusNotFound, err
	}
	if err != nil {
		return http.StatusInternalServerError, err
	}

	product := generic.(*models.Product)
	if product.Deactivated {
		return http.StatusNotFound, err
	}

	cart := s.Values["Cart"].(cart)

	if val, ok := cart.Products[id]; ok {
		// If the Product is already in the cart, increment the quantity
		// Notice that in order for this to work, we have to use pointers
		// (check line 20) and not "normal" values
		val.Quantity++
	} else {
		// Otherwise, we just create a new Cart item, with the product
		cart.Products[id] = &cartItem{
			Product:  product,
			Quantity: 1,
		}
	}

	// Increments the total
	cart.Total += product.Price

	s.Values["Cart"] = cart
	err = s.Save(r, w)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	return http.StatusOK, nil
}

// CartDELETE removes a product from the cart
func CartDELETE(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	if !IsLoggedIn(s) {
		return http.StatusUnauthorized, nil
	}

	id, err := strconv.Atoi(strings.Replace(r.URL.Path, "/cart/", "", 1))
	if err != nil {
		return http.StatusInternalServerError, err
	}

	fmt.Println(id)

	return http.StatusOK, nil
}
<commit_msg>Cart working<commit_after>package pages

import (
	"encoding/gob"
	"net/http"
	"strconv"
	"strings"

	"database/sql"

	"github.com/gorilla/sessions"
	"github.com/upframe/fest/models"
)

type cartItem struct {
	*models.Product
	Quantity int
}

type cart struct {
	Products map[int]*cartItem
	Total    int
}

func init() {
	gob.Register(cartItem{})
	gob.Register(cart{})
}

// CartGET returns the list of items in the cart
func CartGET(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	if !IsLoggedIn(s) {
		return Redirect(w, r, "/login")
	}

	return RenderHTML(w, s, s.Values["Cart"], "cart")
}

// CartPOST adds a product to the cart
func CartPOST(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	if !IsLoggedIn(s) {
		return http.StatusUnauthorized, nil
	}

	id, err := strconv.Atoi(strings.Replace(r.URL.Path, "/cart/", "", -1))
	if err != nil {
		return http.StatusInternalServerError, err
	}

	// Gets the product, checks if it exists and checks for errors.
	generic, err := models.GetProduct(id)
	if err == sql.ErrNoRows {
		return http.StatusNotFound, err
	}
	if err != nil {
		return http.StatusInternalServerError, err
	}

	product := generic.(*models.Product)
	if product.Deactivated {
		return http.StatusNotFound, err
	}

	cart := s.Values["Cart"].(cart)

	if val, ok := cart.Products[id]; ok {
		// If the Product is already in the cart, increment the quantity
		// Notice that in order for this to work, we have to use pointers
		// (check line 20) and not "normal" values
		val.Quantity++
	} else {
		// Otherwise, we just create a new Cart item, with the product
		cart.Products[id] = &cartItem{
			Product:  product,
			Quantity: 1,
		}
	}

	// Increments the total
	cart.Total += product.Price

	s.Values["Cart"] = cart
	err = s.Save(r, w)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	return http.StatusOK, nil
}

// CartDELETE removes a product from the cart
func CartDELETE(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	if !IsLoggedIn(s) {
		return http.StatusUnauthorized, nil
	}

	id, err := strconv.Atoi(strings.Replace(r.URL.Path, "/cart/", "", 1))
	if err != nil {
		return http.StatusInternalServerError, err
	}

	cart := s.Values["Cart"].(cart)

	if val, ok := cart.Products[id]; ok {
		cart.Total -= val.Price
		if val.Quantity-1 == 0 {
			delete(cart.Products, id)
		} else {
			val.Quantity--
		}
	}
	s.Values["Cart"] = cart

	err = s.Save(r, w)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	return http.StatusOK, nil
}
<|endoftext|>


<commit_before>package ber

import "testing"

func TestNull(t *testing.T) {
	var bval BerVal

	bval.Null()

	if 0x05 != bval[0] && 0x00 != bval[1] {
		t.Fail()
	}
}

func TestBool(t *testing.T) {
	var b BerVal

	b.Bool(true)
	if 0x01 != b[0] && 0xFF != b[1] {
		t.Fail()
	}
	b.Bool(false)
	if 0x01 != b[0] && 0x00 != b[1] {
		t.Fail()
	}
}

func TestEOC(t *testing.T) {
	var b BerVal

	b.EOC()

	if 0x00 != b[0] && 0x00 != b[1] {
		t.Fail()
	}
}

func TestSet(t *testing.T) {
	var b BerVal

	b.Set()

	if 0x31 != b[0] && 0x80 != b[1] {
		t.Fail()
	}
}

func TestSequence(t *testing.T) {
	var b BerVal

	b.Sequence()

	if 0x30 != b[0] && 0x80 != b[1] {
		t.Fail()
	}
}

func TestInteger64ToBer(t *testing.T) {
	var res []byte
	min := []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
	max := []byte{0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
	zero := []byte{0x00}
	minus1 := []byte{0xFF}
	one := []byte{0x01}
	vr1 := []byte{0xFF, 0x04}                   // -252
	vr2 := []byte{0xFD, 0x6D, 0x83, 0x7E}       // -43154562
	vr3 := []byte{0x00, 0xA5, 0x65, 0xA2, 0x76} // 2774901366

	res = Integer64ToBer(-9223372036854775808)
	if len(res) != len(min) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != min[i] {
			t.Fail()
		}
	}
	res = Integer64ToBer(9223372036854775807)
	if len(res) != len(max) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != max[i] {
			t.Fail()
		}
	}
	res = Integer64ToBer(0)
	if len(res) != len(zero) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != zero[i] {
			t.Fail()
		}
	}
	res = Integer64ToBer(-1)
	if len(res) != len(minus1) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != minus1[i] {
			t.Fail()
		}
	}
	res = Integer64ToBer(1)
	if len(res) != len(one) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != one[i] {
			t.Fail()
		}
	}
	res = Integer64ToBer(-252)
	if len(res) != len(vr1) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != vr1[i] {
			t.Fail()
		}
	}
	res = Integer64ToBer(-43154562)
	if len(res) != len(vr2) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != vr2[i] {
			t.Fail()
		}
	}
	res = Integer64ToBer(2774901366)
	if len(res) != len(vr3) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != vr3[i] {
			t.Fail()
		}
	}
}

func TestMakeBERLen(t *testing.T) {
	var res []byte
	max := []byte{0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} // 18446744073709551615
	min := []byte{0x00}
	ord := []byte{0x88, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08} // 72623859790382856
	x609 := []byte{0x81, 0xC9}                                          // example value in X.609 document -> 201
	res = MakeBERLen(18446744073709551615)
	if len(res) != len(max) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != max[i] {
			t.Fail()
		}
	}
	res = MakeBERLen(0)
	if len(res) != len(min) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != min[i] {
			t.Fail()
		}
	}
	res = MakeBERLen(72623859790382856)
	if len(res) != len(ord) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != ord[i] {
			t.Fail()
		}
	}
	res = MakeBERLen(201)
	if len(res) != len(x609) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != x609[i] {
			t.Fail()
		}
	}
}

func TestOctetstringC(t *testing.T) {
	var b BerVal

	b.OctetstringC()

	if 0x24 != b[0] && 0x80 != b[1] {
		t.Fail()
	}
}

func TestOctetstringP(t *testing.T) {
	var b BerVal
	val := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}

	b.OctetstringP(val)

	if 0x04 != b[0] && 0x81 != b[1] && 0xC0 != b[2] {
		t.Fail()
	}

	for i := 0; i < len(val); i++ {
		if b[i+3] != val[i] {
			t.Fail()
		}
	}
}

func TestMakeBigTag(t *testing.T) {
	var res []byte
	v1 := []byte{0x1F, 0x36}                   // 54
	v2 := []byte{0x1F, 0x81, 0x1A}             // 154
	v3 := []byte{0x1F, 0x81, 0xB7, 0x8D, 0x40} //3000000

	res = MakeBigTag(54)
	if len(res) != len(v1) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != v1[i] {
			t.Fail()
		}
	}
	res = MakeBigTag(154)
	if len(res) != len(v2) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != v2[i] {
			t.Fail()
		}
	}
	res = MakeBigTag(3000000)
	if len(res) != len(v3) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != v3[i] {
			t.Fail()
		}
	}
}
<commit_msg>X.609 -> X.690<commit_after>package ber

import "testing"

func TestNull(t *testing.T) {
	var bval BerVal

	bval.Null()

	if 0x05 != bval[0] && 0x00 != bval[1] {
		t.Fail()
	}
}

func TestBool(t *testing.T) {
	var b BerVal

	b.Bool(true)
	if 0x01 != b[0] && 0xFF != b[1] {
		t.Fail()
	}
	b.Bool(false)
	if 0x01 != b[0] && 0x00 != b[1] {
		t.Fail()
	}
}

func TestEOC(t *testing.T) {
	var b BerVal

	b.EOC()

	if 0x00 != b[0] && 0x00 != b[1] {
		t.Fail()
	}
}

func TestSet(t *testing.T) {
	var b BerVal

	b.Set()

	if 0x31 != b[0] && 0x80 != b[1] {
		t.Fail()
	}
}

func TestSequence(t *testing.T) {
	var b BerVal

	b.Sequence()

	if 0x30 != b[0] && 0x80 != b[1] {
		t.Fail()
	}
}

func TestInteger64ToBer(t *testing.T) {
	var res []byte
	min := []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
	max := []byte{0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
	zero := []byte{0x00}
	minus1 := []byte{0xFF}
	one := []byte{0x01}
	vr1 := []byte{0xFF, 0x04}                   // -252
	vr2 := []byte{0xFD, 0x6D, 0x83, 0x7E}       // -43154562
	vr3 := []byte{0x00, 0xA5, 0x65, 0xA2, 0x76} // 2774901366

	res = Integer64ToBer(-9223372036854775808)
	if len(res) != len(min) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != min[i] {
			t.Fail()
		}
	}
	res = Integer64ToBer(9223372036854775807)
	if len(res) != len(max) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != max[i] {
			t.Fail()
		}
	}
	res = Integer64ToBer(0)
	if len(res) != len(zero) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != zero[i] {
			t.Fail()
		}
	}
	res = Integer64ToBer(-1)
	if len(res) != len(minus1) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != minus1[i] {
			t.Fail()
		}
	}
	res = Integer64ToBer(1)
	if len(res) != len(one) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != one[i] {
			t.Fail()
		}
	}
	res = Integer64ToBer(-252)
	if len(res) != len(vr1) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != vr1[i] {
			t.Fail()
		}
	}
	res = Integer64ToBer(-43154562)
	if len(res) != len(vr2) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != vr2[i] {
			t.Fail()
		}
	}
	res = Integer64ToBer(2774901366)
	if len(res) != len(vr3) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != vr3[i] {
			t.Fail()
		}
	}
}

func TestMakeBERLen(t *testing.T) {
	var res []byte
	max := []byte{0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} // 18446744073709551615
	min := []byte{0x00}
	ord := []byte{0x88, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08} // 72623859790382856
	x690 := []byte{0x81, 0xC9}                                          // example value in X.690 document -> 201
	res = MakeBERLen(18446744073709551615)
	if len(res) != len(max) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != max[i] {
			t.Fail()
		}
	}
	res = MakeBERLen(0)
	if len(res) != len(min) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != min[i] {
			t.Fail()
		}
	}
	res = MakeBERLen(72623859790382856)
	if len(res) != len(ord) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != ord[i] {
			t.Fail()
		}
	}
	res = MakeBERLen(201)
	if len(res) != len(x690) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != x690[i] {
			t.Fail()
		}
	}
}

func TestOctetstringC(t *testing.T) {
	var b BerVal

	b.OctetstringC()

	if 0x24 != b[0] && 0x80 != b[1] {
		t.Fail()
	}
}

func TestOctetstringP(t *testing.T) {
	var b BerVal
	val := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
		0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}

	b.OctetstringP(val)

	if 0x04 != b[0] && 0x81 != b[1] && 0xC0 != b[2] {
		t.Fail()
	}

	for i := 0; i < len(val); i++ {
		if b[i+3] != val[i] {
			t.Fail()
		}
	}
}

func TestMakeBigTag(t *testing.T) {
	var res []byte
	v1 := []byte{0x1F, 0x36}                   // 54
	v2 := []byte{0x1F, 0x81, 0x1A}             // 154
	v3 := []byte{0x1F, 0x81, 0xB7, 0x8D, 0x40} //3000000

	res = MakeBigTag(54)
	if len(res) != len(v1) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != v1[i] {
			t.Fail()
		}
	}
	res = MakeBigTag(154)
	if len(res) != len(v2) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != v2[i] {
			t.Fail()
		}
	}
	res = MakeBigTag(3000000)
	if len(res) != len(v3) {
		t.Fail()
	}
	for i := 0; i < len(res); i++ {
		if res[i] != v3[i] {
			t.Fail()
		}
	}
}
<|endoftext|>


<commit_before>package gofeed_test

import (
	"fmt"
	"io/ioutil"
	"testing"

	"github.com/mmcdole/gofeed"
	"github.com/stretchr/testify/assert"
)

func TestDetectFeedType(t *testing.T) {
	var feedTypeTests = []struct {
		file     string
		expected gofeed.FeedType
	}{
		{"feedtype_atom03.xml", gofeed.FeedTypeAtom},
		{"feedtype_atom10.xml", gofeed.FeedTypeAtom},
		{"feedtype_rss.xml", gofeed.FeedTypeRSS},
		{"feedtype_rdf.xml", gofeed.FeedTypeRSS},
		{"feedtype_unknown.xml", gofeed.FeedTypeUnknown},
	}

	for _, test := range feedTypeTests {
		fmt.Printf("Testing %s... ", test.file)

		// Get feed content
		path := fmt.Sprintf("testdata/parser/feed/%s", test.file)
		f, _ := ioutil.ReadFile(path)

		// Get actual value
		actual := gofeed.DetectFeedType(string(f))

		if assert.Equal(t, actual, test.expected, "Feed file %s did not match expected type %d", test.file, test.expected) {
			fmt.Printf("OK\n")
		} else {
			fmt.Printf("Failed\n")
		}
	}
}

func ExampleDetectFeedType() {
	feedData := `<rss version="2.0">
<channel>
<title>Sample Feed</title>
</channel>
</rss>`
	feedType := gofeed.DetectFeedType(feedData)
	// Output: gofeed.FeedTypeRSS
}
<commit_msg>Add ParseFeedURL test<commit_after>package gofeed_test

import (
	"fmt"
	"io/ioutil"
	"testing"

	"github.com/mmcdole/gofeed"
	"github.com/stretchr/testify/assert"
)

func TestDetectFeedType(t *testing.T) {
	var feedTypeTests = []struct {
		file     string
		expected gofeed.FeedType
	}{
		{"feedtype_atom03.xml", gofeed.FeedTypeAtom},
		{"feedtype_atom10.xml", gofeed.FeedTypeAtom},
		{"feedtype_rss.xml", gofeed.FeedTypeRSS},
		{"feedtype_rdf.xml", gofeed.FeedTypeRSS},
		{"feedtype_unknown.xml", gofeed.FeedTypeUnknown},
	}

	for _, test := range feedTypeTests {
		fmt.Printf("Testing %s... ", test.file)

		// Get feed content
		path := fmt.Sprintf("testdata/parser/feed/%s", test.file)
		f, _ := ioutil.ReadFile(path)

		// Get actual value
		actual := gofeed.DetectFeedType(string(f))

		if assert.Equal(t, actual, test.expected, "Feed file %s did not match expected type %d", test.file, test.expected) {
			fmt.Printf("OK\n")
		} else {
			fmt.Printf("Failed\n")
		}
	}
}

func ExampleDetectFeedType() {
	feedData := `<rss version="2.0">
<channel>
<title>Sample Feed</title>
</channel>
</rss>`
	feedType := gofeed.DetectFeedType(feedData)
	if feedType == gofeed.FeedTypeRSS {
		fmt.Println("RSS")
	}
}

func ExampleFeedParser_ParseFeedURL() {
	fp := gofeed.NewFeedParser()
	feed, err := fp.ParseFeedURL("http://feeds.twit.tv/twit.xml")
	if err != nil {
		panic(err)
	}
	fmt.Println(feed.Title)
}

func ExampleFeedParser_ParseFeed() {
	feedData := `<rss version="2.0">
<channel>
<title>Sample Feed</title>
</channel>
</rss>`
	fp := gofeed.NewFeedParser()
	feed, err := fp.ParseFeed(feedData)
	if err != nil {
		panic(err)
	}
	fmt.Println(feed.Title)
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License 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 webhook

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"go.uber.org/zap"
	admissionv1beta1 "k8s.io/api/admission/v1beta1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"knative.dev/pkg/logging"
	"knative.dev/pkg/logging/logkey"
)

// AdmissionController provides the interface for different admission controllers
type AdmissionController interface {
	// Path returns the path that this particular admission controller serves on.
	Path() string

	// Admit is the callback which is invoked when an HTTPS request comes in on Path().
	Admit(context.Context, *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse
}

// StatelessAdmissionController is implemented by AdmissionControllers where Admit may be safely
// called before informers have finished syncing.  This is implemented by inlining
// StatelessAdmissionImpl in your Go type.
type StatelessAdmissionController interface {
	// A silly name that should avoid collisions.
	ThisTypeDoesNotDependOnInformerState()
}

// MakeErrorStatus creates an 'BadRequest' error AdmissionResponse
func MakeErrorStatus(reason string, args ...interface{}) *admissionv1beta1.AdmissionResponse {
	result := apierrors.NewBadRequest(fmt.Sprintf(reason, args...)).Status()
	return &admissionv1beta1.AdmissionResponse{
		Result:  &result,
		Allowed: false,
	}
}

func admissionHandler(rootLogger *zap.SugaredLogger, stats StatsReporter, c AdmissionController, synced <-chan struct{}) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if _, ok := c.(StatelessAdmissionController); ok {
			// Stateless admission controllers do not require Informers to have
			// finished syncing before Admit is called.
		} else {
			// Don't allow admission control requests through until we have been
			// notified that informers have been synchronized.
			<-synced
		}

		var ttStart = time.Now()
		logger := rootLogger
		logger.Infof("Webhook ServeHTTP request=%#v", r)

		var review admissionv1beta1.AdmissionReview
		if err := json.NewDecoder(r.Body).Decode(&review); err != nil {
			http.Error(w, fmt.Sprintf("could not decode body: %v", err), http.StatusBadRequest)
			return
		}

		logger = logger.With(
			zap.String(logkey.Kind, review.Request.Kind.String()),
			zap.String(logkey.Namespace, review.Request.Namespace),
			zap.String(logkey.Name, review.Request.Name),
			zap.String(logkey.Operation, string(review.Request.Operation)),
			zap.String(logkey.Resource, review.Request.Resource.String()),
			zap.String(logkey.SubResource, review.Request.SubResource),
			zap.String(logkey.UserInfo, fmt.Sprint(review.Request.UserInfo)))

		ctx := logging.WithLogger(r.Context(), logger)

		var response admissionv1beta1.AdmissionReview
		reviewResponse := c.Admit(ctx, review.Request)
		logger.Infof("AdmissionReview for %#v: %s/%s response=%#v",
			review.Request.Kind, review.Request.Namespace, review.Request.Name, reviewResponse)

		if !reviewResponse.Allowed || reviewResponse.PatchType != nil || response.Response == nil {
			response.Response = reviewResponse
		}
		response.Response.UID = review.Request.UID

		if err := json.NewEncoder(w).Encode(response); err != nil {
			http.Error(w, fmt.Sprintf("could not encode response: %v", err), http.StatusInternalServerError)
			return
		}

		if stats != nil {
			// Only report valid requests
			stats.ReportRequest(review.Request, response.Response, time.Since(ttStart))
		}
	}
}

// Inline this type to implement StatelessAdmissionController.
type StatelessAdmissionImpl struct{}

func (sai StatelessAdmissionImpl) ThisTypeDoesNotDependOnInformerState() {}
<commit_msg>Manually print all elements of response object (#1241)<commit_after>/*
Copyright 2020 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License 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 webhook

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"go.uber.org/zap"
	admissionv1beta1 "k8s.io/api/admission/v1beta1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"knative.dev/pkg/logging"
	"knative.dev/pkg/logging/logkey"
)

// AdmissionController provides the interface for different admission controllers
type AdmissionController interface {
	// Path returns the path that this particular admission controller serves on.
	Path() string

	// Admit is the callback which is invoked when an HTTPS request comes in on Path().
	Admit(context.Context, *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse
}

// StatelessAdmissionController is implemented by AdmissionControllers where Admit may be safely
// called before informers have finished syncing.  This is implemented by inlining
// StatelessAdmissionImpl in your Go type.
type StatelessAdmissionController interface {
	// A silly name that should avoid collisions.
	ThisTypeDoesNotDependOnInformerState()
}

// MakeErrorStatus creates an 'BadRequest' error AdmissionResponse
func MakeErrorStatus(reason string, args ...interface{}) *admissionv1beta1.AdmissionResponse {
	result := apierrors.NewBadRequest(fmt.Sprintf(reason, args...)).Status()
	return &admissionv1beta1.AdmissionResponse{
		Result:  &result,
		Allowed: false,
	}
}

func admissionHandler(rootLogger *zap.SugaredLogger, stats StatsReporter, c AdmissionController, synced <-chan struct{}) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if _, ok := c.(StatelessAdmissionController); ok {
			// Stateless admission controllers do not require Informers to have
			// finished syncing before Admit is called.
		} else {
			// Don't allow admission control requests through until we have been
			// notified that informers have been synchronized.
			<-synced
		}

		var ttStart = time.Now()
		logger := rootLogger
		logger.Infof("Webhook ServeHTTP request=%#v", r)

		var review admissionv1beta1.AdmissionReview
		if err := json.NewDecoder(r.Body).Decode(&review); err != nil {
			http.Error(w, fmt.Sprintf("could not decode body: %v", err), http.StatusBadRequest)
			return
		}

		logger = logger.With(
			zap.String(logkey.Kind, review.Request.Kind.String()),
			zap.String(logkey.Namespace, review.Request.Namespace),
			zap.String(logkey.Name, review.Request.Name),
			zap.String(logkey.Operation, string(review.Request.Operation)),
			zap.String(logkey.Resource, review.Request.Resource.String()),
			zap.String(logkey.SubResource, review.Request.SubResource),
			zap.String(logkey.UserInfo, fmt.Sprint(review.Request.UserInfo)))

		ctx := logging.WithLogger(r.Context(), logger)

		var response admissionv1beta1.AdmissionReview
		reviewResponse := c.Admit(ctx, review.Request)
		var patchType string
		if reviewResponse.PatchType != nil {
			patchType = string(*reviewResponse.PatchType)
		}

		logger.Infof("AdmissionReview for %#v: %s/%s response={ UID: %#v, Allowed: %t, Status: %#v, Patch: %s, PatchType: %s, AuditAnnotations: %#v}",
			review.Request.Kind, review.Request.Namespace, review.Request.Name,
			reviewResponse.UID, reviewResponse.Allowed, reviewResponse.Result, string(reviewResponse.Patch), patchType, reviewResponse.AuditAnnotations)

		if !reviewResponse.Allowed || reviewResponse.PatchType != nil || response.Response == nil {
			response.Response = reviewResponse
		}
		response.Response.UID = review.Request.UID

		if err := json.NewEncoder(w).Encode(response); err != nil {
			http.Error(w, fmt.Sprintf("could not encode response: %v", err), http.StatusInternalServerError)
			return
		}

		if stats != nil {
			// Only report valid requests
			stats.ReportRequest(review.Request, response.Response, time.Since(ttStart))
		}
	}
}

// Inline this type to implement StatelessAdmissionController.
type StatelessAdmissionImpl struct{}

func (sai StatelessAdmissionImpl) ThisTypeDoesNotDependOnInformerState() {}
<|endoftext|>


<commit_before>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ipv4_test

import (
	"code.google.com/p/go.net/ipv4"
	"errors"
	"flag"
)

var testExternal = flag.Bool("external", true, "allow use of external networks during long test")

// icmpMessage represents an ICMP message.
type icmpMessage struct {
	Type     ipv4.ICMPType   // type
	Code     int             // code
	Checksum int             // checksum
	Body     icmpMessageBody // body
}

// icmpMessageBody represents an ICMP message body.
type icmpMessageBody interface {
	Len() int
	Marshal() ([]byte, error)
}

// Marshal returns the binary enconding of the ICMP echo request or
// reply message m.
func (m *icmpMessage) Marshal() ([]byte, error) {
	b := []byte{byte(m.Type), byte(m.Code), 0, 0}
	if m.Body != nil && m.Body.Len() != 0 {
		mb, err := m.Body.Marshal()
		if err != nil {
			return nil, err
		}
		b = append(b, mb...)
	}
	csumcv := len(b) - 1 // checksum coverage
	s := uint32(0)
	for i := 0; i < csumcv; i += 2 {
		s += uint32(b[i+1])<<8 | uint32(b[i])
	}
	if csumcv&1 == 0 {
		s += uint32(b[csumcv])
	}
	s = s>>16 + s&0xffff
	s = s + s>>16
	// Place checksum back in header; using ^= avoids the
	// assumption the checksum bytes are zero.
	b[2] ^= byte(^s & 0xff)
	b[3] ^= byte(^s >> 8)
	return b, nil
}

// parseICMPMessage parses b as an ICMP message.
func parseICMPMessage(b []byte) (*icmpMessage, error) {
	msglen := len(b)
	if msglen < 4 {
		return nil, errors.New("message too short")
	}
	m := &icmpMessage{Type: ipv4.ICMPType(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])}
	if msglen > 4 {
		var err error
		switch m.Type {
		case ipv4.ICMPTypeEcho, ipv4.ICMPTypeEchoReply:
			m.Body, err = parseICMPEcho(b[4:])
			if err != nil {
				return nil, err
			}
		}
	}
	return m, nil
}

// imcpEcho represenets an ICMP echo request or reply message body.
type icmpEcho struct {
	ID   int    // identifier
	Seq  int    // sequence number
	Data []byte // data
}

func (p *icmpEcho) Len() int {
	if p == nil {
		return 0
	}
	return 4 + len(p.Data)
}

// Marshal returns the binary enconding of the ICMP echo request or
// reply message body p.
func (p *icmpEcho) Marshal() ([]byte, error) {
	b := make([]byte, 4+len(p.Data))
	b[0], b[1] = byte(p.ID>>8), byte(p.ID&0xff)
	b[2], b[3] = byte(p.Seq>>8), byte(p.Seq&0xff)
	copy(b[4:], p.Data)
	return b, nil
}

// parseICMPEcho parses b as an ICMP echo request or reply message
// body.
func parseICMPEcho(b []byte) (*icmpEcho, error) {
	bodylen := len(b)
	p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])}
	if bodylen > 4 {
		p.Data = make([]byte, bodylen-4)
		copy(p.Data, b[4:])
	}
	return p, nil
}
<commit_msg>go.net/ipv4: remove unnecessary bit masking<commit_after>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ipv4_test

import (
	"code.google.com/p/go.net/ipv4"
	"errors"
	"flag"
)

var testExternal = flag.Bool("external", true, "allow use of external networks during long test")

// icmpMessage represents an ICMP message.
type icmpMessage struct {
	Type     ipv4.ICMPType   // type
	Code     int             // code
	Checksum int             // checksum
	Body     icmpMessageBody // body
}

// icmpMessageBody represents an ICMP message body.
type icmpMessageBody interface {
	Len() int
	Marshal() ([]byte, error)
}

// Marshal returns the binary enconding of the ICMP echo request or
// reply message m.
func (m *icmpMessage) Marshal() ([]byte, error) {
	b := []byte{byte(m.Type), byte(m.Code), 0, 0}
	if m.Body != nil && m.Body.Len() != 0 {
		mb, err := m.Body.Marshal()
		if err != nil {
			return nil, err
		}
		b = append(b, mb...)
	}
	csumcv := len(b) - 1 // checksum coverage
	s := uint32(0)
	for i := 0; i < csumcv; i += 2 {
		s += uint32(b[i+1])<<8 | uint32(b[i])
	}
	if csumcv&1 == 0 {
		s += uint32(b[csumcv])
	}
	s = s>>16 + s&0xffff
	s = s + s>>16
	// Place checksum back in header; using ^= avoids the
	// assumption the checksum bytes are zero.
	b[2] ^= byte(^s)
	b[3] ^= byte(^s >> 8)
	return b, nil
}

// parseICMPMessage parses b as an ICMP message.
func parseICMPMessage(b []byte) (*icmpMessage, error) {
	msglen := len(b)
	if msglen < 4 {
		return nil, errors.New("message too short")
	}
	m := &icmpMessage{Type: ipv4.ICMPType(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])}
	if msglen > 4 {
		var err error
		switch m.Type {
		case ipv4.ICMPTypeEcho, ipv4.ICMPTypeEchoReply:
			m.Body, err = parseICMPEcho(b[4:])
			if err != nil {
				return nil, err
			}
		}
	}
	return m, nil
}

// imcpEcho represenets an ICMP echo request or reply message body.
type icmpEcho struct {
	ID   int    // identifier
	Seq  int    // sequence number
	Data []byte // data
}

func (p *icmpEcho) Len() int {
	if p == nil {
		return 0
	}
	return 4 + len(p.Data)
}

// Marshal returns the binary enconding of the ICMP echo request or
// reply message body p.
func (p *icmpEcho) Marshal() ([]byte, error) {
	b := make([]byte, 4+len(p.Data))
	b[0], b[1] = byte(p.ID>>8), byte(p.ID)
	b[2], b[3] = byte(p.Seq>>8), byte(p.Seq)
	copy(b[4:], p.Data)
	return b, nil
}

// parseICMPEcho parses b as an ICMP echo request or reply message
// body.
func parseICMPEcho(b []byte) (*icmpEcho, error) {
	bodylen := len(b)
	p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])}
	if bodylen > 4 {
		p.Data = make([]byte, bodylen-4)
		copy(p.Data, b[4:])
	}
	return p, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License 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.

//go:generate protoc --proto_path=model/l3 --gogo_out=model/l3 model/l3/l3.proto
//go:generate binapi-generator --input-file=/usr/share/vpp/api/ip.api.json --output-dir=bin_api

// Package l3plugin implements the L3 plugin that handles L3 FIBs.
package l3plugin

import (
	"fmt"
	"strconv"

	govppapi "git.fd.io/govpp.git/api"
	"github.com/ligato/cn-infra/logging"
	"github.com/ligato/cn-infra/logging/measure"
	"github.com/ligato/cn-infra/utils/safeclose"
	"github.com/ligato/vpp-agent/idxvpp"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/ifaceidx"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l3plugin/bin_api/ip"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l3plugin/model/l3"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l3plugin/vppcalls"
	"github.com/ligato/vpp-agent/plugins/govppmux"
	"github.com/ligato/vpp-agent/errors"
	"github.com/gogo/protobuf/test/indeximport-issue72/index"
	"github.com/prometheus/common/route"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l3plugin/l3idx"
)

// RouteConfigurator runs in the background in its own goroutine where it watches for any changes
// in the configuration of L3 routes as modelled by the proto file "../model/l3/l3.proto" and stored
// in ETCD under the key "/vnf-agent/{vnf-agent}/vpp/config/v1routes". Updates received from the northbound API
// are compared with the VPP run-time configuration and differences are applied through the VPP binary API.
type RouteConfigurator struct {
	Log              logging.Logger
	GoVppmux         govppmux.API
	RouteIndexes     idxvpp.NameToIdxRW
	RouteIndexSeq    uint32
	SwIfIndexes      ifaceidx.SwIfIndex
	RouteCachedIndex l3idx.RouteIndexRW
	vppChan          *govppapi.Channel
	Stopwatch        *measure.Stopwatch // timer used to measure and store time

}

// Init members (channels...) and start go routines.
func (plugin *RouteConfigurator) Init() (err error) {
	plugin.Log.Debug("Initializing L3 plugin")

	// Init VPP API channel.
	plugin.vppChan, err = plugin.GoVppmux.NewAPIChannel()
	if err != nil {
		return err
	}

	err = plugin.checkMsgCompatibility()
	if err != nil {
		return err
	}

	return nil
}

// ConfigureRoute processes the NB config and propagates it to bin api calls.
func (plugin *RouteConfigurator) ConfigureRoute(config *l3.StaticRoutes_Route, vrfFromKey string) error {
	plugin.Log.Infof("Creating new route %v -> %v", config.DstIpAddr, config.NextHopAddr)
	// Validate VRF index from key and it's value in data.
	if err := plugin.validateVrfFromKey(config, vrfFromKey); err != nil {
		return err
	}

	outgoingIfName := config.OutgoingInterface
	routeId := routeIdentifier(config.VrfId, config.DstIpAddr, config.NextHopAddr)

	if outgoingIfName != "" {
		_, _, exists := plugin.SwIfIndexes.LookupIdx(outgoingIfName)
		if !exists {
			plugin.RouteCachedIndex.RegisterName(routeId, plugin.RouteIndexSeq, config)
			plugin.RouteIndexSeq++
			plugin.Log.Debugf("Route %v registered to cache", routeId)
		}
	}

	_,_,routeExists := plugin.RouteIndexes.LookupIdx(routeId)
	if !routeExists {
		plugin.RouteIndexes.RegisterName(routeId, plugin.RouteIndexSeq, nil)
		plugin.RouteIndexSeq++
		plugin.Log.Infof("Route %v registered", routeId)
	}

	// Transform route data.
	route, err := TransformRoute(config, plugin.SwIfIndexes, plugin.Log)
	if err != nil {
		return err
	}

	plugin.Log.Debugf("adding route: %+v", route)
	// Create and register new route.
	if route != nil {
		err := vppcalls.VppAddRoute(route, plugin.vppChan, measure.GetTimeLog(ip.IPAddDelRoute{}, plugin.Stopwatch))
		if err != nil {
			return err
		}
	}

	return nil
}

// ModifyRoute processes the NB config and propagates it to bin api calls.
func (plugin *RouteConfigurator) ModifyRoute(newConfig *l3.StaticRoutes_Route, oldConfig *l3.StaticRoutes_Route, vrfFromKey string) error {
	plugin.Log.Infof("Modifying route %v -> %v", oldConfig.DstIpAddr, oldConfig.NextHopAddr)

	outgoingIfName := newConfig.OutgoingInterface
	if outgoingIfName != "" {
		_, _, existsNewOutgoing := plugin.SwIfIndexes.LookupIdx(outgoingIfName)
		routeId := routeIdentifier(oldConfig.VrfId, oldConfig.DstIpAddr, oldConfig.NextHopAddr)
		if existsNewOutgoing {
			plugin.Log.Debugf("Route %s unregistered from cache.", routeId)
			plugin.RouteCachedIndex.UnregisterName(routeId)
		} else {
			routeIdx,_, isRouteCached := plugin.RouteCachedIndex.LookupIdx(routeId)
			if isRouteCached {
				plugin.RouteCachedIndex.RegisterName(routeId, routeIdx, newConfig)
			} else {
				plugin.RouteCachedIndex.RegisterName(routeId, plugin.RouteIndexSeq, newConfig)
				plugin.RouteIndexSeq++
			}
		}
	}

	var err error
	err = plugin.deleteOldRoute(oldConfig, vrfFromKey)
	if err != nil {
		return err
	}

	err = plugin.addNewRoute(newConfig, vrfFromKey)
	if err != nil {
		return err
	}

	return nil
}

func (plugin *RouteConfigurator) deleteOldRoute(oldConfig *l3.StaticRoutes_Route, vrfFromKey string) error {
	// Transform old route data.
	oldRoute, err := TransformRoute(oldConfig, plugin.SwIfIndexes, plugin.Log)
	if err != nil {
		return err
	}

	// Validate old cachedRoute data Vrf.
	if err := plugin.validateVrfFromKey(oldConfig, vrfFromKey); err != nil {
		return err
	}
	// Remove and unregister old route.
	err = vppcalls.VppDelRoute(oldRoute, plugin.vppChan, measure.GetTimeLog(ip.IPAddDelRoute{}, plugin.Stopwatch))
	if err != nil {
		return err
	}
	oldRouteIdentifier := routeIdentifier(oldRoute.VrfID, oldRoute.DstAddr.String(), oldRoute.NextHopAddr.String())
	_, _, found := plugin.RouteIndexes.UnregisterName(oldRouteIdentifier)
	if found {
		plugin.Log.Infof("Old route %v unregistered", oldRouteIdentifier)
	} else {
		plugin.Log.Warnf("Unregister failed, old route %v not found", oldRouteIdentifier)
	}
	return nil
}

func (plugin *RouteConfigurator) addNewRoute(newConfig *l3.StaticRoutes_Route, vrfFromKey string) error {
	// Validate new route data Vrf.
	if err := plugin.validateVrfFromKey(newConfig, vrfFromKey); err != nil {
		return err
	}
	// Transform new route data.
	newRoute, err := TransformRoute(newConfig, plugin.SwIfIndexes, plugin.Log)
	if err != nil {
		return err
	}
	// Create and register new route.
	err = vppcalls.VppAddRoute(newRoute, plugin.vppChan, measure.GetTimeLog(ip.IPAddDelRoute{}, plugin.Stopwatch))
	if err != nil {
		return err
	}
	newRouteIdentifier := routeIdentifier(newConfig.VrfId, newConfig.DstIpAddr, newConfig.NextHopAddr)
	plugin.RouteIndexes.RegisterName(newRouteIdentifier, plugin.RouteIndexSeq, nil)
	plugin.RouteIndexSeq++
	plugin.Log.Infof("New route %v registered", newRouteIdentifier)
	return nil
}

// DeleteRoute processes the NB config and propagates it to bin api calls.
func (plugin *RouteConfigurator) DeleteRoute(config *l3.StaticRoutes_Route, vrfFromKey string) (wasError error) {
	plugin.Log.Infof("Removing route %v -> %v", config.DstIpAddr, config.NextHopAddr)

	routeIdentifier := routeIdentifier(config.VrfId, config.DstIpAddr, config.NextHopAddr)
	_,_,routeExists := plugin.RouteCachedIndex.UnregisterName(routeIdentifier)
	if !routeExists {
		// Validate VRF index from key and it's value in data.
		if err := plugin.validateVrfFromKey(config, vrfFromKey); err != nil {
			return err
		}
		// Transform route data.
		route, err := TransformRoute(config, plugin.SwIfIndexes, plugin.Log)
		if err != nil {
			return err
		}
		if route == nil {
			return nil
		}
		plugin.Log.Debugf("deleting route: %+v", route)
		// Remove and unregister route.
		err = vppcalls.VppDelRoute(route, plugin.vppChan, measure.GetTimeLog(ip.IPAddDelRoute{}, plugin.Stopwatch))
		if err != nil {
			return err
		}
	}

	_, _, found := plugin.RouteIndexes.UnregisterName(routeIdentifier)
	if found {
		plugin.Log.Infof("Route %v unregistered", routeIdentifier)
	} else {
		plugin.Log.Warnf("Unregister failed, route %v not found", routeIdentifier)
	}

	return nil
}

func (plugin *RouteConfigurator) validateVrfFromKey(config *l3.StaticRoutes_Route, vrfFromKey string) error {
	intVrfFromKey, err := strconv.Atoi(vrfFromKey)
	if intVrfFromKey != int(config.VrfId) {
		if err != nil {
			return err
		}
		plugin.Log.Warnf("VRF index from key (%v) and from config (%v) does not match, using value from the key",
			intVrfFromKey, config.VrfId)
		config.VrfId = uint32(intVrfFromKey)
	}
	return nil
}

func (plugin *RouteConfigurator) checkMsgCompatibility() error {
	msgs := []govppapi.Message{
		&ip.IPAddDelRoute{},
		&ip.IPAddDelRouteReply{},
		&ip.IPFibDump{},
		&ip.IPFibDetails{},
		&ip.IP6FibDump{},
		&ip.IP6FibDetails{},
	}
	err := plugin.vppChan.CheckMessageCompatibility(msgs...)
	if err != nil {
		plugin.Log.Error(err)
	}
	return err
}

// Close GOVPP channel.
func (plugin *RouteConfigurator) Close() error {
	return safeclose.Close(plugin.vppChan)
}

// Create unique identifier which serves as a name in name-to-index mapping.
func routeIdentifier(vrf uint32, destination string, nextHop string) string {
	return fmt.Sprintf("vrf%v-%v-%v", vrf, destination, nextHop)
}

//ResolveCreatedInterface is responsible for reconfiguring cached routes and then from removing
//them from route cache
func (plugin *RouteConfigurator) ResolveCreatedInterface(ifName string, swIdx uint32) {
	routesWithIndex := plugin.RouteCachedIndex.LookupRouteAndIdByOutgoingIfc(ifName)
	for _, routeWithIndex := range routesWithIndex {
		route := routeWithIndex.Route
		plugin.Log.WithFields(
				logging.Fields{
				"interface ifName":         ifName,
				"interface software index": swIdx,
				"vrf":                      route.VrfId,
				"destination ip":           route.DstIpAddr}).
			Debug("Remove routes from cache - outgoing interface was added.")
		plugin.ConfigureRoute(route, strconv.FormatUint(uint64(route.VrfId), 10))
		plugin.RouteCachedIndex.UnregisterName(routeWithIndex.RouteID)
	}
}

//ResolveDeletedInterface is responsible for moving routes of deleted interface to cache
func (plugin *RouteConfigurator) ResolveDeletedInterface(ifName string, swIdx uint32) {
	routesWithIndex := plugin.RouteCachedIndex.LookupRouteAndIdByOutgoingIfc(ifName)
	for _, routeWithIndex := range routesWithIndex {
		route := routeWithIndex.Route
		plugin.Log.WithFields(
			logging.Fields{
				"interface ifName":         ifName,
				"interface software index": swIdx,
				"vrf":                      route.VrfId,
				"destination ip":           route.DstIpAddr}).
			Debug("Add routes to cache - outgoing interface was deleted.")
		plugin.DeleteRoute(route, strconv.FormatUint(uint64(route.VrfId), 10))
		plugin.RouteCachedIndex.RegisterName(routeWithIndex.RouteID, plugin.RouteIndexSeq, route)
		plugin.RouteIndexSeq++
	}
}<commit_msg>Ensure that VPP routes can be configured before interfaces. - removing wrong imports from route_config.go<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License 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.

//go:generate protoc --proto_path=model/l3 --gogo_out=model/l3 model/l3/l3.proto
//go:generate binapi-generator --input-file=/usr/share/vpp/api/ip.api.json --output-dir=bin_api

// Package l3plugin implements the L3 plugin that handles L3 FIBs.
package l3plugin

import (
	"fmt"
	"strconv"

	govppapi "git.fd.io/govpp.git/api"
	"github.com/ligato/cn-infra/logging"
	"github.com/ligato/cn-infra/logging/measure"
	"github.com/ligato/cn-infra/utils/safeclose"
	"github.com/ligato/vpp-agent/idxvpp"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/ifaceidx"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l3plugin/bin_api/ip"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l3plugin/model/l3"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l3plugin/vppcalls"
	"github.com/ligato/vpp-agent/plugins/govppmux"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l3plugin/l3idx"
)

// RouteConfigurator runs in the background in its own goroutine where it watches for any changes
// in the configuration of L3 routes as modelled by the proto file "../model/l3/l3.proto" and stored
// in ETCD under the key "/vnf-agent/{vnf-agent}/vpp/config/v1routes". Updates received from the northbound API
// are compared with the VPP run-time configuration and differences are applied through the VPP binary API.
type RouteConfigurator struct {
	Log              logging.Logger
	GoVppmux         govppmux.API
	RouteIndexes     idxvpp.NameToIdxRW
	RouteIndexSeq    uint32
	SwIfIndexes      ifaceidx.SwIfIndex
	RouteCachedIndex l3idx.RouteIndexRW
	vppChan          *govppapi.Channel
	Stopwatch        *measure.Stopwatch // timer used to measure and store time

}

// Init members (channels...) and start go routines.
func (plugin *RouteConfigurator) Init() (err error) {
	plugin.Log.Debug("Initializing L3 plugin")

	// Init VPP API channel.
	plugin.vppChan, err = plugin.GoVppmux.NewAPIChannel()
	if err != nil {
		return err
	}

	err = plugin.checkMsgCompatibility()
	if err != nil {
		return err
	}

	return nil
}

// ConfigureRoute processes the NB config and propagates it to bin api calls.
func (plugin *RouteConfigurator) ConfigureRoute(config *l3.StaticRoutes_Route, vrfFromKey string) error {
	plugin.Log.Infof("Creating new route %v -> %v", config.DstIpAddr, config.NextHopAddr)
	// Validate VRF index from key and it's value in data.
	if err := plugin.validateVrfFromKey(config, vrfFromKey); err != nil {
		return err
	}

	outgoingIfName := config.OutgoingInterface
	routeId := routeIdentifier(config.VrfId, config.DstIpAddr, config.NextHopAddr)

	if outgoingIfName != "" {
		_, _, exists := plugin.SwIfIndexes.LookupIdx(outgoingIfName)
		if !exists {
			plugin.RouteCachedIndex.RegisterName(routeId, plugin.RouteIndexSeq, config)
			plugin.RouteIndexSeq++
			plugin.Log.Debugf("Route %v registered to cache", routeId)
		}
	}

	_,_,routeExists := plugin.RouteIndexes.LookupIdx(routeId)
	if !routeExists {
		plugin.RouteIndexes.RegisterName(routeId, plugin.RouteIndexSeq, nil)
		plugin.RouteIndexSeq++
		plugin.Log.Infof("Route %v registered", routeId)
	}

	// Transform route data.
	route, err := TransformRoute(config, plugin.SwIfIndexes, plugin.Log)
	if err != nil {
		return err
	}

	plugin.Log.Debugf("adding route: %+v", route)
	// Create and register new route.
	if route != nil {
		err := vppcalls.VppAddRoute(route, plugin.vppChan, measure.GetTimeLog(ip.IPAddDelRoute{}, plugin.Stopwatch))
		if err != nil {
			return err
		}
	}

	return nil
}

// ModifyRoute processes the NB config and propagates it to bin api calls.
func (plugin *RouteConfigurator) ModifyRoute(newConfig *l3.StaticRoutes_Route, oldConfig *l3.StaticRoutes_Route, vrfFromKey string) error {
	plugin.Log.Infof("Modifying route %v -> %v", oldConfig.DstIpAddr, oldConfig.NextHopAddr)

	outgoingIfName := newConfig.OutgoingInterface
	if outgoingIfName != "" {
		_, _, existsNewOutgoing := plugin.SwIfIndexes.LookupIdx(outgoingIfName)
		routeId := routeIdentifier(oldConfig.VrfId, oldConfig.DstIpAddr, oldConfig.NextHopAddr)
		if existsNewOutgoing {
			plugin.Log.Debugf("Route %s unregistered from cache.", routeId)
			plugin.RouteCachedIndex.UnregisterName(routeId)
		} else {
			routeIdx,_, isRouteCached := plugin.RouteCachedIndex.LookupIdx(routeId)
			if isRouteCached {
				plugin.RouteCachedIndex.RegisterName(routeId, routeIdx, newConfig)
			} else {
				plugin.RouteCachedIndex.RegisterName(routeId, plugin.RouteIndexSeq, newConfig)
				plugin.RouteIndexSeq++
			}
		}
	}

	var err error
	err = plugin.deleteOldRoute(oldConfig, vrfFromKey)
	if err != nil {
		return err
	}

	err = plugin.addNewRoute(newConfig, vrfFromKey)
	if err != nil {
		return err
	}

	return nil
}

func (plugin *RouteConfigurator) deleteOldRoute(oldConfig *l3.StaticRoutes_Route, vrfFromKey string) error {
	// Transform old route data.
	oldRoute, err := TransformRoute(oldConfig, plugin.SwIfIndexes, plugin.Log)
	if err != nil {
		return err
	}

	// Validate old cachedRoute data Vrf.
	if err := plugin.validateVrfFromKey(oldConfig, vrfFromKey); err != nil {
		return err
	}
	// Remove and unregister old route.
	err = vppcalls.VppDelRoute(oldRoute, plugin.vppChan, measure.GetTimeLog(ip.IPAddDelRoute{}, plugin.Stopwatch))
	if err != nil {
		return err
	}
	oldRouteIdentifier := routeIdentifier(oldRoute.VrfID, oldRoute.DstAddr.String(), oldRoute.NextHopAddr.String())
	_, _, found := plugin.RouteIndexes.UnregisterName(oldRouteIdentifier)
	if found {
		plugin.Log.Infof("Old route %v unregistered", oldRouteIdentifier)
	} else {
		plugin.Log.Warnf("Unregister failed, old route %v not found", oldRouteIdentifier)
	}
	return nil
}

func (plugin *RouteConfigurator) addNewRoute(newConfig *l3.StaticRoutes_Route, vrfFromKey string) error {
	// Validate new route data Vrf.
	if err := plugin.validateVrfFromKey(newConfig, vrfFromKey); err != nil {
		return err
	}
	// Transform new route data.
	newRoute, err := TransformRoute(newConfig, plugin.SwIfIndexes, plugin.Log)
	if err != nil {
		return err
	}
	// Create and register new route.
	err = vppcalls.VppAddRoute(newRoute, plugin.vppChan, measure.GetTimeLog(ip.IPAddDelRoute{}, plugin.Stopwatch))
	if err != nil {
		return err
	}
	newRouteIdentifier := routeIdentifier(newConfig.VrfId, newConfig.DstIpAddr, newConfig.NextHopAddr)
	plugin.RouteIndexes.RegisterName(newRouteIdentifier, plugin.RouteIndexSeq, nil)
	plugin.RouteIndexSeq++
	plugin.Log.Infof("New route %v registered", newRouteIdentifier)
	return nil
}

// DeleteRoute processes the NB config and propagates it to bin api calls.
func (plugin *RouteConfigurator) DeleteRoute(config *l3.StaticRoutes_Route, vrfFromKey string) (wasError error) {
	plugin.Log.Infof("Removing route %v -> %v", config.DstIpAddr, config.NextHopAddr)

	routeIdentifier := routeIdentifier(config.VrfId, config.DstIpAddr, config.NextHopAddr)
	_,_,routeExists := plugin.RouteCachedIndex.UnregisterName(routeIdentifier)
	if !routeExists {
		// Validate VRF index from key and it's value in data.
		if err := plugin.validateVrfFromKey(config, vrfFromKey); err != nil {
			return err
		}
		// Transform route data.
		route, err := TransformRoute(config, plugin.SwIfIndexes, plugin.Log)
		if err != nil {
			return err
		}
		if route == nil {
			return nil
		}
		plugin.Log.Debugf("deleting route: %+v", route)
		// Remove and unregister route.
		err = vppcalls.VppDelRoute(route, plugin.vppChan, measure.GetTimeLog(ip.IPAddDelRoute{}, plugin.Stopwatch))
		if err != nil {
			return err
		}
	}

	_, _, found := plugin.RouteIndexes.UnregisterName(routeIdentifier)
	if found {
		plugin.Log.Infof("Route %v unregistered", routeIdentifier)
	} else {
		plugin.Log.Warnf("Unregister failed, route %v not found", routeIdentifier)
	}

	return nil
}

func (plugin *RouteConfigurator) validateVrfFromKey(config *l3.StaticRoutes_Route, vrfFromKey string) error {
	intVrfFromKey, err := strconv.Atoi(vrfFromKey)
	if intVrfFromKey != int(config.VrfId) {
		if err != nil {
			return err
		}
		plugin.Log.Warnf("VRF index from key (%v) and from config (%v) does not match, using value from the key",
			intVrfFromKey, config.VrfId)
		config.VrfId = uint32(intVrfFromKey)
	}
	return nil
}

func (plugin *RouteConfigurator) checkMsgCompatibility() error {
	msgs := []govppapi.Message{
		&ip.IPAddDelRoute{},
		&ip.IPAddDelRouteReply{},
		&ip.IPFibDump{},
		&ip.IPFibDetails{},
		&ip.IP6FibDump{},
		&ip.IP6FibDetails{},
	}
	err := plugin.vppChan.CheckMessageCompatibility(msgs...)
	if err != nil {
		plugin.Log.Error(err)
	}
	return err
}

// Close GOVPP channel.
func (plugin *RouteConfigurator) Close() error {
	return safeclose.Close(plugin.vppChan)
}

// Create unique identifier which serves as a name in name-to-index mapping.
func routeIdentifier(vrf uint32, destination string, nextHop string) string {
	return fmt.Sprintf("vrf%v-%v-%v", vrf, destination, nextHop)
}

//ResolveCreatedInterface is responsible for reconfiguring cached routes and then from removing
//them from route cache
func (plugin *RouteConfigurator) ResolveCreatedInterface(ifName string, swIdx uint32) {
	routesWithIndex := plugin.RouteCachedIndex.LookupRouteAndIdByOutgoingIfc(ifName)
	for _, routeWithIndex := range routesWithIndex {
		route := routeWithIndex.Route
		plugin.Log.WithFields(
				logging.Fields{
				"interface ifName":         ifName,
				"interface software index": swIdx,
				"vrf":                      route.VrfId,
				"destination ip":           route.DstIpAddr}).
			Debug("Remove routes from cache - outgoing interface was added.")
		plugin.ConfigureRoute(route, strconv.FormatUint(uint64(route.VrfId), 10))
		plugin.RouteCachedIndex.UnregisterName(routeWithIndex.RouteID)
	}
}

//ResolveDeletedInterface is responsible for moving routes of deleted interface to cache
func (plugin *RouteConfigurator) ResolveDeletedInterface(ifName string, swIdx uint32) {
	routesWithIndex := plugin.RouteCachedIndex.LookupRouteAndIdByOutgoingIfc(ifName)
	for _, routeWithIndex := range routesWithIndex {
		route := routeWithIndex.Route
		plugin.Log.WithFields(
			logging.Fields{
				"interface ifName":         ifName,
				"interface software index": swIdx,
				"vrf":                      route.VrfId,
				"destination ip":           route.DstIpAddr}).
			Debug("Add routes to cache - outgoing interface was deleted.")
		plugin.DeleteRoute(route, strconv.FormatUint(uint64(route.VrfId), 10))
		plugin.RouteCachedIndex.RegisterName(routeWithIndex.RouteID, plugin.RouteIndexSeq, route)
		plugin.RouteIndexSeq++
	}
}<|endoftext|>


<commit_before>// test program to parse dwml xml format from NOAA API

package main

import (
	"encoding/xml"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"reflect"
	"runtime/pprof"
	"time"
)

var inputFile = flag.String("infile", "1~.txt", "Input file path")

func dump_httpresp(resp *http.Response) {
	fmt.Println("resp: ", resp)

	st := reflect.TypeOf(resp)
	fmt.Println(st)

	val := reflect.ValueOf(resp).Elem()

	for i := 0; i < val.NumField(); i++ {
		valueField := val.Field(i)
		typeField := val.Type().Field(i)
		typeName := valueField.Type().Name()

		fmt.Printf("Field Name: %s(%s),\t\t\t Field Value: %v\n", typeField.Name, typeName, valueField.Interface())
	}

	fmt.Println("=== headers ===")
	for k, v := range resp.Header {
		fmt.Printf("%20s = %20s\n", k, v)
	}
}

func dump_value(val reflect.Value) {
	for i := 0; i < val.NumField(); i++ {
		valueField := val.Field(i)
		typeField := val.Type().Field(i)
		typeName := valueField.Type().Name()
		fmt.Printf("%s(%s): %v\n", typeField.Name, typeName, valueField.Interface())
	}
}

// ===========================================================================
// NOAA API dwml structures (top to bottom order)

// root element

type Dwml struct {
	XMLName xml.Name `xml:"dwml"`
	Header  Header   `xml:"head"`
	Data    Data     `xml:"data"`
}

// 3 second level elements

type Header struct {
	XMLName xml.Name `xml:"head"`
	Product Product  `xml:"product"`
}

type Data struct {
	XMLName     xml.Name     `xml:"data"`
	TimeLayouts []TimeLayout `xml:"time-layout"`
	Parameters  Parameters   `xml:"parameters"`
}

// head element children

type Product struct {
	XMLName xml.Name `xml:"product"`
	Src     string   `xml:"srsName,attr"`
	Name    string   `xml:"concise-name,attr"`
	Mode    string   `xml:"operational-mode,attr"`
}

// data element children

type TimeLayout struct {
	XMLName       xml.Name `xml:"time-layout"`
	Coordinate    string   `xml:"time-coordinate,attr"`
	Summarization string   `xml:"summarization,attr"`
	Key           string   `xml:"layout-key"`
	StartTime     []string `xml:"start-valid-time"`
	EndTime       []string `xml:"end-valid-time"`
}

type Parameters struct {
	XMLName       xml.Name   `xml:"parameters"`
	Temperatures  []Valueset `xml:"temperature"`
	Precipitation Valueset   `xml:"precipitation"`
}

type Valueset struct {
	Type       string   `xml:"type,attr"`
	Units      string   `xml:"units,attr"`
	TimeLayout string   `xml:"time-layout,attr"`
	Name       string   `xml:"name"`
	Values     []string `xml:"value"`
}

// ===========================================================================

func decode_dwml(xmlFile *os.File) {
	decoder := xml.NewDecoder(xmlFile)

	p := &Dwml{}
	if err := decoder.Decode(p); err != nil {
		fmt.Println("ERROR: %v", err)
		return
	}

	fmt.Println("Time layouts:")

	for idx, v := range p.Data.TimeLayouts {
		fmt.Println("    ", idx, v.Key, len(v.StartTime))
	}

	fmt.Println("Temperatures:")

	for idx, v := range p.Data.Parameters.Temperatures {
		fmt.Println("    ", idx, v.Name, v.TimeLayout, len(v.Values))
	}

	pr := p.Data.Parameters.Precipitation
	fmt.Println("Precipitation:", pr.TimeLayout, len(pr.Values))
}

func file_cached(fname *string) bool {

	fi, err := os.Stat(*fname)

	if err != nil || fi == nil {
		return false
	}

	if fi.ModTime().Unix()-time.Now().UTC().Unix() < 60*72 {
		return true
	}

	newname := *fname + ".old"

	err = os.Rename(*fname, newname)
	if err != nil {
		fmt.Println("ERROR: %v", err)
	}

	return false
}

func main() {

	flag.Parse()

	dump_resp := false

	if !file_cached(inputFile) {

		fmt.Println("loading from NOAA")

		url := "http://www.weather.gov/forecasts/xml/SOAP_server/ndfdXMLclient.php?whichClient=NDFDgen&zipCodeList=10001&product=time-series&maxt=maxt&mint=mint&temp=temp&wspd=wspd&wdir=wdir&wx=wx&rh=rh&snow=snow&wwa=wwa&sky=sky&appt=appt&Submit=Submit"

		resp, err := http.Get(url)

		fmt.Println("err: ", err)

		if dump_resp {
			dump_httpresp(resp)
		}

		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		//fmt.Println(body)

		err = ioutil.WriteFile(*inputFile, body, 0666)
		fmt.Println("write: ", err)
	}

	xmlFile, err := os.Open(*inputFile)

	if err != nil {
		fmt.Println("Error opening file:", err)
		return
	}

	defer xmlFile.Close()

	f, err := os.Create("1~.prof")
	if err != nil {
		fmt.Println(err)
	}

	pprof.StartCPUProfile(f)
	defer pprof.StopCPUProfile()

	decode_dwml(xmlFile)
}
<commit_msg>Further parsing of dwml.<commit_after>// test program to parse dwml xml format from NOAA API

package main

import (
	"encoding/xml"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"reflect"
	"runtime/pprof"
	"time"
)

var inputFile = flag.String("infile", "1~.xml", "Input file path")

func dump_httpresp(resp *http.Response) {
	fmt.Println("resp: ", resp)

	st := reflect.TypeOf(resp)
	fmt.Println(st)

	val := reflect.ValueOf(resp).Elem()

	for i := 0; i < val.NumField(); i++ {
		valueField := val.Field(i)
		typeField := val.Type().Field(i)
		typeName := valueField.Type().Name()

		fmt.Printf("Field Name: %s(%s),\t\t\t Field Value: %v\n", typeField.Name, typeName, valueField.Interface())
	}

	fmt.Println("=== headers ===")
	for k, v := range resp.Header {
		fmt.Printf("%20s = %20s\n", k, v)
	}
}

func dump_value(val reflect.Value) {
	for i := 0; i < val.NumField(); i++ {
		valueField := val.Field(i)
		typeField := val.Type().Field(i)
		typeName := valueField.Type().Name()
		fmt.Printf("%s(%s): %v\n", typeField.Name, typeName, valueField.Interface())
	}
}

// ===========================================================================
// NOAA API dwml structures (top to bottom order)

// root element

type Dwml struct {
	XMLName xml.Name `xml:"dwml"`
	Header  Header   `xml:"head"`
	Data    Data     `xml:"data"`
}

// 3 second level elements

type Header struct {
	XMLName xml.Name `xml:"head"`
	Product Product  `xml:"product"`
}

type Data struct {
	XMLName     xml.Name     `xml:"data"`
	TimeLayouts []TimeLayout `xml:"time-layout"`
	Parameters  Parameters   `xml:"parameters"`
}

// head element children

type Product struct {
	XMLName xml.Name `xml:"product"`
	Src     string   `xml:"srsName,attr"`
	Name    string   `xml:"concise-name,attr"`
	Mode    string   `xml:"operational-mode,attr"`
}

// data element children

type TimeLayout struct {
	XMLName       xml.Name `xml:"time-layout"`
	Coordinate    string   `xml:"time-coordinate,attr"`
	Summarization string   `xml:"summarization,attr"`
	Key           string   `xml:"layout-key"`
	StartTime     []string `xml:"start-valid-time"`
	EndTime       []string `xml:"end-valid-time"`
}

type Parameters struct {
	XMLName       xml.Name  `xml:"parameters"`
	Temperature   []Valueset `xml:"temperature"`
	WindSpeed     []Valueset `xml:"wind-speed"`
	Direction     []Valueset `xml:"direction"`
	CloudAmount   []Valueset `xml:"cloud-amount"`
	Precipitation []Valueset `xml:"precipitation"`
	Humidity      []Valueset `xml:"humidity"`
}

type Visibility struct {
	XMLName       xml.Name
	Units string              `xml:"units,attr"`
}

type ConditionValue struct {
	Coverage string              `xml:"coverage,attr"`
	Intencity string              `xml:"intencity,attr"`
	WeatherType string              `xml:"weather-type,attr"`
	Qualifier string              `xml:"qualifier,attr"`
}

type WeatherConditions struct {
	Value []ConditionValue `xml:"value"`
}

type Weather struct {
	TimeLayout string              `xml:"time-layout,attr"`
	Conditions []WeatherConditions `xml:"weather-conditions"`
}

type Valueset struct {
	Type       string   `xml:"type,attr"`
	Units      string   `xml:"units,attr"`
	TimeLayout string   `xml:"time-layout,attr"`
	Name       string   `xml:"name"`
	Values     []string `xml:"value"`
}

// ===========================================================================

func decode_dwml(xmlFile *os.File) {
	decoder := xml.NewDecoder(xmlFile)

	p := &Dwml{}
	if err := decoder.Decode(p); err != nil {
		fmt.Println("ERROR: %v", err)
		return
	}

	fmt.Println("Time layouts:")

	for _, v := range p.Data.TimeLayouts {
		fmt.Println("    ", v.Key, len(v.StartTime))
	}

	fmt.Println("Air:")

	for _, v := range p.Data.Parameters.Temperature {
		fmt.Println("    ", v.Name, v.TimeLayout, len(v.Values))
	}

	for _, v := range p.Data.Parameters.Humidity {
		fmt.Println("    ", v.Name, v.TimeLayout, len(v.Values))
	}

	fmt.Println("Wind:")

	for _, v := range p.Data.Parameters.WindSpeed {
		fmt.Println("    ", v.Name, v.TimeLayout, len(v.Values))
	}

	for _, v := range p.Data.Parameters.Direction {
		fmt.Println("    ", v.Name, v.TimeLayout, len(v.Values))
	}

	fmt.Println("Sky:")

	for _, v := range p.Data.Parameters.CloudAmount {
		fmt.Println("    ", v.Name, v.TimeLayout, len(v.Values))
	}

	for _, v := range p.Data.Parameters.Precipitation {
		fmt.Println("    ", v.Name, v.TimeLayout, len(v.Values))
	}
}

func file_cached(fname *string) bool {

	fi, err := os.Stat(*fname)

	if err != nil || fi == nil {
		return false
	}

	if fi.ModTime().Unix()-time.Now().UTC().Unix() < 60*72 {
		return true
	}

	newname := *fname + ".old"

	err = os.Rename(*fname, newname)
	if err != nil {
		fmt.Println("ERROR: %v", err)
	}

	return false
}

func main() {

	flag.Parse()

	dump_resp := false

	if !file_cached(inputFile) {

		fmt.Println("loading from NOAA")

		url := "http://www.weather.gov/forecasts/xml/SOAP_server/ndfdXMLclient.php?whichClient=NDFDgen&zipCodeList=10001&product=time-series&maxt=maxt&mint=mint&temp=temp&wspd=wspd&wdir=wdir&wx=wx&rh=rh&snow=snow&wwa=wwa&sky=sky&appt=appt&Submit=Submit"

		resp, err := http.Get(url)

		fmt.Println("err: ", err)

		if dump_resp {
			dump_httpresp(resp)
		}

		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		//fmt.Println(body)

		err = ioutil.WriteFile(*inputFile, body, 0666)
		fmt.Println("write: ", err)
	}

	xmlFile, err := os.Open(*inputFile)

	if err != nil {
		fmt.Println("Error opening file:", err)
		return
	}

	defer xmlFile.Close()

	f, err := os.Create("1~.prof")
	if err != nil {
		fmt.Println(err)
	}

	pprof.StartCPUProfile(f)
	defer pprof.StopCPUProfile()

	decode_dwml(xmlFile)
}
<|endoftext|>