<commit_before>package workers

import (
	"fmt"
	"github.com/APTrust/exchange/constants"
	"github.com/APTrust/exchange/context"
	"github.com/APTrust/exchange/dpn/models"
	"github.com/APTrust/exchange/dpn/network"
	"github.com/APTrust/exchange/util/fileutil"
	"github.com/APTrust/exchange/util/storage"
	"github.com/APTrust/exchange/validation"
	"github.com/nsqio/go-nsq"
	"github.com/satori/go.uuid"
	"os"
	"time"
)

type DPNFixityChecker struct {
	Context            *context.Context
	LocalDPNRestClient *network.DPNRestClient
	ValidationChannel  chan *DPNRestoreHelper
	RecordChannel      chan *DPNRestoreHelper
	CleanupChannel     chan *DPNRestoreHelper
	// PreTestChannel is used in testing only to set some properties
	// on the helper/manifest. PreTestChannel should push directly into
	// the ValidationChannel.
	PreTestChannel chan *DPNRestoreHelper
	// PostTestChannel is for testing only. It allows us to inspect the
	// state of our helper and manifest when processing completes.
	PostTestChannel     chan *DPNRestoreHelper
	BagValidationConfig *validation.BagValidationConfig
}

// NewDPNFixityChecker creates a new DPNFixityChecker.
func NewDPNFixityChecker(_context *context.Context) (*DPNFixityChecker, error) {
	localClient, err := network.NewDPNRestClient(
		_context.Config.DPN.RestClient.LocalServiceURL,
		_context.Config.DPN.RestClient.LocalAPIRoot,
		_context.Config.DPN.RestClient.LocalAuthToken,
		_context.Config.DPN.LocalNode,
		_context.Config.DPN)
	if err != nil {
		return nil, fmt.Errorf("Error creating local DPN REST client: %v", err)
	}
	checker := &DPNFixityChecker{
		Context:            _context,
		LocalDPNRestClient: localClient,
	}
	// LoadDPNBagValidationConfig is defined in dpn/workers/common.go
	checker.BagValidationConfig = LoadDPNBagValidationConfig(checker.Context)
	workerBufferSize := _context.Config.DPN.DPNFixityWorker.Workers * 4
	checker.ValidationChannel = make(chan *DPNRestoreHelper, workerBufferSize)
	checker.RecordChannel = make(chan *DPNRestoreHelper, workerBufferSize)
	checker.CleanupChannel = make(chan *DPNRestoreHelper, workerBufferSize)
	for i := 0; i < _context.Config.DPN.DPNPackageWorker.Workers; i++ {
		go checker.validate()
		go checker.record()
		go checker.cleanup()
	}
	return checker, nil
}

// HandleMessage is the NSQ message handler. The NSQ consumer will pass each
// message in the subscribed channel to this function.
func (checker *DPNFixityChecker) HandleMessage(message *nsq.Message) error {
	message.DisableAutoResponse()

	helper, err := NewDPNRestoreHelper(message, checker.Context,
		checker.LocalDPNRestClient, constants.ActionFixityCheck,
		"ValidationSummary")
	if err != nil {
		checker.Context.MessageLog.Error(err.Error())
		return err
	}

	if helper.Manifest.DPNWorkItem.IsCompletedOrCancelled() {
		checker.Context.MessageLog.Info("Skipping WorkItem %d because status is %s",
			helper.Manifest.DPNWorkItem.Id, helper.Manifest.DPNWorkItem.Status)
		message.Finish()
		return nil
	}

	helper.WorkSummary.ClearErrors()
	helper.WorkSummary.Attempted = true
	helper.WorkSummary.AttemptNumber += 1
	helper.WorkSummary.Start()
	helper.Manifest.DPNWorkItem.Status = constants.StatusStarted
	helper.Manifest.DPNWorkItem.Stage = constants.StageValidate
	helper.SaveDPNWorkItem()

	if helper.WorkSummary.HasErrors() {
		checker.Context.MessageLog.Error("Error setting up manifest for WorkItem %s: %s",
			string(message.Body), helper.WorkSummary.AllErrorsAsString())
		// No use proceeding...
		checker.CleanupChannel <- helper
		return fmt.Errorf(helper.WorkSummary.AllErrorsAsString())
	}

	if helper.Manifest.ExpectedFixityValue == "" {
		helper.WorkSummary.AddError("ExpectedFixityValue for bag %s "+
			"is missing from manifest. Cannot validate.", helper.Manifest.DPNBag.UUID)
		helper.WorkSummary.ErrorIsFatal = true
		checker.CleanupChannel <- helper
		return nil
	}

	if checker.PreTestChannel != nil {
		checker.PreTestChannel <- helper
	} else {
		checker.ValidationChannel <- helper
	}
	return nil
}

func (checker *DPNFixityChecker) validate() {
	for helper := range checker.ValidationChannel {
		checker.Context.MessageLog.Info("Validating %s", helper.Manifest.LocalPath)
		// Validation can take long time.
		// Ping NSQ immediately before and after,
		// so we don't time out.
		helper.Manifest.NsqMessage.Touch()
		checker.ValidateBag(helper)
		helper.Manifest.NsqMessage.Touch()

		if helper.WorkSummary.HasErrors() {
			checker.CleanupChannel <- helper
		} else {
			checker.RecordChannel <- helper
		}
	}
}

// DPN fixity check requires us to validate the entire bag and
// extract the sha256 checksum of tagmanifest-sha256.txt file.
// If the bag is valid, and the fixity value of the tag manifest
// matches what's in the DPN registry, the fixity check passes.
// DPN currently has no way of recording that a fixity check has
// failed, other than a human looking at the records. We can record
// the DPNWorkItem as failed in Pharos.
func (checker *DPNFixityChecker) ValidateBag(helper *DPNRestoreHelper) {
	validator, err := validation.NewValidator(helper.Manifest.LocalPath,
		checker.BagValidationConfig, false)
	if err != nil {
		helper.WorkSummary.AddError(err.Error())
		helper.WorkSummary.ErrorIsFatal = true
	} else {
		// Validation can take a long time for large bags.
		summary, err := validator.Validate()
		if err != nil {
			helper.WorkSummary.AddError(err.Error())
		} else {
			checker.Context.MessageLog.Info("Finished validating %s",
				helper.Manifest.LocalPath)
			for _, validationError := range summary.Errors {
				helper.WorkSummary.AddError(validationError)
				helper.WorkSummary.ErrorIsFatal = true
			}
			checker.getTagManifestChecksum(helper, validator)
		}
	}
}

// The validator records the results of its work in a BoltDB
// file because we often get bags with over 100,000 files.
// We can extract the tagmanifest-sha256.txt checksum from the BoltDB.
func (checker *DPNFixityChecker) getTagManifestChecksum(helper *DPNRestoreHelper, validator *validation.Validator) {
	fileIdentifier := fmt.Sprintf("%s/tagmanifest-sha256.txt", helper.Manifest.DPNBag.UUID)
	checker.Context.MessageLog.Info("Looking up %s in BoltDB %s",
		fileIdentifier, validator.DBName())
	db, err := storage.NewBoltDB(validator.DBName())
	if err != nil {
		helper.WorkSummary.AddError("Error opening BoltDB: %v", err)
		return
	}
	defer db.Close()
	gf, err := db.GetGenericFile(fileIdentifier)
	if err != nil {
		helper.WorkSummary.AddError("Error finding file %s in BoltDB: %v", fileIdentifier, err)
		return
	}
	if gf == nil {
		helper.WorkSummary.AddError("Cannot find file %s in BoltDB.", fileIdentifier)
		return
	}

	// Record on the manifest the actual sha256 digest that the validator
	// just calculated for the tagmanifest-sha256.txt file.
	helper.Manifest.ActualFixityValue = gf.IngestSha256
	checker.Context.MessageLog.Info("Validator calculated checksum %s for file %s",
		gf.IngestSha256, fileIdentifier)

	// Once we have the validation result and the fixity value,
	// we no longer need the local files (except in unit tests).
	checker.cleanupLocalFiles(helper, validator)
}

func (checker *DPNFixityChecker) cleanupLocalFiles(helper *DPNRestoreHelper, validator *validation.Validator) {
	if checker.Context.Config.TestsAreRunning() {
		checker.Context.MessageLog.Info("Skippint local file and BoltDB deletion because tests are running.")
		return
	}
	// Delete the BoltDB file
	if fileutil.LooksSafeToDelete(validator.DBName(), 12, 3) {
		checker.Context.MessageLog.Info("Deleting BoltDB file %s", validator.DBName())
		err := os.Remove(validator.DBName())
		if err != nil {
			checker.Context.MessageLog.Warning("Error deleting %s: %v", validator.DBName(), err)
		}
	}
	// Delete the local copy of the bag.
	if fileutil.LooksSafeToDelete(helper.Manifest.LocalPath, 12, 3) {
		checker.Context.MessageLog.Info("Deleting local bag file %s", helper.Manifest.LocalPath)
		err := os.Remove(helper.Manifest.LocalPath)
		if err != nil {
			checker.Context.MessageLog.Warning("Error deleting %s: %v", helper.Manifest.LocalPath, err)
		}
	}
}

// Record this fixity check in our local DPN REST server
func (checker *DPNFixityChecker) record() {
	for helper := range checker.RecordChannel {
		checker.Context.MessageLog.Info("Preparing to record fixity for %s", helper.Manifest.DPNBag.UUID)
		checker.SaveFixityRecord(helper)
		checker.CleanupChannel <- helper
	}
}

// Update NSQ and Pharos on the status of this task
func (checker *DPNFixityChecker) cleanup() {
	for helper := range checker.CleanupChannel {
		helper.WorkSummary.Finish()
		if helper.WorkSummary.HasErrors() {
			checker.FinishWithError(helper)
		} else {
			checker.FinishWithSuccess(helper)
		}
		// For testing only. The test code creates the PostTestChannel.
		// When running in demo & production, this channel is nil.
		if checker.PostTestChannel != nil {
			checker.PostTestChannel <- helper
		}
	}
}

// Save the fixity record to the local DPN REST server.
func (checker *DPNFixityChecker) SaveFixityRecord(helper *DPNRestoreHelper) {
	// Create a FixityCheck record and save it with
	// checker.LocalDPNRestClient.FixityCheckCreate()
	if helper.Manifest.ExpectedFixityValue == "" {
		helper.WorkSummary.AddError("Cannot create DPN FixityCheck record because " +
			"because ExpectedFixityValue is missing from manifest.")
		return
	}
	if helper.Manifest.ActualFixityValue == "" {
		helper.WorkSummary.AddError("Cannot create DPN FixityCheck record because " +
			"because ActualFixityValue is missing from manifest.")
		return
	}
	if helper.Manifest.FixityCheck == nil {
		utcNow := time.Now().UTC()
		helper.Manifest.FixityCheck = &models.FixityCheck{
			FixityCheckId: uuid.NewV4().String(),
			Bag:           helper.Manifest.DPNBag.UUID,
			Node:          checker.Context.Config.DPN.LocalNode,
			Success:       helper.Manifest.ExpectedFixityValue == helper.Manifest.ActualFixityValue,
			FixityAt:      utcNow,
			CreatedAt:     utcNow,
		}
	}
	checker.Context.MessageLog.Info("Posting new fixity check %s for bag %s to %s",
		helper.Manifest.FixityCheck.FixityCheckId, helper.Manifest.DPNBag.UUID,
		checker.LocalDPNRestClient.HostUrl)
	resp := checker.LocalDPNRestClient.FixityCheckCreate(helper.Manifest.FixityCheck)
	if resp.Error != nil {
		helper.WorkSummary.AddError("Error saving FixityCheck to DPN REST server: %v",
			resp.Error)
		return
	}
	helper.Manifest.FixityCheck.CreatedAt = resp.FixityCheck().CreatedAt
	helper.Manifest.FixityCheckSavedAt = time.Now().UTC()
	if helper.Manifest.CheckCompletedAndFailed() {
		helper.WorkSummary.AddError(
			"Fixity check completed, and fixity record %s was saved to DPN. "+
				"Actual fixity value %s does not match expected fixity %s",
			helper.Manifest.FixityCheck.FixityCheckId,
			helper.Manifest.ActualFixityValue, helper.Manifest.ExpectedFixityValue)
		helper.WorkSummary.ErrorIsFatal = true
	}
}

func (checker *DPNFixityChecker) FinishWithSuccess(helper *DPNRestoreHelper) {
	helper.Manifest.DPNWorkItem.ClearNodeAndPid()
	checker.Context.MessageLog.Info("Completed fixity check for %s. Saved to DPN with FixityCheckId %s",
		helper.Manifest.DPNBag.UUID, helper.Manifest.FixityCheck.FixityCheckId)
	note := fmt.Sprintf("Fixity check complete. Saved to DPN with FixityCheckId %s",
		helper.Manifest.FixityCheck.FixityCheckId)
	helper.Manifest.DPNWorkItem.Note = &note
	// TODO: To repurpose this code to support restoration,
	// branch here. If DPNWorkItem.Task is fixity check,
	// set Status to Success. If Task is restore, set Stage
	// to StageRestoring, status to StatusPending, and push the
	// bag into the restoration queue, or do whatever else is
	// necessary to complete the restore process.
	helper.WorkSummary.Finish()
	helper.Manifest.DPNWorkItem.Stage = constants.StageResolve
	helper.Manifest.DPNWorkItem.Status = constants.StatusSuccess
	helper.SaveDPNWorkItem()
	helper.Manifest.NsqMessage.Finish()
}

func (checker *DPNFixityChecker) FinishWithError(helper *DPNRestoreHelper) {
	helper.Manifest.DPNWorkItem.ClearNodeAndPid()
	// Copy errors into the DPNWorkItem note, so we can see them in
	// the Pharos UI.
	errors := helper.WorkSummary.AllErrorsAsString()
	helper.Manifest.DPNWorkItem.Note = &errors
	checker.Context.MessageLog.Error(errors)
	helper.WorkSummary.Finish()
	if helper.WorkSummary.ErrorIsFatal {
		// Mark the DPNWorkItem as failed
		checker.Context.MessageLog.Error("Error for %s is fatal. Not requeueing.",
			helper.Manifest.DPNWorkItem.Identifier)
		helper.Manifest.DPNWorkItem.Status = constants.StatusFailed
		helper.Manifest.DPNWorkItem.Retry = false
		helper.SaveDPNWorkItem()
		helper.Manifest.NsqMessage.Finish()
	} else {
		// Transient errors. Retry DPNWorkItem.
		// MINUTES_BETWEEN_RETRIES is defined in dpn_s3_retriever.go
		helper.Manifest.DPNWorkItem.Retry = true
		helper.SaveDPNWorkItem()
		helper.Manifest.NsqMessage.Requeue(MINUTES_BETWEEN_RETRIES * time.Minute)
	}
}
<commit_msg>Record work in WorkSummary<commit_after>package workers

import (
	"fmt"
	"github.com/APTrust/exchange/constants"
	"github.com/APTrust/exchange/context"
	"github.com/APTrust/exchange/dpn/models"
	"github.com/APTrust/exchange/dpn/network"
	"github.com/APTrust/exchange/util/fileutil"
	"github.com/APTrust/exchange/util/storage"
	"github.com/APTrust/exchange/validation"
	"github.com/nsqio/go-nsq"
	"github.com/satori/go.uuid"
	"os"
	"time"
)

type DPNFixityChecker struct {
	Context            *context.Context
	LocalDPNRestClient *network.DPNRestClient
	ValidationChannel  chan *DPNRestoreHelper
	RecordChannel      chan *DPNRestoreHelper
	CleanupChannel     chan *DPNRestoreHelper
	// PreTestChannel is used in testing only to set some properties
	// on the helper/manifest. PreTestChannel should push directly into
	// the ValidationChannel.
	PreTestChannel chan *DPNRestoreHelper
	// PostTestChannel is for testing only. It allows us to inspect the
	// state of our helper and manifest when processing completes.
	PostTestChannel     chan *DPNRestoreHelper
	BagValidationConfig *validation.BagValidationConfig
}

// NewDPNFixityChecker creates a new DPNFixityChecker.
func NewDPNFixityChecker(_context *context.Context) (*DPNFixityChecker, error) {
	localClient, err := network.NewDPNRestClient(
		_context.Config.DPN.RestClient.LocalServiceURL,
		_context.Config.DPN.RestClient.LocalAPIRoot,
		_context.Config.DPN.RestClient.LocalAuthToken,
		_context.Config.DPN.LocalNode,
		_context.Config.DPN)
	if err != nil {
		return nil, fmt.Errorf("Error creating local DPN REST client: %v", err)
	}
	checker := &DPNFixityChecker{
		Context:            _context,
		LocalDPNRestClient: localClient,
	}
	// LoadDPNBagValidationConfig is defined in dpn/workers/common.go
	checker.BagValidationConfig = LoadDPNBagValidationConfig(checker.Context)
	workerBufferSize := _context.Config.DPN.DPNFixityWorker.Workers * 4
	checker.ValidationChannel = make(chan *DPNRestoreHelper, workerBufferSize)
	checker.RecordChannel = make(chan *DPNRestoreHelper, workerBufferSize)
	checker.CleanupChannel = make(chan *DPNRestoreHelper, workerBufferSize)
	for i := 0; i < _context.Config.DPN.DPNPackageWorker.Workers; i++ {
		go checker.validate()
		go checker.record()
		go checker.cleanup()
	}
	return checker, nil
}

// HandleMessage is the NSQ message handler. The NSQ consumer will pass each
// message in the subscribed channel to this function.
func (checker *DPNFixityChecker) HandleMessage(message *nsq.Message) error {
	message.DisableAutoResponse()

	helper, err := NewDPNRestoreHelper(message, checker.Context,
		checker.LocalDPNRestClient, constants.ActionFixityCheck,
		"ValidationSummary")
	if err != nil {
		checker.Context.MessageLog.Error(err.Error())
		return err
	}

	if helper.Manifest.DPNWorkItem.IsCompletedOrCancelled() {
		checker.Context.MessageLog.Info("Skipping WorkItem %d because status is %s",
			helper.Manifest.DPNWorkItem.Id, helper.Manifest.DPNWorkItem.Status)
		message.Finish()
		return nil
	}

	helper.WorkSummary.ClearErrors()
	helper.WorkSummary.Attempted = true
	helper.WorkSummary.AttemptNumber += 1
	helper.WorkSummary.Start()
	helper.Manifest.DPNWorkItem.Status = constants.StatusStarted
	helper.Manifest.DPNWorkItem.Stage = constants.StageValidate
	helper.SaveDPNWorkItem()

	if helper.WorkSummary.HasErrors() {
		checker.Context.MessageLog.Error("Error setting up manifest for WorkItem %s: %s",
			string(message.Body), helper.WorkSummary.AllErrorsAsString())
		// No use proceeding...
		checker.CleanupChannel <- helper
		return fmt.Errorf(helper.WorkSummary.AllErrorsAsString())
	}

	if helper.Manifest.ExpectedFixityValue == "" {
		helper.WorkSummary.AddError("ExpectedFixityValue for bag %s "+
			"is missing from manifest. Cannot validate.", helper.Manifest.DPNBag.UUID)
		helper.WorkSummary.ErrorIsFatal = true
		checker.CleanupChannel <- helper
		return nil
	}

	if checker.PreTestChannel != nil {
		checker.PreTestChannel <- helper
	} else {
		checker.ValidationChannel <- helper
	}
	return nil
}

func (checker *DPNFixityChecker) validate() {
	for helper := range checker.ValidationChannel {
		checker.Context.MessageLog.Info("Validating %s", helper.Manifest.LocalPath)
		// Validation can take long time.
		// Ping NSQ immediately before and after,
		// so we don't time out.
		helper.Manifest.NsqMessage.Touch()
		checker.ValidateBag(helper)
		helper.Manifest.NsqMessage.Touch()

		if helper.WorkSummary.HasErrors() {
			checker.CleanupChannel <- helper
		} else {
			checker.RecordChannel <- helper
		}
	}
}

// DPN fixity check requires us to validate the entire bag and
// extract the sha256 checksum of tagmanifest-sha256.txt file.
// If the bag is valid, and the fixity value of the tag manifest
// matches what's in the DPN registry, the fixity check passes.
// DPN currently has no way of recording that a fixity check has
// failed, other than a human looking at the records. We can record
// the DPNWorkItem as failed in Pharos.
func (checker *DPNFixityChecker) ValidateBag(helper *DPNRestoreHelper) {
	validator, err := validation.NewValidator(helper.Manifest.LocalPath,
		checker.BagValidationConfig, false)
	if err != nil {
		helper.WorkSummary.AddError(err.Error())
		helper.WorkSummary.ErrorIsFatal = true
	} else {
		// Validation can take a long time for large bags.
		summary, err := validator.Validate()
		if err != nil {
			helper.WorkSummary.AddError(err.Error())
		} else {
			checker.Context.MessageLog.Info("Finished validating %s",
				helper.Manifest.LocalPath)
			for _, validationError := range summary.Errors {
				helper.WorkSummary.AddError(validationError)
				helper.WorkSummary.ErrorIsFatal = true
			}
			checker.getTagManifestChecksum(helper, validator)
		}
	}
}

// The validator records the results of its work in a BoltDB
// file because we often get bags with over 100,000 files.
// We can extract the tagmanifest-sha256.txt checksum from the BoltDB.
func (checker *DPNFixityChecker) getTagManifestChecksum(helper *DPNRestoreHelper, validator *validation.Validator) {
	fileIdentifier := fmt.Sprintf("%s/tagmanifest-sha256.txt", helper.Manifest.DPNBag.UUID)
	checker.Context.MessageLog.Info("Looking up %s in BoltDB %s",
		fileIdentifier, validator.DBName())
	db, err := storage.NewBoltDB(validator.DBName())
	if err != nil {
		helper.WorkSummary.AddError("Error opening BoltDB: %v", err)
		return
	}
	defer db.Close()
	gf, err := db.GetGenericFile(fileIdentifier)
	if err != nil {
		helper.WorkSummary.AddError("Error finding file %s in BoltDB: %v", fileIdentifier, err)
		return
	}
	if gf == nil {
		helper.WorkSummary.AddError("Cannot find file %s in BoltDB.", fileIdentifier)
		return
	}

	// Record on the manifest the actual sha256 digest that the validator
	// just calculated for the tagmanifest-sha256.txt file.
	helper.Manifest.ActualFixityValue = gf.IngestSha256
	checker.Context.MessageLog.Info("Validator calculated checksum %s for file %s",
		gf.IngestSha256, fileIdentifier)

	// Once we have the validation result and the fixity value,
	// we no longer need the local files (except in unit tests).
	checker.cleanupLocalFiles(helper, validator)
}

func (checker *DPNFixityChecker) cleanupLocalFiles(helper *DPNRestoreHelper, validator *validation.Validator) {
	if checker.Context.Config.TestsAreRunning() {
		checker.Context.MessageLog.Info("Skippint local file and BoltDB deletion because tests are running.")
		return
	}
	// Delete the BoltDB file
	if fileutil.LooksSafeToDelete(validator.DBName(), 12, 3) {
		checker.Context.MessageLog.Info("Deleting BoltDB file %s", validator.DBName())
		err := os.Remove(validator.DBName())
		if err != nil {
			checker.Context.MessageLog.Warning("Error deleting %s: %v", validator.DBName(), err)
		}
	}
	// Delete the local copy of the bag.
	if fileutil.LooksSafeToDelete(helper.Manifest.LocalPath, 12, 3) {
		checker.Context.MessageLog.Info("Deleting local bag file %s", helper.Manifest.LocalPath)
		err := os.Remove(helper.Manifest.LocalPath)
		if err != nil {
			checker.Context.MessageLog.Warning("Error deleting %s: %v", helper.Manifest.LocalPath, err)
		}
	}
}

// Record this fixity check in our local DPN REST server
func (checker *DPNFixityChecker) record() {
	for helper := range checker.RecordChannel {
		checker.Context.MessageLog.Info("Preparing to record fixity for %s", helper.Manifest.DPNBag.UUID)
		checker.SaveFixityRecord(helper)
		checker.CleanupChannel <- helper
	}
}

// Update NSQ and Pharos on the status of this task
func (checker *DPNFixityChecker) cleanup() {
	for helper := range checker.CleanupChannel {
		helper.WorkSummary.Finish()
		if helper.WorkSummary.HasErrors() {
			checker.FinishWithError(helper)
		} else {
			checker.FinishWithSuccess(helper)
		}
		// For testing only. The test code creates the PostTestChannel.
		// When running in demo & production, this channel is nil.
		if checker.PostTestChannel != nil {
			checker.PostTestChannel <- helper
		}
	}
}

// Save the fixity record to the local DPN REST server.
func (checker *DPNFixityChecker) SaveFixityRecord(helper *DPNRestoreHelper) {
	helper.Manifest.RecordSummary.Attempted = true
	helper.Manifest.RecordSummary.AttemptNumber += 1
	helper.Manifest.RecordSummary.Start()
	// Create a FixityCheck record and save it with
	// checker.LocalDPNRestClient.FixityCheckCreate()
	if helper.Manifest.ExpectedFixityValue == "" {
		helper.WorkSummary.AddError("Cannot create DPN FixityCheck record because " +
			"because ExpectedFixityValue is missing from manifest.")
		helper.Manifest.RecordSummary.Finish()
		return
	}
	if helper.Manifest.ActualFixityValue == "" {
		helper.WorkSummary.AddError("Cannot create DPN FixityCheck record because " +
			"because ActualFixityValue is missing from manifest.")
		helper.Manifest.RecordSummary.Finish()
		return
	}
	if helper.Manifest.FixityCheck == nil {
		utcNow := time.Now().UTC()
		helper.Manifest.FixityCheck = &models.FixityCheck{
			FixityCheckId: uuid.NewV4().String(),
			Bag:           helper.Manifest.DPNBag.UUID,
			Node:          checker.Context.Config.DPN.LocalNode,
			Success:       helper.Manifest.ExpectedFixityValue == helper.Manifest.ActualFixityValue,
			FixityAt:      utcNow,
			CreatedAt:     utcNow,
		}
	}
	checker.Context.MessageLog.Info("Posting new fixity check %s for bag %s to %s",
		helper.Manifest.FixityCheck.FixityCheckId, helper.Manifest.DPNBag.UUID,
		checker.LocalDPNRestClient.HostUrl)
	resp := checker.LocalDPNRestClient.FixityCheckCreate(helper.Manifest.FixityCheck)
	if resp.Error != nil {
		helper.WorkSummary.AddError("Error saving FixityCheck to DPN REST server: %v",
			resp.Error)
		helper.Manifest.RecordSummary.Finish()
		return
	}
	helper.Manifest.FixityCheck.CreatedAt = resp.FixityCheck().CreatedAt
	helper.Manifest.FixityCheckSavedAt = time.Now().UTC()
	if helper.Manifest.CheckCompletedAndFailed() {
		helper.WorkSummary.AddError(
			"Fixity check completed, and fixity record %s was saved to DPN. "+
				"Actual fixity value %s does not match expected fixity %s",
			helper.Manifest.FixityCheck.FixityCheckId,
			helper.Manifest.ActualFixityValue, helper.Manifest.ExpectedFixityValue)
		helper.WorkSummary.ErrorIsFatal = true
	}
	helper.Manifest.RecordSummary.Finish()
}

func (checker *DPNFixityChecker) FinishWithSuccess(helper *DPNRestoreHelper) {
	helper.Manifest.DPNWorkItem.ClearNodeAndPid()
	checker.Context.MessageLog.Info("Completed fixity check for %s. Saved to DPN with FixityCheckId %s",
		helper.Manifest.DPNBag.UUID, helper.Manifest.FixityCheck.FixityCheckId)
	note := fmt.Sprintf("Fixity check complete. Saved to DPN with FixityCheckId %s",
		helper.Manifest.FixityCheck.FixityCheckId)
	helper.Manifest.DPNWorkItem.Note = &note
	// TODO: To repurpose this code to support restoration,
	// branch here. If DPNWorkItem.Task is fixity check,
	// set Status to Success. If Task is restore, set Stage
	// to StageRestoring, status to StatusPending, and push the
	// bag into the restoration queue, or do whatever else is
	// necessary to complete the restore process.
	helper.WorkSummary.Finish()
	helper.Manifest.DPNWorkItem.Stage = constants.StageResolve
	helper.Manifest.DPNWorkItem.Status = constants.StatusSuccess
	helper.SaveDPNWorkItem()
	helper.Manifest.NsqMessage.Finish()
}

func (checker *DPNFixityChecker) FinishWithError(helper *DPNRestoreHelper) {
	helper.Manifest.DPNWorkItem.ClearNodeAndPid()
	// Copy errors into the DPNWorkItem note, so we can see them in
	// the Pharos UI.
	errors := helper.WorkSummary.AllErrorsAsString()
	helper.Manifest.DPNWorkItem.Note = &errors
	checker.Context.MessageLog.Error(errors)
	helper.WorkSummary.Finish()
	if helper.WorkSummary.ErrorIsFatal {
		// Mark the DPNWorkItem as failed
		checker.Context.MessageLog.Error("Error for %s is fatal. Not requeueing.",
			helper.Manifest.DPNWorkItem.Identifier)
		helper.Manifest.DPNWorkItem.Status = constants.StatusFailed
		helper.Manifest.DPNWorkItem.Retry = false
		helper.SaveDPNWorkItem()
		helper.Manifest.NsqMessage.Finish()
	} else {
		// Transient errors. Retry DPNWorkItem.
		// MINUTES_BETWEEN_RETRIES is defined in dpn_s3_retriever.go
		helper.Manifest.DPNWorkItem.Retry = true
		helper.SaveDPNWorkItem()
		helper.Manifest.NsqMessage.Requeue(MINUTES_BETWEEN_RETRIES * time.Minute)
	}
}
<|endoftext|>


<commit_before>package reflect

import (
	"io"
	"net/http"
	"net/url"
	"time"

	"appengine"
	"appengine/urlfetch"
)

const forwardURL = "http://meek.bamsoftware.com:7443/"
// A timeout of 0 means to use the App Engine default (5 seconds).
const urlFetchTimeout = 10 * time.Second
var context appengine.Context

func pathJoin(a, b string) string {
	if len(a) > 0 && a[len(a)-1] == '/' {
		a = a[:len(a)-1]
	}
	if len(b) == 0 || b[0] != '/' {
		b = "/" + b
	}
	return a + b
}

// We reflect only a whitelisted set of header fields. In requests, the full
// list includes things like User-Agent and X-Appengine-Country that the Tor
// bridge doesn't need to know. In responses, there may be things like
// Transfer-Encoding that interfere with App Engine's own hop-by-hop headers.
var reflectedHeaderFields = []string{
	"Content-Type",
	"X-Session-Id",
}

func copyRequest(r *http.Request) (*http.Request, error) {
	u, err := url.Parse(forwardURL)
	if err != nil {
		return nil, err
	}
	u.Path = pathJoin(u.Path, r.URL.Path)
	c, err := http.NewRequest(r.Method, u.String(), r.Body)
	if err != nil {
		return nil, err
	}
	for _, key := range reflectedHeaderFields {
		value := r.Header.Get(key)
		if value != "" {
			c.Header.Add(key, value)
		}
	}
	return c, nil
}

func handler(w http.ResponseWriter, r *http.Request) {
	context = appengine.NewContext(r)
	fr, err := copyRequest(r)
	if err != nil {
		context.Errorf("copyRequest: %s", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	transport := urlfetch.Transport{
		Context: context,
		// Despite the name, Transport.Deadline is really a timeout and
		// not an absolute deadline as used in the net package. In
		// other words it is a time.Duration, not a time.Time.
		Deadline: urlFetchTimeout,
	}
	resp, err := transport.RoundTrip(fr)
	if err != nil {
		context.Errorf("RoundTrip: %s", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer resp.Body.Close()
	for _, key := range reflectedHeaderFields {
		value := resp.Header.Get(key)
		if value != "" {
			w.Header().Add(key, value)
		}
	}
	w.WriteHeader(resp.StatusCode)
	n, err := io.Copy(w, resp.Body)
	if err != nil {
		context.Errorf("io.Copy after %d bytes: %s", n, err)
	}
}

func init() {
	http.HandleFunc("/", handler)
}
<commit_msg>Oops, misedited URL.<commit_after>package reflect

import (
	"io"
	"net/http"
	"net/url"
	"time"

	"appengine"
	"appengine/urlfetch"
)

const forwardURL = "http://meek.bamsoftware.com:7002/"
// A timeout of 0 means to use the App Engine default (5 seconds).
const urlFetchTimeout = 10 * time.Second
var context appengine.Context

func pathJoin(a, b string) string {
	if len(a) > 0 && a[len(a)-1] == '/' {
		a = a[:len(a)-1]
	}
	if len(b) == 0 || b[0] != '/' {
		b = "/" + b
	}
	return a + b
}

// We reflect only a whitelisted set of header fields. In requests, the full
// list includes things like User-Agent and X-Appengine-Country that the Tor
// bridge doesn't need to know. In responses, there may be things like
// Transfer-Encoding that interfere with App Engine's own hop-by-hop headers.
var reflectedHeaderFields = []string{
	"Content-Type",
	"X-Session-Id",
}

func copyRequest(r *http.Request) (*http.Request, error) {
	u, err := url.Parse(forwardURL)
	if err != nil {
		return nil, err
	}
	u.Path = pathJoin(u.Path, r.URL.Path)
	c, err := http.NewRequest(r.Method, u.String(), r.Body)
	if err != nil {
		return nil, err
	}
	for _, key := range reflectedHeaderFields {
		value := r.Header.Get(key)
		if value != "" {
			c.Header.Add(key, value)
		}
	}
	return c, nil
}

func handler(w http.ResponseWriter, r *http.Request) {
	context = appengine.NewContext(r)
	fr, err := copyRequest(r)
	if err != nil {
		context.Errorf("copyRequest: %s", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	transport := urlfetch.Transport{
		Context: context,
		// Despite the name, Transport.Deadline is really a timeout and
		// not an absolute deadline as used in the net package. In
		// other words it is a time.Duration, not a time.Time.
		Deadline: urlFetchTimeout,
	}
	resp, err := transport.RoundTrip(fr)
	if err != nil {
		context.Errorf("RoundTrip: %s", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer resp.Body.Close()
	for _, key := range reflectedHeaderFields {
		value := resp.Header.Get(key)
		if value != "" {
			w.Header().Add(key, value)
		}
	}
	w.WriteHeader(resp.StatusCode)
	n, err := io.Copy(w, resp.Body)
	if err != nil {
		context.Errorf("io.Copy after %d bytes: %s", n, err)
	}
}

func init() {
	http.HandleFunc("/", handler)
}
<|endoftext|>


<commit_before>package assert

import (
	"fmt"
	"reflect"
	"runtime"
	"strings"
	"testing"
)

/*
	Helper functions
*/

// ObjectsAreEqual determines if two objects are considered equal.
//
// This function does no assertion of any kind.
func ObjectsAreEqual(a, b interface{}) bool {

	if reflect.DeepEqual(a, b) {
		return true
	}

	if reflect.ValueOf(a) == reflect.ValueOf(b) {
		return true
	}

	// Last ditch effort
	if fmt.Sprintf("%#v", a) == fmt.Sprintf("%#v", b) {
		return true
	}

	return false

}

/* CallerInfo is necessary because the assert functions use the testing object
internally, causing it to print the file:line of the assert method, rather than where
the problem actually occured in calling code.*/

// CallerInfo returns a string containing the file and line number of the assert call
// that failed.
func CallerInfo() string {

	file := ""
	line := 0
	ok := false

	for i := 0; ; i++ {
		_, file, line, ok = runtime.Caller(i)
		if !ok {
			return ""
		}
		parts := strings.Split(file, "/")
		dir := parts[len(parts)-2]
		file = parts[len(parts)-1]
		if (dir != "assert" && dir != "mock") || file == "mock_test.go" {
			break
		}
	}

	return fmt.Sprintf("%s:%d", file, line)
}

// getWhitespaceString returns a string that is long enough to overwrite the default
// output from the go testing framework.
func getWhitespaceString() string {

	_, file, line, ok := runtime.Caller(1)
	if !ok {
		return ""
	}
	parts := strings.Split(file, "/")
	file = parts[len(parts)-1]

	return strings.Repeat(" ", len(fmt.Sprintf("%s:%d:      ", file, line)))

}

// Implements asserts that an object is implemented by the specified interface.
//
//    assert.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject")
func Implements(t *testing.T, interfaceObject interface{}, object interface{}, message ...string) bool {

	interfaceType := reflect.TypeOf(interfaceObject).Elem()

	if !reflect.TypeOf(object).Implements(interfaceType) {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tObject must implement: %v\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), interfaceType, message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tObject must implement: %v\n\r", getWhitespaceString(), CallerInfo(), interfaceType)
		}

		return false
	}

	return true

}

// IsType asserts that the specified objects are of the same type.
func IsType(t *testing.T, expectedType interface{}, object interface{}, message ...string) bool {

	if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tObject expected to be of type %v, but was %v\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), reflect.TypeOf(expectedType), reflect.TypeOf(object), message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tObject expected to be of type %v, but was %v\n\r", getWhitespaceString(), CallerInfo(), reflect.TypeOf(expectedType), reflect.TypeOf(object))
		}

		return false
	}

	return true
}

// Equal asserts that two objects are equal.
//
//    assert.Equal(t, 123, 123, "123 and 123 should be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func Equal(t *testing.T, a, b interface{}, message ...string) bool {

	if !ObjectsAreEqual(a, b) {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tNot equal: %#v != %#v\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), a, b, message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tNot equal: %#v != %#v\n\r", getWhitespaceString(), CallerInfo(), a, b)
		}

		return false
	}

	return true

}

// NotNil asserts that the specified object is not nil.
//
//    assert.NotNil(t, err, "err should be something")
//
// Returns whether the assertion was successful (true) or not (false).
func NotNil(t *testing.T, object interface{}, message ...string) bool {

	var success bool = true

	if object == nil {
		success = false
	} else if reflect.ValueOf(object).IsNil() {
		success = false
	}

	if !success {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tExpected not to be nil.\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tExpected not to be nil.\n\r", getWhitespaceString(), CallerInfo())
		}

	}

	return success
}

// Nil asserts that the specified object is nil.
//
//    assert.Nil(t, err, "err should be nothing")
//
// Returns whether the assertion was successful (true) or not (false).
func Nil(t *testing.T, object interface{}, message ...string) bool {

	if object == nil {
		return true
	} else if reflect.ValueOf(object).IsNil() {
		return true
	}

	if len(message) > 0 {
		t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tExpected nil, but got: %#v\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), object, message)
	} else {
		t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tExpected nil, but got: %#v\n\r", getWhitespaceString(), CallerInfo(), object)
	}

	return false
}

// True asserts that the specified value is true.
//
//    assert.True(t, myBool, "myBool should be true")
//
// Returns whether the assertion was successful (true) or not (false).
func True(t *testing.T, value bool, message ...string) bool {

	if value != true {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tShould be true\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tShould be true\n\r", getWhitespaceString(), CallerInfo())
		}

		return false
	}

	return true

}

// False asserts that the specified value is true.
//
//    assert.False(t, myBool, "myBool should be false")
//
// Returns whether the assertion was successful (true) or not (false).
func False(t *testing.T, value bool, message ...string) bool {

	if value != false {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tShould be false\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tShould be false\n\r", getWhitespaceString(), CallerInfo())
		}

		return false
	}

	return true

}

// NotEqual asserts that the specified values are NOT equal.
//
//    assert.NotEqual(t, obj1, obj2, "two objects shouldn't be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func NotEqual(t *testing.T, a, b interface{}, message ...string) bool {

	if ObjectsAreEqual(a, b) {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tShould not be equal.\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tShould not be equal.\n\r", getWhitespaceString(), CallerInfo())
		}

		return false
	}

	return true

}

// Contains asserts that the specified string contains the specified substring.
//
//    assert.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'")
//
// Returns whether the assertion was successful (true) or not (false).
func Contains(t *testing.T, s, contains string, message ...string) bool {

	if !strings.Contains(s, contains) {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\t\"%s\" does not contain \"%s\"\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), s, contains, message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\t\"%s\" does not contain \"%s\"\n\r", getWhitespaceString(), CallerInfo(), s, contains)
		}

		return false
	}

	return true

}

// NotContains asserts that the specified string does NOT contain the specified substring.
//
//    assert.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
//
// Returns whether the assertion was successful (true) or not (false).
func NotContains(t *testing.T, s, contains string, message ...string) bool {

	if strings.Contains(s, contains) {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\t\"%s\" should not contain \"%s\"\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), s, contains, message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\t\"%s\" should not contain \"%s\"\n\r", getWhitespaceString(), CallerInfo(), s, contains)
		}

		return false
	}

	return true

}

// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics
// methods, and represents a simple func that takes no arguments, and returns nothing.
type PanicTestFunc func()

// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
func didPanic(f PanicTestFunc) (bool, interface{}) {

	var didPanic bool = false
	var message interface{}
	func() {

		defer func() {
			if message = recover(); message != nil {
				didPanic = true
			}
		}()

		// call the target function
		f()

	}()

	return didPanic, message

}

// Panics asserts that the code inside the specified PanicTestFunc panics.
//
//   assert.Panics(t, func(){
//     GoCrazy()
//   }, "Calling GoCrazy() should panic")
//
// Returns whether the assertion was successful (true) or not (false).
func Panics(t *testing.T, f PanicTestFunc, message ...string) bool {

	if funcDidPanic, panicValue := didPanic(f); !funcDidPanic {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tfunc %#v should panic\n\r\tPanic value:\t%v\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), f, panicValue, message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tfunc %#v should panic\n\r\tPanic value:\t%v\n\r", getWhitespaceString(), CallerInfo(), f, panicValue)
		}
		return false
	}

	return true
}

// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
//
//   assert.NotPanics(t, func(){
//     RemainCalm()
//   }, "Calling RemainCalm() should NOT panic")
//
// Returns whether the assertion was successful (true) or not (false).
func NotPanics(t *testing.T, f PanicTestFunc, message ...string) bool {
	if funcDidPanic, panicValue := didPanic(f); funcDidPanic {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tfunc %#v should not panic\n\r\tPanic value:\t%v\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), f, panicValue, message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tfunc %#v should not panic\n\r\tPanic value:\t%v\n\r", getWhitespaceString(), CallerInfo(), f, panicValue)
		}

		return false
	}

	return true
}
<commit_msg>Add assert.Condition<commit_after>package assert

import (
	"fmt"
	"reflect"
	"runtime"
	"strings"
	"testing"
)

// Comparison a custom function that returns true on success and false on failure
type Comparison func() (success bool)

/*
	Helper functions
*/

// ObjectsAreEqual determines if two objects are considered equal.
//
// This function does no assertion of any kind.
func ObjectsAreEqual(a, b interface{}) bool {

	if reflect.DeepEqual(a, b) {
		return true
	}

	if reflect.ValueOf(a) == reflect.ValueOf(b) {
		return true
	}

	// Last ditch effort
	if fmt.Sprintf("%#v", a) == fmt.Sprintf("%#v", b) {
		return true
	}

	return false

}

/* CallerInfo is necessary because the assert functions use the testing object
internally, causing it to print the file:line of the assert method, rather than where
the problem actually occured in calling code.*/

// CallerInfo returns a string containing the file and line number of the assert call
// that failed.
func CallerInfo() string {

	file := ""
	line := 0
	ok := false

	for i := 0; ; i++ {
		_, file, line, ok = runtime.Caller(i)
		if !ok {
			return ""
		}
		parts := strings.Split(file, "/")
		dir := parts[len(parts)-2]
		file = parts[len(parts)-1]
		if (dir != "assert" && dir != "mock") || file == "mock_test.go" {
			break
		}
	}

	return fmt.Sprintf("%s:%d", file, line)
}

// getWhitespaceString returns a string that is long enough to overwrite the default
// output from the go testing framework.
func getWhitespaceString() string {

	_, file, line, ok := runtime.Caller(1)
	if !ok {
		return ""
	}
	parts := strings.Split(file, "/")
	file = parts[len(parts)-1]

	return strings.Repeat(" ", len(fmt.Sprintf("%s:%d:      ", file, line)))

}

// Implements asserts that an object is implemented by the specified interface.
//
//    assert.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject")
func Implements(t *testing.T, interfaceObject interface{}, object interface{}, message ...string) bool {

	interfaceType := reflect.TypeOf(interfaceObject).Elem()

	if !reflect.TypeOf(object).Implements(interfaceType) {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tObject must implement: %v\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), interfaceType, message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tObject must implement: %v\n\r", getWhitespaceString(), CallerInfo(), interfaceType)
		}

		return false
	}

	return true

}

// IsType asserts that the specified objects are of the same type.
func IsType(t *testing.T, expectedType interface{}, object interface{}, message ...string) bool {

	if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tObject expected to be of type %v, but was %v\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), reflect.TypeOf(expectedType), reflect.TypeOf(object), message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tObject expected to be of type %v, but was %v\n\r", getWhitespaceString(), CallerInfo(), reflect.TypeOf(expectedType), reflect.TypeOf(object))
		}

		return false
	}

	return true
}

// Equal asserts that two objects are equal.
//
//    assert.Equal(t, 123, 123, "123 and 123 should be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func Equal(t *testing.T, a, b interface{}, message ...string) bool {

	if !ObjectsAreEqual(a, b) {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tNot equal: %#v != %#v\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), a, b, message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tNot equal: %#v != %#v\n\r", getWhitespaceString(), CallerInfo(), a, b)
		}

		return false
	}

	return true

}

// NotNil asserts that the specified object is not nil.
//
//    assert.NotNil(t, err, "err should be something")
//
// Returns whether the assertion was successful (true) or not (false).
func NotNil(t *testing.T, object interface{}, message ...string) bool {

	var success bool = true

	if object == nil {
		success = false
	} else if reflect.ValueOf(object).IsNil() {
		success = false
	}

	if !success {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tExpected not to be nil.\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tExpected not to be nil.\n\r", getWhitespaceString(), CallerInfo())
		}

	}

	return success
}

// Nil asserts that the specified object is nil.
//
//    assert.Nil(t, err, "err should be nothing")
//
// Returns whether the assertion was successful (true) or not (false).
func Nil(t *testing.T, object interface{}, message ...string) bool {

	if object == nil {
		return true
	} else if reflect.ValueOf(object).IsNil() {
		return true
	}

	if len(message) > 0 {
		t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tExpected nil, but got: %#v\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), object, message)
	} else {
		t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tExpected nil, but got: %#v\n\r", getWhitespaceString(), CallerInfo(), object)
	}

	return false
}

// True asserts that the specified value is true.
//
//    assert.True(t, myBool, "myBool should be true")
//
// Returns whether the assertion was successful (true) or not (false).
func True(t *testing.T, value bool, message ...string) bool {

	if value != true {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tShould be true\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tShould be true\n\r", getWhitespaceString(), CallerInfo())
		}

		return false
	}

	return true

}

// False asserts that the specified value is true.
//
//    assert.False(t, myBool, "myBool should be false")
//
// Returns whether the assertion was successful (true) or not (false).
func False(t *testing.T, value bool, message ...string) bool {

	if value != false {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tShould be false\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tShould be false\n\r", getWhitespaceString(), CallerInfo())
		}

		return false
	}

	return true

}

// NotEqual asserts that the specified values are NOT equal.
//
//    assert.NotEqual(t, obj1, obj2, "two objects shouldn't be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func NotEqual(t *testing.T, a, b interface{}, message ...string) bool {

	if ObjectsAreEqual(a, b) {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tShould not be equal.\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tShould not be equal.\n\r", getWhitespaceString(), CallerInfo())
		}

		return false
	}

	return true

}

// Contains asserts that the specified string contains the specified substring.
//
//    assert.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'")
//
// Returns whether the assertion was successful (true) or not (false).
func Contains(t *testing.T, s, contains string, message ...string) bool {

	if !strings.Contains(s, contains) {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\t\"%s\" does not contain \"%s\"\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), s, contains, message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\t\"%s\" does not contain \"%s\"\n\r", getWhitespaceString(), CallerInfo(), s, contains)
		}

		return false
	}

	return true

}

// NotContains asserts that the specified string does NOT contain the specified substring.
//
//    assert.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
//
// Returns whether the assertion was successful (true) or not (false).
func NotContains(t *testing.T, s, contains string, message ...string) bool {

	if strings.Contains(s, contains) {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\t\"%s\" should not contain \"%s\"\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), s, contains, message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\t\"%s\" should not contain \"%s\"\n\r", getWhitespaceString(), CallerInfo(), s, contains)
		}

		return false
	}

	return true

}

// Uses a Comparison to assert a complex condition.
func Condition(t *testing.T, comp Comparison, message ...string) bool {
	result := comp()
	if !result {
		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tCondition failed!\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tCondition failed!\n\r", getWhitespaceString(), CallerInfo())
		}
	}
	return result
}

// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics
// methods, and represents a simple func that takes no arguments, and returns nothing.
type PanicTestFunc func()

// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
func didPanic(f PanicTestFunc) (bool, interface{}) {

	var didPanic bool = false
	var message interface{}
	func() {

		defer func() {
			if message = recover(); message != nil {
				didPanic = true
			}
		}()

		// call the target function
		f()

	}()

	return didPanic, message

}

// Panics asserts that the code inside the specified PanicTestFunc panics.
//
//   assert.Panics(t, func(){
//     GoCrazy()
//   }, "Calling GoCrazy() should panic")
//
// Returns whether the assertion was successful (true) or not (false).
func Panics(t *testing.T, f PanicTestFunc, message ...string) bool {

	if funcDidPanic, panicValue := didPanic(f); !funcDidPanic {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tfunc %#v should panic\n\r\tPanic value:\t%v\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), f, panicValue, message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tfunc %#v should panic\n\r\tPanic value:\t%v\n\r", getWhitespaceString(), CallerInfo(), f, panicValue)
		}
		return false
	}

	return true
}

// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
//
//   assert.NotPanics(t, func(){
//     RemainCalm()
//   }, "Calling RemainCalm() should NOT panic")
//
// Returns whether the assertion was successful (true) or not (false).
func NotPanics(t *testing.T, f PanicTestFunc, message ...string) bool {
	if funcDidPanic, panicValue := didPanic(f); funcDidPanic {

		if len(message) > 0 {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tfunc %#v should not panic\n\r\tPanic value:\t%v\n\r\tMessages:\t%s\n\r", getWhitespaceString(), CallerInfo(), f, panicValue, message)
		} else {
			t.Errorf("\r%s\r\tLocation:\t%s\n\r\tError:\t\tfunc %#v should not panic\n\r\tPanic value:\t%v\n\r", getWhitespaceString(), CallerInfo(), f, panicValue)
		}

		return false
	}

	return true
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"net/http"
	"os"
	"runtime"

	"github.com/safchain/ethtool"
	"github.com/vishvananda/netlink"
	"github.com/appc/cni/pkg/ip"
	"github.com/appc/cni/pkg/ipam"
	"github.com/appc/cni/pkg/ns"
	"github.com/appc/cni/pkg/skel"
	"github.com/appc/cni/pkg/types"
	"github.com/appc/cni/pkg/utils"
)

// Adding additional configuration for EVPN - importRT and exportRT
type NetConf struct {
	types.NetConf
	ImportRT string `json:"importrt"`
	ExportRT string `json:"exportrt"`
	IsGW     bool   `json:"isGateway"`
	IPMasq   bool   `json:"ipMasq"`
	MTU      int    `json:"mtu"`
}

func init() {
	// this ensures that main runs only on main thread (thread group leader).
	// since namespace ops (unshare, setns) are done for a single thread, we
	// must ensure that the goroutine does not jump from OS thread to thread
	runtime.LockOSThread()
}

func loadNetConf(bytes []byte) (*NetConf, error) {
	n := &NetConf{
		MTU: 1500,
	}
	if err := json.Unmarshal(bytes, n); err != nil {
		return nil, fmt.Errorf("failed to load netconf: %v", err)
	}
	return n, nil
}

func createBGPConf(n *NetConf, LocalPort string, gw string, ipa string, mac string) (b []byte, err error) {

	// JSON payload struct for bagpipeBGP
	type Message struct {
		Import_rt        []string         `json:"import_rt"`
		Vpn_type         string           `json:"vpn_type"`
		Vpn_instance_id  string           `json:"vpn_instance_id"`
		Ip_address       string           `json:"ip_address"`
		Export_rt        []string         `json:"export_rt"`
		Local_port       *json.RawMessage `json:"local_port"`
		Readvertise      string           `json:"readvertise"`
		Gateway_ip       string           `json:"gateway_ip"`
		Mac_address      string           `json:"mac_address"`
		Advertise_subnet bool             `json:"advertise_subnet"`
	}

	// Linuxif Raw JSON object
	type LcPorts struct {
		LinuxIf string `json:"linuxif"`
	}

	tmp := LcPorts{LocalPort}
	l, err := json.Marshal(tmp)
	LcPort := json.RawMessage(l)

	Imports := []string{n.ImportRT}
	Exports := []string{n.ExportRT}

	m := Message{
		Import_rt:        Imports,
		Vpn_type:         "evpn",
		Vpn_instance_id:  LocalPort,
		Ip_address:       ipa,
		Export_rt:        Exports,
		Local_port:       &LcPort,
		Gateway_ip:       gw,
		Mac_address:      mac,
		Advertise_subnet: false,
	}

	b, err = json.Marshal(m)
	return b, err
}

func sendBagpipeReq(n *NetConf, Request string, LocalPort string, gw string, ipa string, mac string) error {
	// send json payload
	url := fmt.Sprintf("http://127.0.0.1:8082/%s_localport", Request)

	var jsonStr []byte
	// create JSON object for BagpipeBGP
	jsonStr, err := createBGPConf(n, LocalPort, gw, ipa, mac)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))

	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)

	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()
	return err
}

func setupVeth(netns string, ifName string, mtu int) (contMacAddr string, hostVethName string, err error) {

	err = ns.WithNetNSPath(netns, false, func(hostNS *os.File) error {
		// create the veth pair in the container and move host end into host netns
		hostVeth, _, err := ip.SetupVeth(ifName, mtu, hostNS)
		if err != nil {
			return nil
		}

		hostVethName = hostVeth.Attrs().Name
		interfaces, _ := net.Interfaces()

		// Lookup MAC address of eth0 inside namespace
		for _, inter := range interfaces {
			if inter.Name != "lo" {
				contMacAddr = fmt.Sprintf("%v", inter.HardwareAddr)
			}

		}
		return nil
	})
	if err != nil {
		return contMacAddr, hostVethName, err
	}

	if err != nil {
		return contMacAddr, hostVethName, fmt.Errorf("failed to lookup %q: %v", hostVethName, err)
	}

	return contMacAddr, hostVethName, err
}

func calcGatewayIP(ipn *net.IPNet) net.IP {
	nid := ipn.IP.Mask(ipn.Mask)
	return ip.NextIP(nid)
}

func cmdAdd(args *skel.CmdArgs) error {
	n, err := loadNetConf(args.StdinData)
	if err != nil {
		return err
	}
	var vethName string
	var macAddr string

	if macAddr, vethName, err = setupVeth(args.Netns, args.IfName, n.MTU); err != nil {
		return err
	}

	// run the IPAM plugin and get back the config to apply
	result, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
	if err != nil {
		return err
	}

	if result.IP4 == nil {
		return errors.New("IPAM plugin returned missing IPv4 config")
	}

	if result.IP4.Gateway == nil && n.IsGW {
		result.IP4.Gateway = calcGatewayIP(&result.IP4.IP)
	}

	err = ns.WithNetNSPath(args.Netns, false, func(hostNS *os.File) error {
		return ipam.ConfigureIface(args.IfName, result)
	})
	if err != nil {
		return err
	}

	if n.IPMasq {
		chain := utils.FormatChainName(n.Name, args.ContainerID)
		comment := utils.FormatComment(n.Name, args.ContainerID)
		if err = ip.SetupIPMasq(ip.Network(&result.IP4.IP), chain, comment); err != nil {
			return err
		}
	}

	var ip_gw, ip_addr string

	ip_gw = fmt.Sprintf("%v", &result.IP4.Gateway)
	ip_addr = fmt.Sprintf("%v", &result.IP4.IP)

	sendBagpipeReq(n, "attach", vethName, ip_gw, ip_addr, macAddr)

	result.DNS = n.DNS
	return result.Print()
}

func cmdDel(args *skel.CmdArgs) error {

	// bagpipe detach should be implemented
	n, err := loadNetConf(args.StdinData)
	if err != nil {
		return err
	}

	err = ipam.ExecDel(n.IPAM.Type, args.StdinData)
	if err != nil {
		return err
	}

	var contMacAddr string
	var hostVethName string
	var ip_gw string
	var ip_addr string
	var if_index uint64

	err = ns.WithNetNSPath(args.Netns, false, func(hostNS *os.File) error {
		link, _ := netlink.LinkByName(args.IfName)

		// Getting container MAC address
		contMacAddr =fmt.Sprintf("%s", link.Attrs().HardwareAddr)
		// Getting container IP address, should be rewritten PoC
		cont_IP, _ := netlink.AddrList(link, netlink.FAMILY_V4)
		ip_addr = fmt.Sprintf("%s", cont_IP[0].IPNet.IP)

		// Getting peer interface index in Root namespace
		stats, _ := ethtool.Stats(args.IfName)
		if_index = stats["peer_ifindex"]

		// Getting default gateway address - should be rewritten PoC
		gw_route, _ := netlink.RouteGet(net.ParseIP("1.2.3.4"))
		ip_gw = fmt.Sprintf("%s", gw_route[0].Gw)

		return nil
	})

	// Getting hostlink based on if_index in Root NS
	hostlink, _ := netlink.LinkByIndex(int(if_index))
	hostVethName = hostlink.Attrs().Name

	// Dettaching the route from BaGPipe BGP
	sendBagpipeReq(n, "detach", hostVethName, ip_gw, ip_addr, contMacAddr)
	// Removing the link
	return ip.DelLinkByName(hostVethName)
}

func main() {
	skel.PluginMain(cmdAdd, cmdDel)
}
<commit_msg>DelCMD prefix for the mask<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"net/http"
	"os"
	"runtime"

	"github.com/appc/cni/pkg/ip"
	"github.com/appc/cni/pkg/ipam"
	"github.com/appc/cni/pkg/ns"
	"github.com/appc/cni/pkg/skel"
	"github.com/appc/cni/pkg/types"
	"github.com/appc/cni/pkg/utils"
	"github.com/safchain/ethtool"
	"github.com/vishvananda/netlink"
)

// Adding additional configuration for EVPN - importRT and exportRT
type NetConf struct {
	types.NetConf
	ImportRT string `json:"importrt"`
	ExportRT string `json:"exportrt"`
	IsGW     bool   `json:"isGateway"`
	IPMasq   bool   `json:"ipMasq"`
	MTU      int    `json:"mtu"`
}

func init() {
	// this ensures that main runs only on main thread (thread group leader).
	// since namespace ops (unshare, setns) are done for a single thread, we
	// must ensure that the goroutine does not jump from OS thread to thread
	runtime.LockOSThread()
}

func loadNetConf(bytes []byte) (*NetConf, error) {
	n := &NetConf{
		MTU: 1500,
	}
	if err := json.Unmarshal(bytes, n); err != nil {
		return nil, fmt.Errorf("failed to load netconf: %v", err)
	}
	return n, nil
}

func createBGPConf(n *NetConf, LocalPort string, gw string, ipa string, mac string) (b []byte, err error) {

	// JSON payload struct for bagpipeBGP
	type Message struct {
		Import_rt        []string         `json:"import_rt"`
		Vpn_type         string           `json:"vpn_type"`
		Vpn_instance_id  string           `json:"vpn_instance_id"`
		Ip_address       string           `json:"ip_address"`
		Export_rt        []string         `json:"export_rt"`
		Local_port       *json.RawMessage `json:"local_port"`
		Readvertise      string           `json:"readvertise"`
		Gateway_ip       string           `json:"gateway_ip"`
		Mac_address      string           `json:"mac_address"`
		Advertise_subnet bool             `json:"advertise_subnet"`
	}

	// Linuxif Raw JSON object
	type LcPorts struct {
		LinuxIf string `json:"linuxif"`
	}

	tmp := LcPorts{LocalPort}
	l, err := json.Marshal(tmp)
	LcPort := json.RawMessage(l)

	Imports := []string{n.ImportRT}
	Exports := []string{n.ExportRT}

	m := Message{
		Import_rt:        Imports,
		Vpn_type:         "evpn",
		Vpn_instance_id:  LocalPort,
		Ip_address:       ipa,
		Export_rt:        Exports,
		Local_port:       &LcPort,
		Gateway_ip:       gw,
		Mac_address:      mac,
		Advertise_subnet: false,
	}

	b, err = json.Marshal(m)
	return b, err
}

func sendBagpipeReq(n *NetConf, Request string, LocalPort string, gw string, ipa string, mac string) error {
	// send json payload
	url := fmt.Sprintf("http://127.0.0.1:8082/%s_localport", Request)

	var jsonStr []byte
	// create JSON object for BagpipeBGP
	jsonStr, err := createBGPConf(n, LocalPort, gw, ipa, mac)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))

	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)

	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()
	return err
}

func setupVeth(netns string, ifName string, mtu int) (contMacAddr string, hostVethName string, err error) {

	err = ns.WithNetNSPath(netns, false, func(hostNS *os.File) error {
		// create the veth pair in the container and move host end into host netns
		hostVeth, _, err := ip.SetupVeth(ifName, mtu, hostNS)
		if err != nil {
			return nil
		}

		hostVethName = hostVeth.Attrs().Name
		interfaces, _ := net.Interfaces()

		// Lookup MAC address of eth0 inside namespace
		for _, inter := range interfaces {
			if inter.Name != "lo" {
				contMacAddr = fmt.Sprintf("%v", inter.HardwareAddr)
			}

		}
		return nil
	})
	if err != nil {
		return contMacAddr, hostVethName, err
	}

	if err != nil {
		return contMacAddr, hostVethName, fmt.Errorf("failed to lookup %q: %v", hostVethName, err)
	}

	return contMacAddr, hostVethName, err
}

func calcGatewayIP(ipn *net.IPNet) net.IP {
	nid := ipn.IP.Mask(ipn.Mask)
	return ip.NextIP(nid)
}

func cmdAdd(args *skel.CmdArgs) error {
	n, err := loadNetConf(args.StdinData)
	if err != nil {
		return err
	}
	var vethName string
	var macAddr string

	if macAddr, vethName, err = setupVeth(args.Netns, args.IfName, n.MTU); err != nil {
		return err
	}

	// run the IPAM plugin and get back the config to apply
	result, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
	if err != nil {
		return err
	}

	if result.IP4 == nil {
		return errors.New("IPAM plugin returned missing IPv4 config")
	}

	if result.IP4.Gateway == nil && n.IsGW {
		result.IP4.Gateway = calcGatewayIP(&result.IP4.IP)
	}

	err = ns.WithNetNSPath(args.Netns, false, func(hostNS *os.File) error {
		return ipam.ConfigureIface(args.IfName, result)
	})
	if err != nil {
		return err
	}

	if n.IPMasq {
		chain := utils.FormatChainName(n.Name, args.ContainerID)
		comment := utils.FormatComment(n.Name, args.ContainerID)
		if err = ip.SetupIPMasq(ip.Network(&result.IP4.IP), chain, comment); err != nil {
			return err
		}
	}

	var ip_gw, ip_addr string

	ip_gw = fmt.Sprintf("%v", &result.IP4.Gateway)
	ip_addr = fmt.Sprintf("%v", &result.IP4.IP)

	sendBagpipeReq(n, "attach", vethName, ip_gw, ip_addr, macAddr)

	result.DNS = n.DNS
	return result.Print()
}

func cmdDel(args *skel.CmdArgs) error {

	// bagpipe detach should be implemented
	n, err := loadNetConf(args.StdinData)
	if err != nil {
		return err
	}

	err = ipam.ExecDel(n.IPAM.Type, args.StdinData)
	if err != nil {
		return err
	}

	var contMacAddr string
	var hostVethName string
	var ip_gw string
	var ip_addr string
	var if_index uint64

	err = ns.WithNetNSPath(args.Netns, false, func(hostNS *os.File) error {
		link, _ := netlink.LinkByName(args.IfName)

		// Getting container MAC address
		contMacAddr = fmt.Sprintf("%s", link.Attrs().HardwareAddr)
		// Getting container IP address, should be rewritten PoC
		cont_IP, _ := netlink.AddrList(link, netlink.FAMILY_V4)
		prefix, _ := cont_IP[0].IPNet.Mask.Size()
		ip_addr = fmt.Sprintf("%s/%d", cont_IP[0].IPNet.IP, prefix)

		// Getting peer interface index in Root namespace
		stats, _ := ethtool.Stats(args.IfName)
		if_index = stats["peer_ifindex"]

		// Getting default gateway address - should be rewritten PoC
		gw_route, _ := netlink.RouteGet(net.ParseIP("1.2.3.4"))
		ip_gw = fmt.Sprintf("%s", gw_route[0].Gw)

		return nil
	})

	// Getting hostlink based on if_index in Root NS
	hostlink, _ := netlink.LinkByIndex(int(if_index))
	hostVethName = hostlink.Attrs().Name

	// Dettaching the route from BaGPipe BGP
	sendBagpipeReq(n, "detach", hostVethName, ip_gw, ip_addr, contMacAddr)
	// Removing the link
	return ip.DelLinkByName(hostVethName)
}

func main() {
	skel.PluginMain(cmdAdd, cmdDel)
}
<|endoftext|>


<commit_before>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"
	"strings"

	fct "github.com/FactomProject/factoid"
	"github.com/FactomProject/factom"
	"github.com/FactomProject/fctwallet/Wallet/Utility"
)

// balance prints the current balance of the specified address
func balance(args []string) error {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 2 {
		fmt.Println("Too few arguments")
		man("balance")
		return fmt.Errorf("Too Few Arguments")
	}

	switch args[0] {
	case "ec":
		return ecbalance(args[1])
	case "fct":
		return fctbalance(args[1])
	default:
		fmt.Println("Must specify an address type, either 'ec' or 'fct'")
		man("balance")
		return fmt.Errorf("")
	}

}

func ecbalance(addr string) error {
	if Utility.IsValidAddress(addr) && strings.HasPrefix(addr,"FA") {
		fmt.Println("Not a valid Entry Credit Address")
		return fmt.Errorf("Not a valid Entry Credit Address")
	}
	if b, err := factom.ECBalance(addr); err != nil {
		fmt.Println("Address undefined or invalid")
		return err
	} else {
		fmt.Println("Balance of ", addr, " = ", b)
	}

	return nil
}

func fctbalance(addr string) error {
	if Utility.IsValidAddress(addr) && strings.HasPrefix(addr,"EC") {
		fmt.Println("Not a valid Entry Credit Address")
		return fmt.Errorf("Not a valid Entry Credit Address")
	}

	if b, err := factom.FctBalance(addr); err != nil {
		fmt.Println("Address undefined or invalid")
		return err
	} else {
		fmt.Println("Balance of ", addr, " = ", fct.ConvertDecimal(uint64(b)))
	}

	return nil
}
<commit_msg>message fix for Issue #746<commit_after>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"
	"strings"

	fct "github.com/FactomProject/factoid"
	"github.com/FactomProject/factom"
	"github.com/FactomProject/fctwallet/Wallet/Utility"
)

// balance prints the current balance of the specified address
func balance(args []string) error {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 2 {
		fmt.Println("Too few arguments")
		man("balance")
		return fmt.Errorf("Too Few Arguments")
	}

	switch args[0] {
	case "ec":
		return ecbalance(args[1])
	case "fct":
		return fctbalance(args[1])
	default:
		fmt.Println("Must specify an address type, either 'ec' or 'fct'")
		man("balance")
		return fmt.Errorf("")
	}

}

func ecbalance(addr string) error {
	if Utility.IsValidAddress(addr) && strings.HasPrefix(addr,"FA") {
		fmt.Println("Not a valid Entry Credit Address")
		return fmt.Errorf("Not a valid Entry Credit Address")
	}
	if b, err := factom.ECBalance(addr); err != nil {
		fmt.Println("Address undefined or invalid")
		return err
	} else {
		fmt.Println("Balance of ", addr, " = ", b)
	}

	return nil
}

func fctbalance(addr string) error {
	if Utility.IsValidAddress(addr) && strings.HasPrefix(addr,"EC") {
		fmt.Println("Not a valid Entry Credit Address")
		return fmt.Errorf("Not a valid Entry Credit Address")
	}

	if b, err := factom.FctBalance(addr); err != nil {
		fmt.Println("Address undefined or invalid: "+err.Error())
		return err
	} else {
		fmt.Println("Balance of ", addr, " = ", fct.ConvertDecimal(uint64(b)))
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2009 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.

// +build linux
// +build power64 power64le

package syscall

//sys	Chown(path string, uid int, gid int) (err error)
//sys	Fchown(fd int, uid int, gid int) (err error)
//sys	Fstat(fd int, stat *Stat_t) (err error)
//sys	Fstatfs(fd int, buf *Statfs_t) (err error)
//sys	Ftruncate(fd int, length int64) (err error)
//sysnb	Getegid() (egid int)
//sysnb	Geteuid() (euid int)
//sysnb	Getgid() (gid int)
//sysnb	Getrlimit(resource int, rlim *Rlimit) (err error) = SYS_UGETRLIMIT
//sysnb	Getuid() (uid int)
//sys	Ioperm(from int, num int, on int) (err error)
//sys	Iopl(level int) (err error)
//sys	Lchown(path string, uid int, gid int) (err error)
//sys	Listen(s int, n int) (err error)
//sys	Lstat(path string, stat *Stat_t) (err error)
//sys	Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
//sys	Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
//sys	Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK
//sys	Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
//sys	sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
//sys	Setfsgid(gid int) (err error)
//sys	Setfsuid(uid int) (err error)
//sysnb	Setregid(rgid int, egid int) (err error)
//sysnb	Setresgid(rgid int, egid int, sgid int) (err error)
//sysnb	Setresuid(ruid int, euid int, suid int) (err error)
//sysnb	Setrlimit(resource int, rlim *Rlimit) (err error)
//sysnb	Setreuid(ruid int, euid int) (err error)
//sys	Shutdown(fd int, how int) (err error)
//sys	Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
//sys	Stat(path string, stat *Stat_t) (err error)
//sys	Statfs(path string, buf *Statfs_t) (err error)
//sys	SyncFileRange(fd int, off int64, n int64, flags int) (err error) = SYS_SYNC_FILE_RANGE2
//sys	Truncate(path string, length int64) (err error)
//sys	accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
//sys	accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
//sys	bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
//sys	connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
//sysnb	getgroups(n int, list *_Gid_t) (nn int, err error)
//sysnb	setgroups(n int, list *_Gid_t) (err error)
//sys	getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
//sys	setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
//sysnb	socket(domain int, typ int, proto int) (fd int, err error)
//sysnb	socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
//sysnb	getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sysnb	getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sys	recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
//sys	sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
//sys	recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
//sys	sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
//sys	mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)

func Getpagesize() int { return 4096 }

//sysnb	Gettimeofday(tv *Timeval) (err error)
//sysnb	Time(t *Time_t) (tt Time_t, err error)

func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }

func NsecToTimespec(nsec int64) (ts Timespec) {
	ts.Sec = nsec / 1e9
	ts.Nsec = nsec % 1e9
	return
}

func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }

func NsecToTimeval(nsec int64) (tv Timeval) {
	nsec += 999 // round up to microsecond
	tv.Sec = nsec / 1e9
	tv.Usec = nsec % 1e9 / 1e3
	return
}

func (r *PtraceRegs) PC() uint64 { return r.Nip }

func (r *PtraceRegs) SetPC(pc uint64) { r.Nip = pc }

func (iov *Iovec) SetLen(length int) {
	iov.Len = uint64(length)
}

func (msghdr *Msghdr) SetControllen(length int) {
	msghdr.Controllen = uint64(length)
}

func (cmsg *Cmsghdr) SetLen(length int) {
	cmsg.Len = uint64(length)
}
<commit_msg>[dev.power64] syscall: fix power64 page size<commit_after>// Copyright 2009 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.

// +build linux
// +build power64 power64le

package syscall

//sys	Chown(path string, uid int, gid int) (err error)
//sys	Fchown(fd int, uid int, gid int) (err error)
//sys	Fstat(fd int, stat *Stat_t) (err error)
//sys	Fstatfs(fd int, buf *Statfs_t) (err error)
//sys	Ftruncate(fd int, length int64) (err error)
//sysnb	Getegid() (egid int)
//sysnb	Geteuid() (euid int)
//sysnb	Getgid() (gid int)
//sysnb	Getrlimit(resource int, rlim *Rlimit) (err error) = SYS_UGETRLIMIT
//sysnb	Getuid() (uid int)
//sys	Ioperm(from int, num int, on int) (err error)
//sys	Iopl(level int) (err error)
//sys	Lchown(path string, uid int, gid int) (err error)
//sys	Listen(s int, n int) (err error)
//sys	Lstat(path string, stat *Stat_t) (err error)
//sys	Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
//sys	Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
//sys	Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK
//sys	Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
//sys	sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
//sys	Setfsgid(gid int) (err error)
//sys	Setfsuid(uid int) (err error)
//sysnb	Setregid(rgid int, egid int) (err error)
//sysnb	Setresgid(rgid int, egid int, sgid int) (err error)
//sysnb	Setresuid(ruid int, euid int, suid int) (err error)
//sysnb	Setrlimit(resource int, rlim *Rlimit) (err error)
//sysnb	Setreuid(ruid int, euid int) (err error)
//sys	Shutdown(fd int, how int) (err error)
//sys	Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
//sys	Stat(path string, stat *Stat_t) (err error)
//sys	Statfs(path string, buf *Statfs_t) (err error)
//sys	SyncFileRange(fd int, off int64, n int64, flags int) (err error) = SYS_SYNC_FILE_RANGE2
//sys	Truncate(path string, length int64) (err error)
//sys	accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
//sys	accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
//sys	bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
//sys	connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
//sysnb	getgroups(n int, list *_Gid_t) (nn int, err error)
//sysnb	setgroups(n int, list *_Gid_t) (err error)
//sys	getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
//sys	setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
//sysnb	socket(domain int, typ int, proto int) (fd int, err error)
//sysnb	socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
//sysnb	getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sysnb	getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
//sys	recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
//sys	sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
//sys	recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
//sys	sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
//sys	mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)

func Getpagesize() int { return 65536 }

//sysnb	Gettimeofday(tv *Timeval) (err error)
//sysnb	Time(t *Time_t) (tt Time_t, err error)

func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }

func NsecToTimespec(nsec int64) (ts Timespec) {
	ts.Sec = nsec / 1e9
	ts.Nsec = nsec % 1e9
	return
}

func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }

func NsecToTimeval(nsec int64) (tv Timeval) {
	nsec += 999 // round up to microsecond
	tv.Sec = nsec / 1e9
	tv.Usec = nsec % 1e9 / 1e3
	return
}

func (r *PtraceRegs) PC() uint64 { return r.Nip }

func (r *PtraceRegs) SetPC(pc uint64) { r.Nip = pc }

func (iov *Iovec) SetLen(length int) {
	iov.Len = uint64(length)
}

func (msghdr *Msghdr) SetControllen(length int) {
	msghdr.Controllen = uint64(length)
}

func (cmsg *Cmsghdr) SetLen(length int) {
	cmsg.Len = uint64(length)
}
<|endoftext|>


<commit_before>package asana

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
)

// A remote client to Asana
type Client struct {
	key string
	hc  http.Client
	Me  User
}

type Project struct {
	Id   int64
	Name string
}

type Task struct {
	Id             int64
	Name           string
	AssigneeStatus string `json:"assignee_status"`
	CreatedAt      string `json:"created_at"`
	Assignee       UserLite
	Completed      bool
	CompletedAt    string `json:"completed_at"`
	DueOn          string `json:"due_on"`
	Followers      []UserLite
	ModifiedAt     string `json:"modified_at"`
	Notes          string
	Projects       []Project
	Parent         *Task
	Workspace      WorkspaceLite
}

type WorkspaceLite struct {
	Id int64
}

type Workspace struct {
	WorkspaceLite
	Name string
}

type Photos struct {
	Image_21x21   string
	Image_27x27   string
	Image_36x36   string
	Image_60x60   string
	Image_128x128 string
}

type UserLite struct {
	Id   int64
	Name string
}

type User struct {
	UserLite
	Email      string
	Photos     Photos `json:"photo"`
	Workspaces []Workspace
}

// Created a new client with a specified API Key
func NewClient(key string) (Client, error) {
	c := Client{key, http.Client{}, User{}}
	me, err := c.User("me")
	if err != nil {
		return c, err
	}

	c.Me = me
	return c, nil
}

func (c Client) request(method string, uri string, body io.Reader) (*http.Request, error) {
	req, err := http.NewRequest(method, uri, body)
	if err != nil {
		return req, fmt.Errorf("Cannot create request %s %s", method, uri, err)
	}
	req.SetBasicAuth(c.key, "")
	return req, nil
}

// Fetch a user by id
func (a Client) User(id interface{}) (User, error) {
	ud := struct{ Data User }{}
	uri := fmt.Sprintf("https://app.asana.com/api/1.0/users/%v", id)
	req, err := a.request("GET", uri, nil)
	if err != nil {
		return ud.Data, err
	}

	resp, err := a.hc.Do(req)
	if err != nil {
		return ud.Data, fmt.Errorf("Cannot execute request GET %s: %s", uri, err)
	}

	if resp.StatusCode != 200 {
		return ud.Data, fmt.Errorf("Error response: %d", resp.StatusCode)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return ud.Data, fmt.Errorf("error reading body: %s", err)
	}
	err = json.Unmarshal(body, &ud)
	return ud.Data, err
}

func (c Client) Tasks(w Workspace) ([]Task, error) {
	url := fmt.Sprintf("https://app.asana.com/api/1.0/workspaces/%d/tasks?assignee=%d&opt_fields=assignee,assignee_status,created_at,completed,completed_at,due_on,followers,modified_at,name,projects,parent,workspace",
		w.Id, c.Me.Id)

	req, err := c.request("GET", url, nil)
	if err != nil {
		return nil, err
	}

	res, err := c.hc.Do(req)
	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, fmt.Errorf("error reading body: %s", err)
	}

	data := struct{ Data []Task }{}

	err = json.Unmarshal(body, &data)
	return data.Data, err
}

func (c Client) MyTasks() ([]Task, error) {
	url := fmt.Sprintf("https://app.asana.com/api/1.0/tasks?assignee=%d&opt_fields=assignee,assignee_status,created_at,completed,completed_at,due_on,followers,modified_at,name,projects,parent,workspace",
		c.Me.Id)

	req, err := c.request("GET", url, nil)
	if err != nil {
		return nil, err
	}

	res, err := c.hc.Do(req)
	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, fmt.Errorf("error reading body: %s", err)
	}

	data := struct{ Data []Task }{}

	err = json.Unmarshal(body, &data)
	return data.Data, err
}
<commit_msg>remove non-functioning MyTasks<commit_after>package asana

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
)

// A remote client to Asana
type Client struct {
	key string
	hc  http.Client
	Me  User
}

type Project struct {
	Id   int64
	Name string
}

type Task struct {
	Id             int64
	Name           string
	AssigneeStatus string `json:"assignee_status"`
	CreatedAt      string `json:"created_at"`
	Assignee       UserLite
	Completed      bool
	CompletedAt    string `json:"completed_at"`
	DueOn          string `json:"due_on"`
	Followers      []UserLite
	ModifiedAt     string `json:"modified_at"`
	Notes          string
	Projects       []Project
	Parent         *Task
	Workspace      WorkspaceLite
}

type WorkspaceLite struct {
	Id int64
}

type Workspace struct {
	WorkspaceLite
	Name string
}

type Photos struct {
	Image_21x21   string
	Image_27x27   string
	Image_36x36   string
	Image_60x60   string
	Image_128x128 string
}

type UserLite struct {
	Id   int64
	Name string
}

type User struct {
	UserLite
	Email      string
	Photos     Photos `json:"photo"`
	Workspaces []Workspace
}

// Created a new client with a specified API Key
func NewClient(key string) (Client, error) {
	c := Client{key, http.Client{}, User{}}
	me, err := c.User("me")
	if err != nil {
		return c, err
	}

	c.Me = me
	return c, nil
}

func (c Client) request(method string, uri string, body io.Reader) (*http.Request, error) {
	req, err := http.NewRequest(method, uri, body)
	if err != nil {
		return req, fmt.Errorf("Cannot create request %s %s", method, uri, err)
	}
	req.SetBasicAuth(c.key, "")
	return req, nil
}

// Fetch a user by id
func (a Client) User(id interface{}) (User, error) {
	ud := struct{ Data User }{}
	uri := fmt.Sprintf("https://app.asana.com/api/1.0/users/%v", id)
	req, err := a.request("GET", uri, nil)
	if err != nil {
		return ud.Data, err
	}

	resp, err := a.hc.Do(req)
	if err != nil {
		return ud.Data, fmt.Errorf("Cannot execute request GET %s: %s", uri, err)
	}

	if resp.StatusCode != 200 {
		return ud.Data, fmt.Errorf("Error response: %d", resp.StatusCode)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return ud.Data, fmt.Errorf("error reading body: %s", err)
	}
	err = json.Unmarshal(body, &ud)
	return ud.Data, err
}

func (c Client) Tasks(w Workspace) ([]Task, error) {
	url := fmt.Sprintf("https://app.asana.com/api/1.0/workspaces/%d/tasks?assignee=%d&opt_fields=assignee,assignee_status,created_at,completed,completed_at,due_on,followers,modified_at,name,projects,parent,workspace",
		w.Id, c.Me.Id)

	req, err := c.request("GET", url, nil)
	if err != nil {
		return nil, err
	}

	res, err := c.hc.Do(req)
	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, fmt.Errorf("error reading body: %s", err)
	}

	data := struct{ Data []Task }{}

	err = json.Unmarshal(body, &data)
	return data.Data, err
}
<|endoftext|>