<commit_before>package awsprovider

import (
	"errors"
	"fmt"
	"strconv"
	"time"

	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"

	"koding/kites/kloud/api/amazon"
	"koding/kites/kloud/contexthelper/publickeys"
	"koding/kites/kloud/contexthelper/request"
	"koding/kites/kloud/machinestate"
	"koding/kites/kloud/userdata"

	kiteprotocol "github.com/koding/kite/protocol"

	"github.com/mitchellh/goamz/ec2"
	"github.com/nu7hatch/gouuid"
	"golang.org/x/net/context"
)

var DefaultUbuntuImage = "ami-d05e75b8"

type BuildData struct {
	// This is passed directly to goamz to create the final instance
	EC2Data   *ec2.RunInstances
	ImageData *ImageData
	KiteId    string
}

type ImageData struct {
	blockDeviceMapping ec2.BlockDeviceMapping
	imageId            string
}

func (m *Machine) Build(ctx context.Context) (err error) {
	req, ok := request.FromContext(ctx)
	if !ok {
		return errors.New("request context is not available")
	}

	// the user might send us a snapshot id
	var args struct {
		Reason string
	}

	err = req.Args.One().Unmarshal(&args)
	if err != nil {
		return err
	}

	reason := "Machine is building."
	if args.Reason != "" {
		reason += "Custom reason: " + args.Reason
	}

	if err := m.UpdateState(reason, machinestate.Building); err != nil {
		return err
	}

	latestState := m.State()
	defer func() {
		// run any availabile cleanupFunction
		m.runCleanupFunctions()

		// if there is any error mark it as NotInitialized
		if err != nil {
			m.UpdateState("Machine is marked as "+latestState.String(), latestState)
		}
	}()

	if m.Meta.InstanceName == "" {
		m.Meta.InstanceName = "user-" + m.Username + "-" + strconv.FormatInt(time.Now().UTC().UnixNano(), 10)
	}

	// if there is already a machine just check it again
	if m.Meta.InstanceId == "" {
		m.push("Generating and fetching build data", 10, machinestate.Building)

		m.Log.Debug("Generating and fetching build data")
		buildData, err := m.buildData(ctx)
		if err != nil {
			return err
		}

		m.Meta.SourceAmi = buildData.ImageData.imageId
		m.QueryString = kiteprotocol.Kite{ID: buildData.KiteId}.String()

		m.push("Initiating build process", 30, machinestate.Building)
		m.Log.Debug("Initiating creating process of instance")

		m.Meta.InstanceId, err = m.Session.AWSClient.Build(buildData.EC2Data)
		if err != nil {
			return err
		}

		if err := m.Session.DB.Run("jMachines", func(c *mgo.Collection) error {
			return c.UpdateId(
				m.Id,
				bson.M{"$set": bson.M{
					"meta.instanceId": m.Meta.InstanceId,
					"meta.source_ami": m.Meta.SourceAmi,
					"meta.region":     m.Meta.Region,
					"queryString":     m.QueryString,
				}},
			)
		}); err != nil {
			return err
		}
	} else {
		m.Log.Debug("Continue build process with data, instanceId: '%s' and queryString: '%s'",
			m.Meta.InstanceId, m.QueryString)
	}

	m.push("Checking build process", 40, machinestate.Building)
	m.Log.Debug("Checking build process of instanceId '%s'", m.Meta.InstanceId)

	instance, err := m.Session.AWSClient.CheckBuild(ctx, m.Meta.InstanceId, 50, 70)
	if err == amazon.ErrInstanceTerminated || err == amazon.ErrNoInstances {
		if err := m.markAsNotInitialized(); err != nil {
			return err
		}

		return errors.New("instance is not available anymore")
	}

	if err != nil {
		return err
	}

	m.Meta.InstanceType = instance.InstanceType
	m.Meta.SourceAmi = instance.ImageId
	m.IpAddress = instance.PublicIpAddress

	m.push("Adding and setting up domains and tags", 70, machinestate.Building)
	m.addDomainAndTags()

	m.push(fmt.Sprintf("Checking klient connection '%s'", m.IpAddress), 80, machinestate.Building)
	if !m.isKlientReady() {
		return errors.New("klient is not ready")
	}

	resultInfo := fmt.Sprintf("username: [%s], instanceId: [%s], ipAdress: [%s], kiteQuery: [%s]",
		m.Username, m.Meta.InstanceId, m.IpAddress, m.QueryString)

	m.Log.Info("========== BUILD results ========== %s", resultInfo)

	reason = "Machine is build successfully."
	if args.Reason != "" {
		reason += "Custom reason: " + args.Reason
	}

	return m.Session.DB.Run("jMachines", func(c *mgo.Collection) error {
		return c.UpdateId(
			m.Id,
			bson.M{"$set": bson.M{
				"ipAddress":         m.IpAddress,
				"queryString":       m.QueryString,
				"meta.instanceType": m.Meta.InstanceType,
				"meta.instanceName": m.Meta.InstanceName,
				"meta.instanceId":   m.Meta.InstanceId,
				"meta.source_ami":   m.Meta.SourceAmi,
				"status.state":      machinestate.Running.String(),
				"status.modifiedAt": time.Now().UTC(),
				"status.reason":     reason,
			}},
		)
	})
}

func (m *Machine) imageData() (*ImageData, error) {
	if m.Meta.StorageSize == 0 {
		return nil, errors.New("storage size is zero")
	}

	m.Log.Debug("Fetching image which is tagged with '%s'", m.Meta.SourceAmi)

	imageId := DefaultUbuntuImage
	if m.Meta.SourceAmi != "" {
		m.Log.Critical("Source AMI is not set, using default Ubuntu AMI: %s", DefaultUbuntuImage)
		imageId = m.Meta.SourceAmi
	}

	image, err := m.Session.AWSClient.Image(imageId)
	if err != nil {
		return nil, err
	}

	device := image.BlockDevices[0]

	// The lowest commong storage size for public Images is 8. To have a
	// smaller storage size (like we do have for Koding, one must create new
	// image). We assume that nodody did this :)
	if m.Meta.StorageSize < 8 {
		m.Meta.StorageSize = 8
	}

	// Increase storage if it's passed to us, otherwise the default 3GB is
	// created already with the default AMI
	blockDeviceMapping := ec2.BlockDeviceMapping{
		DeviceName:          device.DeviceName,
		VirtualName:         device.VirtualName,
		VolumeType:          "standard", // Use magnetic storage because it is cheaper
		VolumeSize:          int64(m.Meta.StorageSize),
		DeleteOnTermination: true,
		Encrypted:           false,
	}

	m.Log.Debug("Using image Id: %s and block device settings %v", image.Id, blockDeviceMapping)

	return &ImageData{
		imageId:            image.Id,
		blockDeviceMapping: blockDeviceMapping,
	}, nil
}

// buildData returns all necessary data that is needed to build a machine.
func (m *Machine) buildData(ctx context.Context) (*BuildData, error) {
	imageData, err := m.imageData()
	if err != nil {
		return nil, err
	}

	if m.Session.AWSClient.Builder.InstanceType == "" {
		return nil, errors.New("instance type is empty")
	}

	kiteUUID, err := uuid.NewV4()
	if err != nil {
		return nil, err
	}

	kiteId := kiteUUID.String()

	m.Log.Debug("Creating user data")

	sshKeys := make([]string, len(m.User.SshKeys))
	for i, sshKey := range m.User.SshKeys {
		sshKeys[i] = sshKey.Key
	}

	cloudInitConfig := &userdata.CloudInitConfig{
		Username:    m.Username,
		Groups:      []string{"sudo"},
		UserSSHKeys: sshKeys,
		Hostname:    m.Username, // no typo here. hostname = username
		KiteId:      kiteId,
	}

	userdata, err := m.Session.Userdata.Create(cloudInitConfig)
	if err != nil {
		return nil, err
	}

	keys, ok := publickeys.FromContext(ctx)
	if !ok {
		return nil, errors.New("public keys are not available")
	}

	subnets, err := m.Session.AWSClient.ListSubnets()
	if err != nil {
		return nil, err
	}

	if len(subnets.Subnets) == 0 {
		return nil, errors.New("no subnets are available")
	}

	var subnetId string
	var vpcId string
	for _, subnet := range subnets.Subnets {
		if subnet.AvailableIpAddressCount == 0 {
			continue
		}

		subnetId = subnet.SubnetId
		vpcId = subnet.VpcId
	}

	if subnetId == "" {
		return nil, errors.New("subnetId is empty")
	}

	var groupName = "Koding-Kloud-SG"
	var group ec2.SecurityGroup

	group, err = m.Session.AWSClient.SecurityGroup(groupName)
	if err != nil {
		// TODO: parse the error code and only create if it's a `NotFound` error
		// assume it doesn't exists, go and create it
		opts := ec2.SecurityGroup{
			Name:        groupName,
			Description: "Koding VMs group",
			VpcId:       vpcId,
		}

		resp, err := m.Session.AWSClient.Client.CreateSecurityGroup(opts)
		if err != nil {
			return nil, err
		}

		// Authorize the SSH and Klient access
		perms := []ec2.IPPerm{
			ec2.IPPerm{
				Protocol:  "tcp",
				FromPort:  0,
				ToPort:    65535,
				SourceIPs: []string{"0.0.0.0/0"},
			},
		}

		group = resp.SecurityGroup

		// TODO: use retry mechanism
		// We loop and retry this a few times because sometimes the security
		// group isn't available immediately because AWS resources are eventaully
		// consistent.
		for i := 0; i < 5; i++ {
			_, err = m.Session.AWSClient.Client.AuthorizeSecurityGroup(group, perms)
			if err == nil {
				break
			}

			m.Log.Error("Error authorizing. Will sleep and retry. %s", err)
			time.Sleep((time.Duration(i) * time.Second) + 1)
		}

		if err != nil {
			return nil, err
		}

	}

	m.Session.AWSClient.Builder.KeyPair = keys.KeyName
	m.Session.AWSClient.Builder.PrivateKey = keys.PrivateKey
	m.Session.AWSClient.Builder.PublicKey = keys.PublicKey

	keyName, err := m.Session.AWSClient.DeployKey()
	if err != nil {
		return nil, err
	}

	ec2Data := &ec2.RunInstances{
		ImageId:                  m.Meta.SourceAmi,
		MinCount:                 1,
		MaxCount:                 1,
		KeyName:                  keyName,
		InstanceType:             m.Session.AWSClient.Builder.InstanceType,
		SubnetId:                 subnetId,
		SecurityGroups:           []ec2.SecurityGroup{{Id: group.Id}},
		AssociatePublicIpAddress: true,
		BlockDevices:             []ec2.BlockDeviceMapping{imageData.blockDeviceMapping},
		UserData:                 userdata,
	}

	return &BuildData{
		EC2Data:   ec2Data,
		ImageData: imageData,
		KiteId:    kiteId,
	}, nil
}

func (m *Machine) addDomainAndTags() {
	// this can happen when an Info method is called on a terminated instance.
	// This updates the DB records with the name that EC2 gives us, which is a
	// "terminated-instance"
	m.Log.Debug("Adding and setting up domain and tags")
	if m.Meta.InstanceName == "terminated-instance" {
		m.Meta.InstanceName = "user-" + m.Username + "-" + strconv.FormatInt(time.Now().UTC().UnixNano(), 10)
		m.Log.Debug("Instance name is an artifact (terminated), changing to %s", m.Meta.InstanceName)
	}

	m.push("Updating/Creating domain", 70, machinestate.Building)
	m.Log.Debug("Updating/Creating domain %s", m.IpAddress)

	if err := m.Session.DNSClient.Validate(m.Domain, m.Username); err != nil {
		m.Log.Error("couldn't update machine domain: %s", err.Error())
	}

	if err := m.Session.DNSClient.Upsert(m.Domain, m.IpAddress); err != nil {
		m.Log.Error("couldn't update machine domain: %s", err.Error())
	}

	m.push("Updating domain aliases", 72, machinestate.Building)
	domains, err := m.Session.DNSStorage.GetByMachine(m.Id.Hex())
	if err != nil {
		m.Log.Error("fetching domains for setting err: %s", err.Error())
	}

	for _, domain := range domains {
		if err := m.Session.DNSClient.Validate(domain.Name, m.Username); err != nil {
			m.Log.Error("couldn't update machine domain: %s", err.Error())
		}
		if err := m.Session.DNSClient.Upsert(domain.Name, m.IpAddress); err != nil {
			m.Log.Error("couldn't update machine domain: %s", err.Error())
		}
	}

	tags := []ec2.Tag{
		{Key: "Name", Value: m.Meta.InstanceName},
		{Key: "koding-user", Value: m.Username},
		{Key: "koding-env", Value: m.Session.Kite.Config.Environment},
		{Key: "koding-machineId", Value: m.Id.Hex()},
		{Key: "koding-domain", Value: m.Domain},
	}

	m.Log.Debug("Adding user tags %v", tags)
	if err := m.Session.AWSClient.AddTags(m.Meta.InstanceId, tags); err != nil {
		m.Log.Error("Adding tags failed: %v", err)
	}
}
<commit_msg>kloud: fix aws passing empty for fallback image<commit_after>package awsprovider

import (
	"errors"
	"fmt"
	"strconv"
	"time"

	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"

	"koding/kites/kloud/api/amazon"
	"koding/kites/kloud/contexthelper/publickeys"
	"koding/kites/kloud/contexthelper/request"
	"koding/kites/kloud/machinestate"
	"koding/kites/kloud/userdata"

	kiteprotocol "github.com/koding/kite/protocol"

	"github.com/mitchellh/goamz/ec2"
	"github.com/nu7hatch/gouuid"
	"golang.org/x/net/context"
)

var DefaultUbuntuImage = "ami-d05e75b8"

type BuildData struct {
	// This is passed directly to goamz to create the final instance
	EC2Data   *ec2.RunInstances
	ImageData *ImageData
	KiteId    string
}

type ImageData struct {
	blockDeviceMapping ec2.BlockDeviceMapping
	imageId            string
}

func (m *Machine) Build(ctx context.Context) (err error) {
	req, ok := request.FromContext(ctx)
	if !ok {
		return errors.New("request context is not available")
	}

	// the user might send us a snapshot id
	var args struct {
		Reason string
	}

	err = req.Args.One().Unmarshal(&args)
	if err != nil {
		return err
	}

	reason := "Machine is building."
	if args.Reason != "" {
		reason += "Custom reason: " + args.Reason
	}

	if err := m.UpdateState(reason, machinestate.Building); err != nil {
		return err
	}

	latestState := m.State()
	defer func() {
		// run any availabile cleanupFunction
		m.runCleanupFunctions()

		// if there is any error mark it as NotInitialized
		if err != nil {
			m.UpdateState("Machine is marked as "+latestState.String(), latestState)
		}
	}()

	if m.Meta.InstanceName == "" {
		m.Meta.InstanceName = "user-" + m.Username + "-" + strconv.FormatInt(time.Now().UTC().UnixNano(), 10)
	}

	// if there is already a machine just check it again
	if m.Meta.InstanceId == "" {
		m.push("Generating and fetching build data", 10, machinestate.Building)

		m.Log.Debug("Generating and fetching build data")
		buildData, err := m.buildData(ctx)
		if err != nil {
			return err
		}

		m.Meta.SourceAmi = buildData.ImageData.imageId
		m.QueryString = kiteprotocol.Kite{ID: buildData.KiteId}.String()

		m.push("Initiating build process", 30, machinestate.Building)
		m.Log.Debug("Initiating creating process of instance")

		m.Meta.InstanceId, err = m.Session.AWSClient.Build(buildData.EC2Data)
		if err != nil {
			return err
		}

		if err := m.Session.DB.Run("jMachines", func(c *mgo.Collection) error {
			return c.UpdateId(
				m.Id,
				bson.M{"$set": bson.M{
					"meta.instanceId": m.Meta.InstanceId,
					"meta.source_ami": m.Meta.SourceAmi,
					"meta.region":     m.Meta.Region,
					"queryString":     m.QueryString,
				}},
			)
		}); err != nil {
			return err
		}
	} else {
		m.Log.Debug("Continue build process with data, instanceId: '%s' and queryString: '%s'",
			m.Meta.InstanceId, m.QueryString)
	}

	m.push("Checking build process", 40, machinestate.Building)
	m.Log.Debug("Checking build process of instanceId '%s'", m.Meta.InstanceId)

	instance, err := m.Session.AWSClient.CheckBuild(ctx, m.Meta.InstanceId, 50, 70)
	if err == amazon.ErrInstanceTerminated || err == amazon.ErrNoInstances {
		if err := m.markAsNotInitialized(); err != nil {
			return err
		}

		return errors.New("instance is not available anymore")
	}

	if err != nil {
		return err
	}

	m.Meta.InstanceType = instance.InstanceType
	m.Meta.SourceAmi = instance.ImageId
	m.IpAddress = instance.PublicIpAddress

	m.push("Adding and setting up domains and tags", 70, machinestate.Building)
	m.addDomainAndTags()

	m.push(fmt.Sprintf("Checking klient connection '%s'", m.IpAddress), 80, machinestate.Building)
	if !m.isKlientReady() {
		return errors.New("klient is not ready")
	}

	resultInfo := fmt.Sprintf("username: [%s], instanceId: [%s], ipAdress: [%s], kiteQuery: [%s]",
		m.Username, m.Meta.InstanceId, m.IpAddress, m.QueryString)

	m.Log.Info("========== BUILD results ========== %s", resultInfo)

	reason = "Machine is build successfully."
	if args.Reason != "" {
		reason += "Custom reason: " + args.Reason
	}

	return m.Session.DB.Run("jMachines", func(c *mgo.Collection) error {
		return c.UpdateId(
			m.Id,
			bson.M{"$set": bson.M{
				"ipAddress":         m.IpAddress,
				"queryString":       m.QueryString,
				"meta.instanceType": m.Meta.InstanceType,
				"meta.instanceName": m.Meta.InstanceName,
				"meta.instanceId":   m.Meta.InstanceId,
				"meta.source_ami":   m.Meta.SourceAmi,
				"status.state":      machinestate.Running.String(),
				"status.modifiedAt": time.Now().UTC(),
				"status.reason":     reason,
			}},
		)
	})
}

func (m *Machine) imageData() (*ImageData, error) {
	if m.Meta.StorageSize == 0 {
		return nil, errors.New("storage size is zero")
	}

	m.Log.Debug("Fetching image which is tagged with '%s'", m.Meta.SourceAmi)

	imageId := DefaultUbuntuImage
	if m.Meta.SourceAmi != "" {
		m.Log.Critical("Source AMI is not set, using default Ubuntu AMI: %s", DefaultUbuntuImage)
		imageId = m.Meta.SourceAmi
	}

	image, err := m.Session.AWSClient.Image(imageId)
	if err != nil {
		return nil, err
	}

	device := image.BlockDevices[0]

	// The lowest commong storage size for public Images is 8. To have a
	// smaller storage size (like we do have for Koding, one must create new
	// image). We assume that nodody did this :)
	if m.Meta.StorageSize < 8 {
		m.Meta.StorageSize = 8
	}

	// Increase storage if it's passed to us, otherwise the default 3GB is
	// created already with the default AMI
	blockDeviceMapping := ec2.BlockDeviceMapping{
		DeviceName:          device.DeviceName,
		VirtualName:         device.VirtualName,
		VolumeType:          "standard", // Use magnetic storage because it is cheaper
		VolumeSize:          int64(m.Meta.StorageSize),
		DeleteOnTermination: true,
		Encrypted:           false,
	}

	m.Log.Debug("Using image Id: %s and block device settings %v", image.Id, blockDeviceMapping)

	return &ImageData{
		imageId:            image.Id,
		blockDeviceMapping: blockDeviceMapping,
	}, nil
}

// buildData returns all necessary data that is needed to build a machine.
func (m *Machine) buildData(ctx context.Context) (*BuildData, error) {
	imageData, err := m.imageData()
	if err != nil {
		return nil, err
	}

	if m.Session.AWSClient.Builder.InstanceType == "" {
		return nil, errors.New("instance type is empty")
	}

	kiteUUID, err := uuid.NewV4()
	if err != nil {
		return nil, err
	}

	kiteId := kiteUUID.String()

	m.Log.Debug("Creating user data")

	sshKeys := make([]string, len(m.User.SshKeys))
	for i, sshKey := range m.User.SshKeys {
		sshKeys[i] = sshKey.Key
	}

	cloudInitConfig := &userdata.CloudInitConfig{
		Username:    m.Username,
		Groups:      []string{"sudo"},
		UserSSHKeys: sshKeys,
		Hostname:    m.Username, // no typo here. hostname = username
		KiteId:      kiteId,
	}

	userdata, err := m.Session.Userdata.Create(cloudInitConfig)
	if err != nil {
		return nil, err
	}

	keys, ok := publickeys.FromContext(ctx)
	if !ok {
		return nil, errors.New("public keys are not available")
	}

	subnets, err := m.Session.AWSClient.ListSubnets()
	if err != nil {
		return nil, err
	}

	if len(subnets.Subnets) == 0 {
		return nil, errors.New("no subnets are available")
	}

	var subnetId string
	var vpcId string
	for _, subnet := range subnets.Subnets {
		if subnet.AvailableIpAddressCount == 0 {
			continue
		}

		subnetId = subnet.SubnetId
		vpcId = subnet.VpcId
	}

	if subnetId == "" {
		return nil, errors.New("subnetId is empty")
	}

	var groupName = "Koding-Kloud-SG"
	var group ec2.SecurityGroup

	group, err = m.Session.AWSClient.SecurityGroup(groupName)
	if err != nil {
		// TODO: parse the error code and only create if it's a `NotFound` error
		// assume it doesn't exists, go and create it
		opts := ec2.SecurityGroup{
			Name:        groupName,
			Description: "Koding VMs group",
			VpcId:       vpcId,
		}

		resp, err := m.Session.AWSClient.Client.CreateSecurityGroup(opts)
		if err != nil {
			return nil, err
		}

		// Authorize the SSH and Klient access
		perms := []ec2.IPPerm{
			ec2.IPPerm{
				Protocol:  "tcp",
				FromPort:  0,
				ToPort:    65535,
				SourceIPs: []string{"0.0.0.0/0"},
			},
		}

		group = resp.SecurityGroup

		// TODO: use retry mechanism
		// We loop and retry this a few times because sometimes the security
		// group isn't available immediately because AWS resources are eventaully
		// consistent.
		for i := 0; i < 5; i++ {
			_, err = m.Session.AWSClient.Client.AuthorizeSecurityGroup(group, perms)
			if err == nil {
				break
			}

			m.Log.Error("Error authorizing. Will sleep and retry. %s", err)
			time.Sleep((time.Duration(i) * time.Second) + 1)
		}

		if err != nil {
			return nil, err
		}

	}

	m.Session.AWSClient.Builder.KeyPair = keys.KeyName
	m.Session.AWSClient.Builder.PrivateKey = keys.PrivateKey
	m.Session.AWSClient.Builder.PublicKey = keys.PublicKey

	keyName, err := m.Session.AWSClient.DeployKey()
	if err != nil {
		return nil, err
	}

	ec2Data := &ec2.RunInstances{
		ImageId:                  imageData.imageId,
		MinCount:                 1,
		MaxCount:                 1,
		KeyName:                  keyName,
		InstanceType:             m.Session.AWSClient.Builder.InstanceType,
		SubnetId:                 subnetId,
		SecurityGroups:           []ec2.SecurityGroup{{Id: group.Id}},
		AssociatePublicIpAddress: true,
		BlockDevices:             []ec2.BlockDeviceMapping{imageData.blockDeviceMapping},
		UserData:                 userdata,
	}

	return &BuildData{
		EC2Data:   ec2Data,
		ImageData: imageData,
		KiteId:    kiteId,
	}, nil
}

func (m *Machine) addDomainAndTags() {
	// this can happen when an Info method is called on a terminated instance.
	// This updates the DB records with the name that EC2 gives us, which is a
	// "terminated-instance"
	m.Log.Debug("Adding and setting up domain and tags")
	if m.Meta.InstanceName == "terminated-instance" {
		m.Meta.InstanceName = "user-" + m.Username + "-" + strconv.FormatInt(time.Now().UTC().UnixNano(), 10)
		m.Log.Debug("Instance name is an artifact (terminated), changing to %s", m.Meta.InstanceName)
	}

	m.push("Updating/Creating domain", 70, machinestate.Building)
	m.Log.Debug("Updating/Creating domain %s", m.IpAddress)

	if err := m.Session.DNSClient.Validate(m.Domain, m.Username); err != nil {
		m.Log.Error("couldn't update machine domain: %s", err.Error())
	}

	if err := m.Session.DNSClient.Upsert(m.Domain, m.IpAddress); err != nil {
		m.Log.Error("couldn't update machine domain: %s", err.Error())
	}

	m.push("Updating domain aliases", 72, machinestate.Building)
	domains, err := m.Session.DNSStorage.GetByMachine(m.Id.Hex())
	if err != nil {
		m.Log.Error("fetching domains for setting err: %s", err.Error())
	}

	for _, domain := range domains {
		if err := m.Session.DNSClient.Validate(domain.Name, m.Username); err != nil {
			m.Log.Error("couldn't update machine domain: %s", err.Error())
		}
		if err := m.Session.DNSClient.Upsert(domain.Name, m.IpAddress); err != nil {
			m.Log.Error("couldn't update machine domain: %s", err.Error())
		}
	}

	tags := []ec2.Tag{
		{Key: "Name", Value: m.Meta.InstanceName},
		{Key: "koding-user", Value: m.Username},
		{Key: "koding-env", Value: m.Session.Kite.Config.Environment},
		{Key: "koding-machineId", Value: m.Id.Hex()},
		{Key: "koding-domain", Value: m.Domain},
	}

	m.Log.Debug("Adding user tags %v", tags)
	if err := m.Session.AWSClient.AddTags(m.Meta.InstanceId, tags); err != nil {
		m.Log.Error("Adding tags failed: %v", err)
	}
}
<|endoftext|>


<commit_before>package engine

// #include <stdlib.h>
// #include "skiplist.h"
// #include "kv_skiplist.h"
import "C"
import (
	"sync/atomic"
	"unsafe"
)

// byteToChar returns *C.char from byte slice.
func byteToChar(b []byte) *C.char {
	var c *C.char
	if len(b) > 0 {
		c = (*C.char)(unsafe.Pointer(&b[0]))
	}
	return c
}

type skipList struct {
	csl    *C.skiplist_raw
	closed int32
}

func NewSkipList() *skipList {
	return &skipList{
		csl: C.kv_skiplist_create(),
	}
}

func (sl *skipList) Destroy() {
	atomic.StoreInt32(&sl.closed, 1)
	C.kv_skiplist_destroy(sl.csl)
}

func (sl *skipList) IsClosed() bool {
	return atomic.LoadInt32(&sl.closed) == 1
}

func (sl *skipList) Len() int64 {
	cs := C.skiplist_get_size(sl.csl)
	return int64(cs)
}

func (sl *skipList) NewIterator() *SkipListIterator {
	// the mutex RUnlock must be called while iterator is closed
	return &SkipListIterator{
		sl:     sl,
		cursor: nil,
	}
}

func (sl *skipList) Get(key []byte) ([]byte, error) {
	var (
		cvsz C.size_t
		cKey = byteToChar(key)
	)
	cv := C.kv_skiplist_get(sl.csl, cKey, C.size_t(len(key)), &cvsz)
	if cv == nil {
		return nil, nil
	}
	defer C.free(unsafe.Pointer(cv))
	return C.GoBytes(unsafe.Pointer(cv), C.int(cvsz)), nil
}

func (sl *skipList) Set(key []byte, value []byte) error {
	var (
		cKey   = byteToChar(key)
		cValue = byteToChar(value)
	)
	C.kv_skiplist_update(sl.csl, cKey, C.size_t(len(key)), cValue, C.size_t(len(value)))
	return nil
}

func (sl *skipList) Delete(key []byte) error {
	cKey := byteToChar(key)
	C.kv_skiplist_del(sl.csl, cKey, C.size_t(len(key)))
	return nil
}
<commit_msg>fix compile for linux<commit_after>package engine

//#cgo CXXFLAGS: -std=c++11
// #include <stdlib.h>
// #include "skiplist.h"
// #include "kv_skiplist.h"
import "C"
import (
	"sync/atomic"
	"unsafe"
)

// byteToChar returns *C.char from byte slice.
func byteToChar(b []byte) *C.char {
	var c *C.char
	if len(b) > 0 {
		c = (*C.char)(unsafe.Pointer(&b[0]))
	}
	return c
}

type skipList struct {
	csl    *C.skiplist_raw
	closed int32
}

func NewSkipList() *skipList {
	return &skipList{
		csl: C.kv_skiplist_create(),
	}
}

func (sl *skipList) Destroy() {
	atomic.StoreInt32(&sl.closed, 1)
	C.kv_skiplist_destroy(sl.csl)
}

func (sl *skipList) IsClosed() bool {
	return atomic.LoadInt32(&sl.closed) == 1
}

func (sl *skipList) Len() int64 {
	cs := C.skiplist_get_size(sl.csl)
	return int64(cs)
}

func (sl *skipList) NewIterator() *SkipListIterator {
	// the mutex RUnlock must be called while iterator is closed
	return &SkipListIterator{
		sl:     sl,
		cursor: nil,
	}
}

func (sl *skipList) Get(key []byte) ([]byte, error) {
	var (
		cvsz C.size_t
		cKey = byteToChar(key)
	)
	cv := C.kv_skiplist_get(sl.csl, cKey, C.size_t(len(key)), &cvsz)
	if cv == nil {
		return nil, nil
	}
	defer C.free(unsafe.Pointer(cv))
	return C.GoBytes(unsafe.Pointer(cv), C.int(cvsz)), nil
}

func (sl *skipList) Set(key []byte, value []byte) error {
	var (
		cKey   = byteToChar(key)
		cValue = byteToChar(value)
	)
	C.kv_skiplist_update(sl.csl, cKey, C.size_t(len(key)), cValue, C.size_t(len(value)))
	return nil
}

func (sl *skipList) Delete(key []byte) error {
	cKey := byteToChar(key)
	C.kv_skiplist_del(sl.csl, cKey, C.size_t(len(key)))
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	. "koding/db/models"
	helper "koding/db/mongodb/modelhelper"
	"labix.org/v2/mgo/bson"
)

// hard delete.
func DeleteStatusUpdate(id string) error {
	err := RemoveComments(id)
	if err != nil {
		log.Error("Empty Status Update Cannot be deleted")
		return err
	}

	err = RemovePostRelationships(id)
	if err != nil {
		log.Error("Empty Status Update Cannot be deleted")
		return err
	}

	err = helper.DeleteStatusUpdateById(id)
	if err != nil {
		log.Error("Empty Status Update Cannot be deleted")
		return err
	}

	log.Info("Deleted Empty Status Update")
	return nil
}

//Creates Relationships both in mongo and neo4j
func CreateRelationship(relationship *Relationship) error {
	err := CreateGraphRelationship(relationship)
	if err != nil {
		return err
	}
	log.Debug("Add Mongo Relationship")
	return helper.AddRelationship(relationship)
}

//Removes Relationships both from mongo and neo4j
func RemoveRelationship(relationship *Relationship) error {
	err := RemoveGraphRelationship(relationship)
	if err != nil {
		return err
	}

	selector := helper.Selector{
		"sourceId": relationship.SourceId,
		"targetId": relationship.TargetId,
		"as":       relationship.As,
	}
	log.Debug("Delete Mongo Relationship")
	return helper.DeleteRelationship(selector)
}

//Finds synonym of a given tag by tagId
func FindSynonym(tagId string) (*Tag, error) {
	selector := helper.Selector{"sourceId": helper.GetObjectId(tagId), "as": "synonymOf"}
	synonymRel, err := helper.GetRelationship(selector)
	if err != nil {
		return nil, err
	}

	return helper.GetTagById(synonymRel.TargetId.Hex())
}

func RemoveComments(id string) error {
	objectId := helper.GetObjectId(id)
	selector := helper.Selector{"targetId": objectId, "sourceName": "JComment"}

	removedNodeIds := make([]bson.ObjectId, 0)
	rels, err := helper.GetRelationships(selector)
	if err != nil {
		return err
	}
	for _, rel := range rels {
		err = RemoveRelationship(&rel)
		if err != nil {
			return err
		}
		removedNodeIds = append(removedNodeIds, rel.SourceId)
	}

	//remove comment relationships with opposite orientation
	selector = helper.Selector{"targetId": helper.Selector{"$in": removedNodeIds}}
	err = RemoveRelationships(selector)
	if err != nil {
		return err
	}

	selector = helper.Selector{"_id": helper.Selector{"$in": removedNodeIds}}
	return helper.DeleteComment(selector)
}

func RemovePostRelationships(id string) error {
	objectId := helper.GetObjectId(id)
	// remove post relationships
	selector := helper.Selector{"$or": []helper.Selector{
		helper.Selector{"sourceId": objectId},
		helper.Selector{"targetId": objectId},
	}}
	return RemoveRelationships(selector)
}

func RemoveRelationships(selector helper.Selector) error {
	rels, err := helper.GetRelationships(selector)
	if err != nil {
		return err
	}

	for _, rel := range rels {
		err = RemoveRelationship(&rel)
		if err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Moderation: while deleting empty posts return when post does not have any comments<commit_after>package main

import (
	. "koding/db/models"
	helper "koding/db/mongodb/modelhelper"
	"labix.org/v2/mgo/bson"
)

// hard delete.
func DeleteStatusUpdate(id string) error {
	err := RemoveComments(id)
	if err != nil {
		log.Error("Empty Status Update Cannot be deleted")
		return err
	}

	err = RemovePostRelationships(id)
	if err != nil {
		log.Error("Empty Status Update Cannot be deleted")
		return err
	}

	err = helper.DeleteStatusUpdateById(id)
	if err != nil {
		log.Error("Empty Status Update Cannot be deleted")
		return err
	}

	log.Info("Deleted Empty Status Update")
	return nil
}

//Creates Relationships both in mongo and neo4j
func CreateRelationship(relationship *Relationship) error {
	err := CreateGraphRelationship(relationship)
	if err != nil {
		return err
	}
	log.Debug("Add Mongo Relationship")
	return helper.AddRelationship(relationship)
}

//Removes Relationships both from mongo and neo4j
func RemoveRelationship(relationship *Relationship) error {
	err := RemoveGraphRelationship(relationship)
	if err != nil {
		return err
	}

	selector := helper.Selector{
		"sourceId": relationship.SourceId,
		"targetId": relationship.TargetId,
		"as":       relationship.As,
	}
	log.Debug("Delete Mongo Relationship")
	return helper.DeleteRelationship(selector)
}

//Finds synonym of a given tag by tagId
func FindSynonym(tagId string) (*Tag, error) {
	selector := helper.Selector{"sourceId": helper.GetObjectId(tagId), "as": "synonymOf"}
	synonymRel, err := helper.GetRelationship(selector)
	if err != nil {
		return nil, err
	}

	return helper.GetTagById(synonymRel.TargetId.Hex())
}

func RemoveComments(id string) error {
	objectId := helper.GetObjectId(id)
	selector := helper.Selector{"targetId": objectId, "sourceName": "JComment"}

	removedNodeIds := make([]bson.ObjectId, 0)
	rels, err := helper.GetRelationships(selector)
	if len(rels) == 0 {
		return nil
	}

	if err != nil {
		return err
	}
	for _, rel := range rels {
		err = RemoveRelationship(&rel)
		if err != nil {
			return err
		}
		removedNodeIds = append(removedNodeIds, rel.SourceId)
	}

	//remove comment relationships with opposite orientation
	selector = helper.Selector{"targetId": helper.Selector{"$in": removedNodeIds}}
	err = RemoveRelationships(selector)
	if err != nil {
		return err
	}

	selector = helper.Selector{"_id": helper.Selector{"$in": removedNodeIds}}
	return helper.DeleteComment(selector)
}

func RemovePostRelationships(id string) error {
	objectId := helper.GetObjectId(id)
	// remove post relationships
	selector := helper.Selector{"$or": []helper.Selector{
		helper.Selector{"sourceId": objectId},
		helper.Selector{"targetId": objectId},
	}}
	return RemoveRelationships(selector)
}

func RemoveRelationships(selector helper.Selector) error {
	rels, err := helper.GetRelationships(selector)
	if err != nil {
		return err
	}

	for _, rel := range rels {
		err = RemoveRelationship(&rel)
		if err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package v1alpha1

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"reflect"
	"testing"

	"github.com/h-fam/errdiff"
	"github.com/kr/pretty"
	srlinuxv1 "github.com/srl-labs/srl-controller/api/types/v1alpha1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	ktest "k8s.io/client-go/testing"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/watch"
	dynamicfake "k8s.io/client-go/dynamic/fake"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/rest"
	restfake "k8s.io/client-go/rest/fake"
)

var (
	obj1 = &srlinuxv1.Srlinux{
		TypeMeta: metav1.TypeMeta{
			Kind:       "Srlinux",
			APIVersion: "kne.srlinux.dev/v1alpha1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name:       "obj1",
			Namespace:  "test",
			Generation: 1,
		},
		Status: srlinuxv1.SrlinuxStatus{},
		Spec: srlinuxv1.SrlinuxSpec{
			Config:        &srlinuxv1.NodeConfig{},
			NumInterfaces: 2,
			Model:         "fake",
			Version:       "1",
		},
	}

	obj2 = &srlinuxv1.Srlinux{
		TypeMeta: metav1.TypeMeta{
			Kind:       "Srlinux",
			APIVersion: "kne.srlinux.dev/v1alpha1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name:       "obj2",
			Namespace:  "test",
			Generation: 1,
		},
		Status: srlinuxv1.SrlinuxStatus{},
		Spec: srlinuxv1.SrlinuxSpec{
			Config:        &srlinuxv1.NodeConfig{},
			NumInterfaces: 2,
			Model:         "fake1",
			Version:       "2",
		},
	}
)

func setUp(t *testing.T) (*Clientset, *restfake.RESTClient) {
	t.Helper()

	gv := GV()

	fakeClient := &restfake.RESTClient{
		NegotiatedSerializer: scheme.Codecs.WithoutConversion(),
		GroupVersion:         *gv,
		VersionedAPIPath:     GVR().Version,
	}

	cs, err := NewForConfig(&rest.Config{})
	if err != nil {
		t.Fatalf("NewForConfig() failed: %v", err)
	}

	objs := []runtime.Object{obj1, obj2}
	cs.restClient = fakeClient
	f := dynamicfake.NewSimpleDynamicClient(scheme.Scheme, objs...)
	f.PrependReactor("get", "*", func(action ktest.Action) (bool, runtime.Object, error) {
		gAction := action.(ktest.GetAction)
		switch gAction.GetName() {
		case "obj1":
			return true, obj1, nil
		case "obj2":
			return true, obj2, nil
		}

		return false, nil, nil
	})

	f.PrependReactor("update", "*", func(action ktest.Action) (bool, runtime.Object, error) {
		uAction, ok := action.(ktest.UpdateAction)
		if !ok {
			return false, nil, nil
		}

		uObj := uAction.GetObject().(*unstructured.Unstructured)
		sObj := &srlinuxv1.Srlinux{}

		if err := runtime.DefaultUnstructuredConverter.FromUnstructured(uObj.Object, sObj); err != nil {
			return true, nil, fmt.Errorf("failed to convert object: %v", err)
		}

		if sObj.ObjectMeta.Name == "doesnotexist" {
			return true, nil, fmt.Errorf("doesnotexist")
		}

		return true, uAction.GetObject(), nil
	})

	cs.dInterface = f.Resource(GVR())

	return cs, fakeClient
}

func TestCreate(t *testing.T) {
	cs, fakeClient := setUp(t)

	tests := []struct {
		desc    string
		resp    *http.Response
		want    *srlinuxv1.Srlinux
		wantErr string
	}{{
		desc:    "Error",
		wantErr: "TEST ERROR",
	}, {
		desc: "Valid Node",
		resp: &http.Response{
			StatusCode: http.StatusOK,
		},
		want: obj1,
	}}

	for _, tt := range tests {
		fakeClient.Err = nil
		if tt.wantErr != "" {
			fakeClient.Err = fmt.Errorf(tt.wantErr)
		}

		fakeClient.Resp = tt.resp

		if tt.want != nil {
			b, _ := json.Marshal(tt.want)
			tt.resp.Body = io.NopCloser(bytes.NewReader(b))
		}

		t.Run(tt.desc, func(t *testing.T) {
			tc := cs.Srlinux("foo")
			got, err := tc.Create(context.Background(), tt.want)
			if s := errdiff.Substring(err, tt.wantErr); s != "" {
				t.Fatalf("unexpected error: %s", s)
			}
			if tt.wantErr != "" {
				return
			}
			want := tt.want.DeepCopy()
			want.TypeMeta = metav1.TypeMeta{}
			if !reflect.DeepEqual(got, want) {
				t.Fatalf("Create(%+v) failed: diff\n%s", tt.want, pretty.Diff(got, want))
			}
		})
	}
}

func TestList(t *testing.T) {
	cs, fakeClient := setUp(t)
	tests := []struct {
		desc    string
		resp    *http.Response
		want    *srlinuxv1.SrlinuxList
		wantErr string
	}{{
		desc:    "Error",
		wantErr: "TEST ERROR",
	}, {
		desc: "Valid Node",
		resp: &http.Response{
			StatusCode: http.StatusOK,
		},
		want: &srlinuxv1.SrlinuxList{
			Items: []srlinuxv1.Srlinux{*obj1, *obj2},
		},
	}}

	for _, tt := range tests {
		fakeClient.Err = nil

		if tt.wantErr != "" {
			fakeClient.Err = fmt.Errorf(tt.wantErr)
		}

		fakeClient.Resp = tt.resp

		if tt.want != nil {
			b, _ := json.Marshal(tt.want)
			tt.resp.Body = io.NopCloser(bytes.NewReader(b))
		}

		t.Run(tt.desc, func(t *testing.T) {
			tc := cs.Srlinux("foo")

			got, err := tc.List(context.Background(), metav1.ListOptions{})
			if s := errdiff.Substring(err, tt.wantErr); s != "" {
				t.Fatalf("unexpected error: %s", s)
			}

			if tt.wantErr != "" {
				return
			}

			if !reflect.DeepEqual(got, tt.want) {
				t.Fatalf("List() failed: got %v, want %v", got, tt.want)
			}
		})
	}
}

func TestGet(t *testing.T) {
	cs, fakeClient := setUp(t)
	tests := []struct {
		desc    string
		resp    *http.Response
		want    *srlinuxv1.Srlinux
		wantErr string
	}{{
		desc:    "Error",
		wantErr: "TEST ERROR",
	}, {
		desc: "Valid Node",
		resp: &http.Response{
			StatusCode: http.StatusOK,
		},
		want: obj1,
	}}

	for _, tt := range tests {
		fakeClient.Err = nil

		if tt.wantErr != "" {
			fakeClient.Err = fmt.Errorf(tt.wantErr)
		}

		fakeClient.Resp = tt.resp

		if tt.want != nil {
			b, _ := json.Marshal(tt.want)
			tt.resp.Body = io.NopCloser(bytes.NewReader(b))
		}

		t.Run(tt.desc, func(t *testing.T) {
			tc := cs.Srlinux("foo")

			got, err := tc.Get(context.Background(), "test", metav1.GetOptions{})
			if s := errdiff.Substring(err, tt.wantErr); s != "" {
				t.Fatalf("unexpected error: %s", s)
			}

			if tt.wantErr != "" {
				return
			}

			want := tt.want.DeepCopy()
			want.TypeMeta = metav1.TypeMeta{}
			if !reflect.DeepEqual(got, want) {
				t.Fatalf("Get() failed: got %v, want %v", got, want)
			}
		})
	}
}

func TestDelete(t *testing.T) {
	cs, fakeClient := setUp(t)
	tests := []struct {
		desc    string
		resp    *http.Response
		wantErr string
	}{{
		desc:    "Error",
		wantErr: "TEST ERROR",
	}, {
		desc: "Valid Node",
		resp: &http.Response{
			StatusCode: http.StatusOK,
		},
	}}

	for _, tt := range tests {
		fakeClient.Err = nil

		if tt.wantErr != "" {
			fakeClient.Err = fmt.Errorf(tt.wantErr)
		}

		fakeClient.Resp = tt.resp

		t.Run(tt.desc, func(t *testing.T) {
			tc := cs.Srlinux("foo")
			err := tc.Delete(context.Background(), "obj1", metav1.DeleteOptions{})
			if s := errdiff.Substring(err, tt.wantErr); s != "" {
				t.Fatalf("unexpected error: %s", s)
			}
			if tt.wantErr != "" {
				return
			}
		})
	}
}

func TestWatch(t *testing.T) {
	cs, fakeClient := setUp(t)
	tests := []struct {
		desc    string
		resp    *http.Response
		want    *watch.Event
		wantErr string
	}{{
		desc:    "Error",
		wantErr: "TEST ERROR",
	}}

	for _, tt := range tests {
		fakeClient.Err = nil

		if tt.wantErr != "" {
			fakeClient.Err = fmt.Errorf(tt.wantErr)
		}

		fakeClient.Resp = tt.resp

		if tt.want != nil {
			b, _ := json.Marshal(tt.want)
			tt.resp.Body = io.NopCloser(bytes.NewReader(b))
		}

		t.Run(tt.desc, func(t *testing.T) {
			tc := cs.Srlinux("foo")
			w, err := tc.Watch(context.Background(), metav1.ListOptions{})
			if s := errdiff.Substring(err, tt.wantErr); s != "" {
				t.Fatalf("unexpected error: %s", s)
			}

			if tt.wantErr != "" {
				return
			}

			e := <-w.ResultChan()
			if !reflect.DeepEqual(e, tt.want) {
				t.Fatalf("Watch() failed: got %v, want %v", e, tt.want)
			}
		})
	}
}

func TestUnstructured(t *testing.T) {
	cs, _ := setUp(t)
	tests := []struct {
		desc    string
		in      string
		want    *srlinuxv1.Srlinux
		wantErr string
	}{{
		desc:    "Error",
		in:      "missingObj",
		wantErr: `"missingObj" not found`,
	}, {
		desc: "Valid Node",
		in:   obj1.GetObjectMeta().GetName(),
		want: obj1,
	}, {
		desc: "Valid Node",
		in:   obj2.GetObjectMeta().GetName(),
		want: obj2,
	}}
	for _, tt := range tests {
		t.Run(tt.desc, func(t *testing.T) {
			tc := cs.Srlinux("test")
			got, err := tc.Unstructured(context.Background(), tt.in, metav1.GetOptions{})
			if s := errdiff.Substring(err, tt.wantErr); s != "" {
				t.Fatalf("unexpected error: %s", s)
			}

			if tt.wantErr != "" {
				return
			}

			uObj1 := &srlinuxv1.Srlinux{}
			if err := runtime.DefaultUnstructuredConverter.FromUnstructured(got.Object, uObj1); err != nil {
				t.Fatalf("failed to turn response into a topology: %v", err)
			}

			if !reflect.DeepEqual(uObj1, tt.want) {
				t.Fatalf("Unstructured(%q) failed: got %+v, want %+v", tt.in, uObj1, tt.want)
			}
		})
	}
}

func TestUpdate(t *testing.T) {
	cs, _ := setUp(t)
	tests := []struct {
		desc    string
		want    *srlinuxv1.Srlinux
		wantErr string
	}{{
		desc: "Error",
		want: &srlinuxv1.Srlinux{
			TypeMeta: metav1.TypeMeta{
				Kind:       "Srlinux",
				APIVersion: "kne.srlinux.dev/v1alpha1",
			},
			ObjectMeta: metav1.ObjectMeta{
				Name:       "doesnotexist",
				Namespace:  "test",
				Generation: 1,
			},
		},
		wantErr: "doesnotexist",
	}, {
		desc: "Valid Topology",
		want: obj1,
	}}
	for _, tt := range tests {
		t.Run(tt.desc, func(t *testing.T) {
			sc := cs.Srlinux("test")
			updateObj := tt.want.DeepCopy()
			updateObj.Spec.Version = "updated version"

			update, err := runtime.DefaultUnstructuredConverter.ToUnstructured(updateObj)
			if err != nil {
				t.Fatalf("failed to generate update: %v", err)
			}

			got, err := sc.Update(context.Background(), &unstructured.Unstructured{
				Object: update,
			}, metav1.UpdateOptions{})

			if s := errdiff.Substring(err, tt.wantErr); s != "" {
				t.Fatalf("unexpected error: %s", s)
			}

			if tt.wantErr != "" {
				return
			}

			want := tt.want.DeepCopy()
			want.TypeMeta = metav1.TypeMeta{}
			if !reflect.DeepEqual(got, updateObj) {
				t.Fatalf("Update() failed: got %+v, want %+v", got, want)
			}
		})
	}
}
<commit_msg>fix some more cuddling<commit_after>package v1alpha1

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"reflect"
	"testing"

	"github.com/h-fam/errdiff"
	"github.com/kr/pretty"
	srlinuxv1 "github.com/srl-labs/srl-controller/api/types/v1alpha1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	ktest "k8s.io/client-go/testing"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/watch"
	dynamicfake "k8s.io/client-go/dynamic/fake"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/rest"
	restfake "k8s.io/client-go/rest/fake"
)

var (
	obj1 = &srlinuxv1.Srlinux{
		TypeMeta: metav1.TypeMeta{
			Kind:       "Srlinux",
			APIVersion: "kne.srlinux.dev/v1alpha1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name:       "obj1",
			Namespace:  "test",
			Generation: 1,
		},
		Status: srlinuxv1.SrlinuxStatus{},
		Spec: srlinuxv1.SrlinuxSpec{
			Config:        &srlinuxv1.NodeConfig{},
			NumInterfaces: 2,
			Model:         "fake",
			Version:       "1",
		},
	}

	obj2 = &srlinuxv1.Srlinux{
		TypeMeta: metav1.TypeMeta{
			Kind:       "Srlinux",
			APIVersion: "kne.srlinux.dev/v1alpha1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name:       "obj2",
			Namespace:  "test",
			Generation: 1,
		},
		Status: srlinuxv1.SrlinuxStatus{},
		Spec: srlinuxv1.SrlinuxSpec{
			Config:        &srlinuxv1.NodeConfig{},
			NumInterfaces: 2,
			Model:         "fake1",
			Version:       "2",
		},
	}
)

func setUp(t *testing.T) (*Clientset, *restfake.RESTClient) {
	t.Helper()

	gv := GV()

	fakeClient := &restfake.RESTClient{
		NegotiatedSerializer: scheme.Codecs.WithoutConversion(),
		GroupVersion:         *gv,
		VersionedAPIPath:     GVR().Version,
	}

	cs, err := NewForConfig(&rest.Config{})
	if err != nil {
		t.Fatalf("NewForConfig() failed: %v", err)
	}

	objs := []runtime.Object{obj1, obj2}
	cs.restClient = fakeClient
	f := dynamicfake.NewSimpleDynamicClient(scheme.Scheme, objs...)
	f.PrependReactor("get", "*", func(action ktest.Action) (bool, runtime.Object, error) {
		gAction := action.(ktest.GetAction)
		switch gAction.GetName() {
		case "obj1":
			return true, obj1, nil
		case "obj2":
			return true, obj2, nil
		}

		return false, nil, nil
	})

	f.PrependReactor("update", "*", func(action ktest.Action) (bool, runtime.Object, error) {
		uAction, ok := action.(ktest.UpdateAction)
		if !ok {
			return false, nil, nil
		}

		uObj := uAction.GetObject().(*unstructured.Unstructured)
		sObj := &srlinuxv1.Srlinux{}

		if err := runtime.DefaultUnstructuredConverter.FromUnstructured(uObj.Object, sObj); err != nil {
			return true, nil, fmt.Errorf("failed to convert object: %v", err)
		}

		if sObj.ObjectMeta.Name == "doesnotexist" {
			return true, nil, fmt.Errorf("doesnotexist")
		}

		return true, uAction.GetObject(), nil
	})

	cs.dInterface = f.Resource(GVR())

	return cs, fakeClient
}

func TestCreate(t *testing.T) {
	cs, fakeClient := setUp(t)

	tests := []struct {
		desc    string
		resp    *http.Response
		want    *srlinuxv1.Srlinux
		wantErr string
	}{{
		desc:    "Error",
		wantErr: "TEST ERROR",
	}, {
		desc: "Valid Node",
		resp: &http.Response{
			StatusCode: http.StatusOK,
		},
		want: obj1,
	}}

	for _, tt := range tests {
		fakeClient.Err = nil
		if tt.wantErr != "" {
			fakeClient.Err = fmt.Errorf(tt.wantErr)
		}

		fakeClient.Resp = tt.resp

		if tt.want != nil {
			b, _ := json.Marshal(tt.want)
			tt.resp.Body = io.NopCloser(bytes.NewReader(b))
		}

		t.Run(tt.desc, func(t *testing.T) {
			tc := cs.Srlinux("foo")
			got, err := tc.Create(context.Background(), tt.want)
			if s := errdiff.Substring(err, tt.wantErr); s != "" {
				t.Fatalf("unexpected error: %s", s)
			}
			if tt.wantErr != "" {
				return
			}
			want := tt.want.DeepCopy()
			want.TypeMeta = metav1.TypeMeta{}
			if !reflect.DeepEqual(got, want) {
				t.Fatalf("Create(%+v) failed: diff\n%s", tt.want, pretty.Diff(got, want))
			}
		})
	}
}

func TestList(t *testing.T) {
	cs, fakeClient := setUp(t)
	tests := []struct {
		desc    string
		resp    *http.Response
		want    *srlinuxv1.SrlinuxList
		wantErr string
	}{{
		desc:    "Error",
		wantErr: "TEST ERROR",
	}, {
		desc: "Valid Node",
		resp: &http.Response{
			StatusCode: http.StatusOK,
		},
		want: &srlinuxv1.SrlinuxList{
			Items: []srlinuxv1.Srlinux{*obj1, *obj2},
		},
	}}

	for _, tt := range tests {
		fakeClient.Err = nil

		if tt.wantErr != "" {
			fakeClient.Err = fmt.Errorf(tt.wantErr)
		}

		fakeClient.Resp = tt.resp

		if tt.want != nil {
			b, _ := json.Marshal(tt.want)
			tt.resp.Body = io.NopCloser(bytes.NewReader(b))
		}

		t.Run(tt.desc, func(t *testing.T) {
			tc := cs.Srlinux("foo")

			got, err := tc.List(context.Background(), metav1.ListOptions{})
			if s := errdiff.Substring(err, tt.wantErr); s != "" {
				t.Fatalf("unexpected error: %s", s)
			}

			if tt.wantErr != "" {
				return
			}

			if !reflect.DeepEqual(got, tt.want) {
				t.Fatalf("List() failed: got %v, want %v", got, tt.want)
			}
		})
	}
}

func TestGet(t *testing.T) {
	cs, fakeClient := setUp(t)
	tests := []struct {
		desc    string
		resp    *http.Response
		want    *srlinuxv1.Srlinux
		wantErr string
	}{{
		desc:    "Error",
		wantErr: "TEST ERROR",
	}, {
		desc: "Valid Node",
		resp: &http.Response{
			StatusCode: http.StatusOK,
		},
		want: obj1,
	}}

	for _, tt := range tests {
		fakeClient.Err = nil

		if tt.wantErr != "" {
			fakeClient.Err = fmt.Errorf(tt.wantErr)
		}

		fakeClient.Resp = tt.resp

		if tt.want != nil {
			b, _ := json.Marshal(tt.want)
			tt.resp.Body = io.NopCloser(bytes.NewReader(b))
		}

		t.Run(tt.desc, func(t *testing.T) {
			tc := cs.Srlinux("foo")

			got, err := tc.Get(context.Background(), "test", metav1.GetOptions{})
			if s := errdiff.Substring(err, tt.wantErr); s != "" {
				t.Fatalf("unexpected error: %s", s)
			}

			if tt.wantErr != "" {
				return
			}

			want := tt.want.DeepCopy()
			want.TypeMeta = metav1.TypeMeta{}
			if !reflect.DeepEqual(got, want) {
				t.Fatalf("Get() failed: got %v, want %v", got, want)
			}
		})
	}
}

func TestDelete(t *testing.T) {
	cs, fakeClient := setUp(t)
	tests := []struct {
		desc    string
		resp    *http.Response
		wantErr string
	}{{
		desc:    "Error",
		wantErr: "TEST ERROR",
	}, {
		desc: "Valid Node",
		resp: &http.Response{
			StatusCode: http.StatusOK,
		},
	}}

	for _, tt := range tests {
		fakeClient.Err = nil

		if tt.wantErr != "" {
			fakeClient.Err = fmt.Errorf(tt.wantErr)
		}

		fakeClient.Resp = tt.resp

		t.Run(tt.desc, func(t *testing.T) {
			tc := cs.Srlinux("foo")
			err := tc.Delete(context.Background(), "obj1", metav1.DeleteOptions{})
			if s := errdiff.Substring(err, tt.wantErr); s != "" {
				t.Fatalf("unexpected error: %s", s)
			}
			if tt.wantErr != "" {
				return
			}
		})
	}
}

func TestWatch(t *testing.T) {
	cs, fakeClient := setUp(t)
	tests := []struct {
		desc    string
		resp    *http.Response
		want    *watch.Event
		wantErr string
	}{{
		desc:    "Error",
		wantErr: "TEST ERROR",
	}}

	for _, tt := range tests {
		fakeClient.Err = nil

		if tt.wantErr != "" {
			fakeClient.Err = fmt.Errorf(tt.wantErr)
		}

		fakeClient.Resp = tt.resp

		if tt.want != nil {
			b, _ := json.Marshal(tt.want)
			tt.resp.Body = io.NopCloser(bytes.NewReader(b))
		}

		t.Run(tt.desc, func(t *testing.T) {
			tc := cs.Srlinux("foo")
			w, err := tc.Watch(context.Background(), metav1.ListOptions{})
			if s := errdiff.Substring(err, tt.wantErr); s != "" {
				t.Fatalf("unexpected error: %s", s)
			}

			if tt.wantErr != "" {
				return
			}

			e := <-w.ResultChan()
			if !reflect.DeepEqual(e, tt.want) {
				t.Fatalf("Watch() failed: got %v, want %v", e, tt.want)
			}
		})
	}
}

func TestUnstructured(t *testing.T) {
	cs, _ := setUp(t)
	tests := []struct {
		desc    string
		in      string
		want    *srlinuxv1.Srlinux
		wantErr string
	}{{
		desc:    "Error",
		in:      "missingObj",
		wantErr: `"missingObj" not found`,
	}, {
		desc: "Valid Node",
		in:   obj1.GetObjectMeta().GetName(),
		want: obj1,
	}, {
		desc: "Valid Node",
		in:   obj2.GetObjectMeta().GetName(),
		want: obj2,
	}}

	for _, tt := range tests {
		t.Run(tt.desc, func(t *testing.T) {
			tc := cs.Srlinux("test")
			got, err := tc.Unstructured(context.Background(), tt.in, metav1.GetOptions{})
			if s := errdiff.Substring(err, tt.wantErr); s != "" {
				t.Fatalf("unexpected error: %s", s)
			}

			if tt.wantErr != "" {
				return
			}

			uObj1 := &srlinuxv1.Srlinux{}
			if err := runtime.DefaultUnstructuredConverter.FromUnstructured(got.Object, uObj1); err != nil {
				t.Fatalf("failed to turn response into a topology: %v", err)
			}

			if !reflect.DeepEqual(uObj1, tt.want) {
				t.Fatalf("Unstructured(%q) failed: got %+v, want %+v", tt.in, uObj1, tt.want)
			}
		})
	}
}

func TestUpdate(t *testing.T) {
	cs, _ := setUp(t)
	tests := []struct {
		desc    string
		want    *srlinuxv1.Srlinux
		wantErr string
	}{{
		desc: "Error",
		want: &srlinuxv1.Srlinux{
			TypeMeta: metav1.TypeMeta{
				Kind:       "Srlinux",
				APIVersion: "kne.srlinux.dev/v1alpha1",
			},
			ObjectMeta: metav1.ObjectMeta{
				Name:       "doesnotexist",
				Namespace:  "test",
				Generation: 1,
			},
		},
		wantErr: "doesnotexist",
	}, {
		desc: "Valid Topology",
		want: obj1,
	}}

	for _, tt := range tests {
		t.Run(tt.desc, func(t *testing.T) {
			sc := cs.Srlinux("test")
			updateObj := tt.want.DeepCopy()
			updateObj.Spec.Version = "updated version"

			update, err := runtime.DefaultUnstructuredConverter.ToUnstructured(updateObj)
			if err != nil {
				t.Fatalf("failed to generate update: %v", err)
			}

			got, err := sc.Update(context.Background(), &unstructured.Unstructured{
				Object: update,
			}, metav1.UpdateOptions{})

			if s := errdiff.Substring(err, tt.wantErr); s != "" {
				t.Fatalf("unexpected error: %s", s)
			}

			if tt.wantErr != "" {
				return
			}

			want := tt.want.DeepCopy()
			want.TypeMeta = metav1.TypeMeta{}
			if !reflect.DeepEqual(got, updateObj) {
				t.Fatalf("Update() failed: got %+v, want %+v", got, want)
			}
		})
	}
}
<|endoftext|>


<commit_before>package images

import (
	"fmt"
	"strings"

	g "github.com/onsi/ginkgo"
	o "github.com/onsi/gomega"

	e2e "k8s.io/kubernetes/test/e2e/framework"

	exutil "github.com/openshift/origin/test/extended/util"
)

var _ = g.Describe("[sig-imageregistry][Serial][Suite:openshift/registry/serial] Image signature workflow", func() {
	defer g.GinkgoRecover()

	var (
		oc                 = exutil.NewCLI("registry-signing")
		signerBuildFixture = exutil.FixturePath("testdata", "signer-buildconfig.yaml")
	)

	g.It("can push a signed image to openshift registry and verify it", func() {
		g.By("building a signer image that knows how to sign images")
		output, err := oc.Run("create").Args("-f", signerBuildFixture).Output()
		if err != nil {
			fmt.Fprintf(g.GinkgoWriter, "%s\n\n", output)
		}
		o.Expect(err).NotTo(o.HaveOccurred())
		err = exutil.WaitForAnImageStreamTag(oc, oc.Namespace(), "signer", "latest")
		containerLog, _ := oc.Run("logs").Args("builds/signer-1").Output()
		e2e.Logf("signer build logs:\n%s\n", containerLog)
		o.Expect(err).NotTo(o.HaveOccurred())

		g.By("looking up the openshift registry URL")
		registryURL, err := GetDockerRegistryURL(oc)
		signerImage := fmt.Sprintf("%s/%s/signer:latest", registryURL, oc.Namespace())
		signedImage := fmt.Sprintf("%s/%s/signed:latest", registryURL, oc.Namespace())
		o.Expect(err).NotTo(o.HaveOccurred())

		g.By("obtaining bearer token for the test user")
		user := oc.Username()
		token, err := oc.Run("whoami").Args("-t").Output()
		o.Expect(err).NotTo(o.HaveOccurred())

		g.By("granting the image-signer role to test user")
		_, err = oc.AsAdmin().Run("adm").Args("policy", "add-cluster-role-to-user", "system:image-signer", oc.Username()).Output()
		o.Expect(err).NotTo(o.HaveOccurred())

		// TODO: The test user needs to be able to unlink the /dev/random which is owned by a
		// root. This cannot be done during image build time because the /dev is plugged into
		// container after it starts. This SCC could be avoided in the future when /dev/random
		// issue is fixed in Docker.
		g.By("granting the anyuid scc to test user")
		_, err = oc.AsAdmin().Run("adm").Args("policy", "add-scc-to-user", "anyuid", oc.Username()).Output()
		o.Expect(err).NotTo(o.HaveOccurred())

		g.By("preparing the image stream where the signed image will be pushed")
		_, err = oc.Run("create").Args("imagestream", "signed").Output()
		o.Expect(err).NotTo(o.HaveOccurred())

		g.By("granting the image-auditor role to test user")
		_, err = oc.AsAdmin().Run("adm").Args("policy", "add-cluster-role-to-user", "system:image-auditor", oc.Username()).Output()
		o.Expect(err).NotTo(o.HaveOccurred())

		pod, err := exutil.NewPodExecutor(oc, "sign-and-push", signerImage)
		o.Expect(err).NotTo(o.HaveOccurred())

		// Generate GPG key
		// Note that we need to replace the /dev/random with /dev/urandom to get more entropy
		// into container so we can successfully generate the GPG keypair.
		g.By("creating dummy GPG key")
		out, err := pod.Exec("rm -f /dev/random; ln -sf /dev/urandom /dev/random && " +
			"GNUPGHOME=/var/lib/origin/gnupg gpg2 --batch --gen-key --pinentry-mode=loopback --passphrase '' dummy_key.conf && " +
			"GNUPGHOME=/var/lib/origin/gnupg gpg2 --output=gnupg/pubring.gpg --export joe@foo.bar")
		o.Expect(err).NotTo(o.HaveOccurred())
		o.Expect(out).To(o.ContainSubstring("keybox '/var/lib/origin/gnupg/pubring.kbx' created"))

		// Create kubeconfig for oc
		g.By("logging as a test user")
		out, err = pod.Exec("oc login https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT --token=" + token + " --certificate-authority=/run/secrets/kubernetes.io/serviceaccount/ca.crt")
		o.Expect(err).NotTo(o.HaveOccurred())
		o.Expect(out).To(o.ContainSubstring("Logged in"))

		// Sign and copy the memcached image into target image stream tag
		g.By("signing a just-built image and pushing it into openshift registry")
		out, err = pod.Exec(strings.Join([]string{
			"GNUPGHOME=/var/lib/origin/gnupg",
			"skopeo", "--debug",
			"copy", "--sign-by", "joe@foo.bar",
			"--src-creds=" + user + ":" + token,
			"--dest-creds=" + user + ":" + token,

			// Expect to use /run/secrets/kubernetes.io/serviceaccount/ca.crt
			"--src-cert-dir=/run/secrets/kubernetes.io/serviceaccount",
			"--dest-cert-dir=/run/secrets/kubernetes.io/serviceaccount",

			"docker://" + signerImage,
			"docker://" + signedImage,
		}, " "))
		fmt.Fprintf(g.GinkgoWriter, "output: %s\n", out)
		o.Expect(err).NotTo(o.HaveOccurred())

		err = exutil.WaitForAnImageStreamTag(oc, oc.Namespace(), "signed", "latest")
		o.Expect(err).NotTo(o.HaveOccurred())

		g.By("obtaining the signed:latest image name")
		imageName, err := oc.Run("get").Args("istag", "signed:latest", "-o", "jsonpath={.image.metadata.name}").Output()
		o.Expect(err).NotTo(o.HaveOccurred())

		g.By("expecting the image to have unverified signature")
		out, err = oc.Run("describe").Args("istag", "signed:latest").Output()
		o.Expect(err).NotTo(o.HaveOccurred())
		e2e.Logf(out)
		o.Expect(out).To(o.ContainSubstring("Unverified"))

		out, err = pod.Exec(strings.Join([]string{
			"GNUPGHOME=/var/lib/origin/gnupg",
			"oc", "adm",
			"verify-image-signature",
			"--insecure=true", // TODO: import the ca certificate into the signing pod
			"--loglevel=8",
			imageName,
			"--expected-identity=" + signedImage,
			"--save",
		}, " "))
		fmt.Fprintf(g.GinkgoWriter, "output: %s\n", out)
		o.Expect(err).NotTo(o.HaveOccurred())
		o.Expect(out).To(o.ContainSubstring("identity is now confirmed"))

		g.By("checking the signature is present on the image and it is now verified")
		out, err = oc.Run("describe").Args("istag", "signed:latest").Output()
		o.Expect(err).NotTo(o.HaveOccurred())
		o.Expect(out).To(o.ContainSubstring("Verified"))
	})
})
<commit_msg>Bug 2057990: Add debug info for signature test<commit_after>package images

import (
	"fmt"
	"strings"

	g "github.com/onsi/ginkgo"
	o "github.com/onsi/gomega"

	e2e "k8s.io/kubernetes/test/e2e/framework"

	exutil "github.com/openshift/origin/test/extended/util"
)

var _ = g.Describe("[sig-imageregistry][Serial][Suite:openshift/registry/serial] Image signature workflow", func() {
	defer g.GinkgoRecover()

	var (
		oc                 = exutil.NewCLI("registry-signing")
		signerBuildFixture = exutil.FixturePath("testdata", "signer-buildconfig.yaml")
	)

	g.AfterEach(func() {
		if g.CurrentGinkgoTestDescription().Failed {
			exutil.DumpPodStates(oc)
			exutil.DumpConfigMapStates(oc)
			exutil.DumpPodLogsStartingWith("", oc)
		}
	})

	g.It("can push a signed image to openshift registry and verify it", func() {
		g.By("building a signer image that knows how to sign images")
		output, err := oc.Run("create").Args("-f", signerBuildFixture).Output()
		if err != nil {
			fmt.Fprintf(g.GinkgoWriter, "%s\n\n", output)
		}
		o.Expect(err).NotTo(o.HaveOccurred())
		err = exutil.WaitForAnImageStreamTag(oc, oc.Namespace(), "signer", "latest")
		o.Expect(err).NotTo(o.HaveOccurred())

		g.By("looking up the openshift registry URL")
		registryURL, err := GetDockerRegistryURL(oc)
		signerImage := fmt.Sprintf("%s/%s/signer:latest", registryURL, oc.Namespace())
		signedImage := fmt.Sprintf("%s/%s/signed:latest", registryURL, oc.Namespace())
		o.Expect(err).NotTo(o.HaveOccurred())

		g.By("obtaining bearer token for the test user")
		user := oc.Username()
		token, err := oc.Run("whoami").Args("-t").Output()
		o.Expect(err).NotTo(o.HaveOccurred())

		g.By("granting the image-signer role to test user")
		_, err = oc.AsAdmin().Run("adm").Args("policy", "add-cluster-role-to-user", "system:image-signer", oc.Username()).Output()
		o.Expect(err).NotTo(o.HaveOccurred())

		// TODO: The test user needs to be able to unlink the /dev/random which is owned by a
		// root. This cannot be done during image build time because the /dev is plugged into
		// container after it starts. This SCC could be avoided in the future when /dev/random
		// issue is fixed in Docker.
		g.By("granting the anyuid scc to test user")
		_, err = oc.AsAdmin().Run("adm").Args("policy", "add-scc-to-user", "anyuid", oc.Username()).Output()
		o.Expect(err).NotTo(o.HaveOccurred())

		g.By("preparing the image stream where the signed image will be pushed")
		_, err = oc.Run("create").Args("imagestream", "signed").Output()
		o.Expect(err).NotTo(o.HaveOccurred())

		g.By("granting the image-auditor role to test user")
		_, err = oc.AsAdmin().Run("adm").Args("policy", "add-cluster-role-to-user", "system:image-auditor", oc.Username()).Output()
		o.Expect(err).NotTo(o.HaveOccurred())

		pod, err := exutil.NewPodExecutor(oc, "sign-and-push", signerImage)
		o.Expect(err).NotTo(o.HaveOccurred())

		// Generate GPG key
		// Note that we need to replace the /dev/random with /dev/urandom to get more entropy
		// into container so we can successfully generate the GPG keypair.
		g.By("creating dummy GPG key")
		out, err := pod.Exec("rm -f /dev/random; ln -sf /dev/urandom /dev/random && " +
			"GNUPGHOME=/var/lib/origin/gnupg gpg2 --batch --gen-key --pinentry-mode=loopback --passphrase '' dummy_key.conf && " +
			"GNUPGHOME=/var/lib/origin/gnupg gpg2 --output=gnupg/pubring.gpg --export joe@foo.bar")
		o.Expect(err).NotTo(o.HaveOccurred())
		o.Expect(out).To(o.ContainSubstring("keybox '/var/lib/origin/gnupg/pubring.kbx' created"))

		// Create kubeconfig for oc
		g.By("logging as a test user")
		out, err = pod.Exec("oc login https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT --token=" + token + " --certificate-authority=/run/secrets/kubernetes.io/serviceaccount/ca.crt")
		o.Expect(err).NotTo(o.HaveOccurred())
		o.Expect(out).To(o.ContainSubstring("Logged in"))

		// Sign and copy the memcached image into target image stream tag
		g.By("signing a just-built image and pushing it into openshift registry")
		out, err = pod.Exec(strings.Join([]string{
			"GNUPGHOME=/var/lib/origin/gnupg",
			"skopeo", "--debug",
			"copy", "--sign-by", "joe@foo.bar",
			"--src-creds=" + user + ":" + token,
			"--dest-creds=" + user + ":" + token,

			// Expect to use /run/secrets/kubernetes.io/serviceaccount/ca.crt
			"--src-cert-dir=/run/secrets/kubernetes.io/serviceaccount",
			"--dest-cert-dir=/run/secrets/kubernetes.io/serviceaccount",

			"docker://" + signerImage,
			"docker://" + signedImage,
		}, " "))
		fmt.Fprintf(g.GinkgoWriter, "output: %s\n", out)
		o.Expect(err).NotTo(o.HaveOccurred())

		err = exutil.WaitForAnImageStreamTag(oc, oc.Namespace(), "signed", "latest")
		o.Expect(err).NotTo(o.HaveOccurred())

		g.By("obtaining the signed:latest image name")
		imageName, err := oc.Run("get").Args("istag", "signed:latest", "-o", "jsonpath={.image.metadata.name}").Output()
		o.Expect(err).NotTo(o.HaveOccurred())

		g.By("expecting the image to have unverified signature")
		out, err = oc.Run("describe").Args("istag", "signed:latest").Output()
		o.Expect(err).NotTo(o.HaveOccurred())
		e2e.Logf(out)
		o.Expect(out).To(o.ContainSubstring("Unverified"))

		out, err = pod.Exec(strings.Join([]string{
			"GNUPGHOME=/var/lib/origin/gnupg",
			"oc", "adm",
			"verify-image-signature",
			"--insecure=true", // TODO: import the ca certificate into the signing pod
			"--loglevel=8",
			imageName,
			"--expected-identity=" + signedImage,
			"--save",
		}, " "))
		fmt.Fprintf(g.GinkgoWriter, "output: %s\n", out)
		o.Expect(err).NotTo(o.HaveOccurred())
		o.Expect(out).To(o.ContainSubstring("identity is now confirmed"))

		g.By("checking the signature is present on the image and it is now verified")
		out, err = oc.Run("describe").Args("istag", "signed:latest").Output()
		o.Expect(err).NotTo(o.HaveOccurred())
		o.Expect(out).To(o.ContainSubstring("Verified"))
	})
})
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/eaciit/gocr"
)

var (
	samplePath = func() string {
		d, _ := os.Getwd()
		return d
	}() + "/../../train_data/"
)

var (
	modelPath = func() string {
		d, _ := os.Getwd()
		return d
	}() + "/../../model/"
)

func main() {
	// Downloading english font dataset and index.csv
	d, _ := os.Getwd()
	//
	// Load the sample data and save it in .gob file
	// err := gocr.TrainAverage(d+"/English/Fnt/", d+"/English/")
	// if err != nil {
	// 	panic(err)
	// }

	// Read the image
	image, err := gocr.ReadImage(d + "/imagetext_2.png")
	if err != nil {
		panic(err)
	}
	im := gocr.ImageToBinaryArray(image)
	gocr.ImageMatrixToImage(im, d+"/result/image.png", 255)

}
<commit_msg>Fixing error in examples<commit_after>package main

import (
	"os"

	"github.com/eaciit/gocr"
)

var (
	samplePath = func() string {
		d, _ := os.Getwd()
		return d
	}() + "/../../train_data/"
)

var (
	modelPath = func() string {
		d, _ := os.Getwd()
		return d
	}() + "/../../model/"
)

func main() {
	// Downloading english font dataset and index.csv
	d, _ := os.Getwd()
	//
	// Load the sample data and save it in .gob file
	// err := gocr.TrainAverage(d+"/English/Fnt/", d+"/English/")
	// if err != nil {
	// 	panic(err)
	// }

	// Read the image
	image, err := gocr.ReadImage(d + "/imagetext_2.png")
	if err != nil {
		panic(err)
	}

	im := gocr.ImageToGraysclaeArray(image)
	gocr.ImageMatrixToImage(im, d+"/result/image.png", 255)

}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
    "time"
	"sort"
)

var colors = map[string]string{
	"header": "\033[95m",
	"blue":   "\033[94m",
	"green":  "\033[92m",
	"yellow": "\033[93m",
	"red":    "\033[91m",
	"bold":   "\033[1m",
	"end":    "\033[0m",
}

func color(color string, s string) string {
	return fmt.Sprintf("%s%s%s", colors[color], s, colors["end"])
}

var rexes = map[string]*regexp.Regexp{
	"pep8":      regexp.MustCompile(`\w+:(\d+):(\d+):\s(\w+)\s(.+)(?m)$`),
	"pylint":    regexp.MustCompile(`(?m)^(\w):\s+(\d+),\s*(\d+):\s(.+)$`),
	"blameName": regexp.MustCompile(`\(([\w\s]+)\d{4}`),
    "goBuild": regexp.MustCompile(`\w+:(\d+):\s(.+)(?m)$`),
}

var config = map[string]string{
	"workingDir": "",
}

type Environment struct {
	gitPath string
	gitName string
}

func (c *Environment) GitPath() string {
	if len(c.gitPath) == 0 {
		cmd := exec.Command("git", "rev-parse", "--show-toplevel")
		out, err := cmd.Output()
		if err != nil {
			log.Fatal("Failed to find git parent path.")
		}
		c.gitPath = strings.TrimSpace(string(out))
	}
	return c.gitPath
}

func (c *Environment) GitName() string {
	if len(c.gitName) == 0 {
		cmd := exec.Command("git", "config", "user.name")
		out, err := cmd.Output()
		if err != nil {
			c.gitName = "None"
		} else {
			c.gitName = strings.TrimSpace(string(out))
		}
	}
	return c.gitName
}

func (c Environment) CurrentGitBranch() string {
	cmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD")
	out, err := cmd.Output()
	if err != nil {
		log.Fatal("Failed to get git branch")
	}
	return strings.TrimSpace(string(out))
}

var env = Environment{}

type Times []*time.Time
func (s Times) Len() int { return len(s) }
func (s Times) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

type ByTime struct{ Times }
func (s ByTime) Less(i, j int) bool { return s.Times[i].Before(*s.Times[j]) }

type ModifiedTimes struct {
	timeMap map[string]time.Time
}

func (m *ModifiedTimes) CheckTime(path string) bool {
	hasChanged := false

	fileInfo, err := os.Stat(path)
	if err != nil {
		log.Println("Couldn't access ", path, ". Skipping it.")
	} else {
		if fileInfo != nil {
			mt := fileInfo.ModTime()
			if storedTime, ok := m.timeMap[path]; ok {
				if !storedTime.Equal(mt) {
					hasChanged = true
				}
			} else {
				hasChanged = true
			}
			if hasChanged {
				m.timeMap[path] = mt
			}
		}
	}
	return hasChanged
}

func (m ModifiedTimes) MostRecent() string {
	var returnPath string
	var mostRecentTime time.Time
	for path, time := range m.timeMap {
		if mostRecentTime.Before(time) {
			returnPath = path
			mostRecentTime = time
		}
	}
	return returnPath
}

func (m ModifiedTimes) PathsByModTime() []string {
    size := len(m.timeMap)
    times := make(Times, size)
    timesToPaths := make(map[time.Time]string, size)
    returnSlice := make([]string, size)
    i := 0
    for path, time_ := range m.timeMap {
        times[i] = &time_
        timesToPaths[time_] = path
        i += 1
    }
    sort.Sort(ByTime{times})

    for i, time_ := range times {
        log.Print("time_: ", time_)
        returnSlice[i] = timesToPaths[*time_]
    }
    return returnSlice
}

func NewModifiedTimes() *ModifiedTimes {
    return &ModifiedTimes{timeMap: make(map[string]time.Time, 9)}
}

type Wart struct {
	Reporter  string
	Line      int
	Column    int
	IssueCode string
	Message   string
}

func (w Wart) String() string {
	return fmt.Sprintf("%d: [%s %s] %s", w.Line, w.Reporter, w.IssueCode, w.Message)
}

type TargetFile struct {
	Path         string
	ContentLines []string
	BlameLines   []string
	Warts        map[int][]Wart
}

func (tf *TargetFile) Blame() {
	os.Chdir(config["workingDir"])
	cmd := exec.Command("git", "blame", tf.Path)
	results, err := cmd.Output()
	if err != nil {
		tf.BlameLines = make([]string, 0)
	} else {
    	tf.BlameLines = strings.Split(string(results), "\n")
    }
}

func NewWart(reporter string, line string, column string, issueCode string, message string) Wart {

	line64, err := strconv.ParseInt(line, 10, 0)
	if err != nil {
		log.Fatal("Failed parsing line number %s", line)
	}
	col64, err := strconv.ParseInt(column, 10, 0)
	if err != nil {
		log.Fatal("Failed parsing column number %s", column)
	}
	w := Wart{
		Reporter:  reporter,
		Line:      int(line64),
		Column:    int(col64),
		IssueCode: issueCode,
		Message:   message,
	}
	return w
}

func (tf TargetFile) ExtEquals(ext string) bool {
    return filepath.Ext(tf.Path) == ext
}

func (tf *TargetFile) AddWart(wart Wart) {
    if _, ok := tf.Warts[wart.Line]; !ok {
        tf.Warts[wart.Line] = make([]Wart, 0)
    }
    tf.Warts[wart.Line] = append(tf.Warts[wart.Line], wart)
}

func (tf *TargetFile) Pep8() {
	if filepath.Ext(tf.Path) != ".py" {
		return
	}
	cmd := exec.Command("pep8", tf.Path)
	results, _ := cmd.Output()
	parsed := rexes["pep8"].FindAllStringSubmatch(string(results), -1)
	for _, group := range parsed {
		wart := NewWart("PEP8", group[1], group[2], group[3], group[4])
        tf.AddWart(wart)
	}
}

func (tf *TargetFile) GoBuild() {
    if !tf.ExtEquals(".go") { return }
    os.Chdir(config["workingDir"])
    _, file := filepath.Split(tf.Path)
    cmd := exec.Command("go", "build", file)
    results, _ := cmd.CombinedOutput()
    parsed := rexes["goBuild"].FindAllStringSubmatch(string(results), -1)
    for _, group := range parsed {
        wart := NewWart("gobuild", group[1], "0", "-", group[2])
        tf.AddWart(wart)
    }
}

func (tf *TargetFile) PyLint() {
	if filepath.Ext(tf.Path) != ".py" {
		return
	}
	cmd := exec.Command("pylint", "--output-format=text", tf.Path)
	results, _ := cmd.Output()
	parsed := rexes["pylint"].FindAllStringSubmatch(string(results), -1)
    for _, group := range parsed {
        wart := NewWart("Pylint", group[2], group[3], group[1], group[4])
        tf.AddWart(wart)
    }
}

func (tf TargetFile) BlameName(line int) string {
    if len(tf.BlameLines) == 0 {
        return "-"
    }
	match := rexes["blameName"].FindStringSubmatch(tf.BlameLines[line - 1])
	return strings.TrimSpace(match[1])
}

func NewTargetFile(path string) *TargetFile {
	tf := TargetFile{
		Path:  path,
		Warts: make(map[int][]Wart),
	}
	bytes, err := ioutil.ReadFile(path)
	if err != nil {
		log.Fatal("Unable to read file ", path)
	}
	tf.ContentLines = strings.Split(string(bytes), "\n")
	tf.Blame()
	tf.Pep8()
    tf.PyLint()
    tf.GoBuild()
	return &tf
}

func getDirFiles(dirPath string) []string {
	files, err := ioutil.ReadDir(dirPath)
	if err != nil {
		log.Fatal("Could not read directory", dirPath)
	}
	filepaths := make([]string, len(files))
	for i, fileInfo := range files {
		filepaths[i] = path.Join(dirPath, fileInfo.Name())
	}
	return filterFiles(filepaths)
}

func gitBranchFiles() []string {
	dirtyFilesCmd := exec.Command("git", "diff", "--name-only")
	dirtyFiles, err := dirtyFilesCmd.Output()
	if err != nil {
		log.Fatal("Failed to list dirty files")
	}

	branchFilesCmd := exec.Command("git", "diff", "--name-only", "master..HEAD")
	branchFiles, err := branchFilesCmd.Output()
	if err != nil {
		log.Print("branchFiles: ", branchFiles)
		log.Fatal("Failed to list branch files:", err)
	}

	allFiles := append(
		strings.Split(string(dirtyFiles), "\n"),
		strings.Split(string(branchFiles), "\n")...,
	)
	return filterFiles(allFiles)
}

func filterFiles(filepaths []string) []string {
	goodstuffs := make([]string, 0)
	for _, filepath := range filepaths {
		if len(filepath) > 0 {
			match, err := regexp.MatchString(".py|.go", path.Ext(filepath))
			if err != nil {
				log.Fatalf("Failed checking %s's extension", filepath)
			}
            if match == true {
                if !strings.HasPrefix(filepath, "/") {
                    filepath = path.Join(config["workingDir"], filepath)
                }
				goodstuffs = append(goodstuffs, filepath)
			}
		}
	}
	return goodstuffs
}

func printWarts(targetFile *TargetFile) {
	fmt.Println(color("green", targetFile.Path))
	if len(targetFile.Warts) == 0 {
		fmt.Println(color("bold", "- All clean!"))
	}
	for line, warts := range targetFile.Warts {
		blameName := targetFile.BlameName(line)
		nameColor := "blue"
		if blameName == env.GitName() {
			nameColor = "yellow"
		}
		fmt.Printf(
			"%s: (%s) %s\n",
			color("bold", fmt.Sprintf("%d", line)),
			color(nameColor, blameName),
			strings.TrimSpace(targetFile.ContentLines[line-1]),
		)
		for _, wart := range warts {
			fmt.Printf(
				"    [%s %s] %s\n",
				wart.Reporter,
				wart.IssueCode,
				color("bold", wart.Message),
			)
		}
	}
}

func clear() {
	cmd := exec.Command("clear")
	cmd.Stdout = os.Stdout
	cmd.Run()
    fmt.Println(color("header", "--- LintBlame ---"))
}

func makeTargetFile(filepath string, c chan *TargetFile) {
	tf := NewTargetFile(filepath)
	c <- tf
}

func update(filepaths []string) {
	c := make(chan *TargetFile)
	for _, path := range filepaths {
		go makeTargetFile(path, c)
	}
	cleared := false
	for i := 0; i < len(filepaths); i++ {
		if !cleared {
			clear()
			cleared = true
		}
		tf := <-c
		printWarts(tf)
        fmt.Println("")
	}
}

func initialPaths() []string {
    var branch bool
    flag.BoolVar(&branch, "b", false, "Run against current branch")
    flag.Parse()

    var filepaths []string
    if branch {
        config["workingDir"] = env.GitPath()
        filepaths = gitBranchFiles()
    } else {
        args := flag.Args()
        if len(args) > 0 {
            target := args[0]
            stat, err := os.Stat(target)
            if err != nil {
                log.Fatal("Unable to process argument: ", target)
            }
            absPath, err := filepath.Abs(target)
            if err != nil {
                log.Fatal("Unable to get absolute path of ", target)
            }
            if stat.IsDir() {
                config["workingDir"] = absPath
                filepaths = getDirFiles(absPath)
            } else {
                dir, _ := filepath.Split(absPath)
                config["workingDir"] = dir
                filepaths = filterFiles([]string{absPath})
            }
        }
    }
    return filepaths
}

func main() {
    filepaths := initialPaths()
	modTimes := NewModifiedTimes()

	for _, file := range filepaths {
		modTimes.CheckTime(file)
	}
	update(modTimes.PathsByModTime())
	for {
		runUpdate := false
		for _, file := range filepaths {
			if modTimes.CheckTime(file) {
				runUpdate = true
				break
			}
		}
		if runUpdate {
			update(modTimes.PathsByModTime())
		}
		time.Sleep(1 * time.Second)
	}
}
<commit_msg>I _think_ sorting is working now?<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
    "time"
	"sort"
)

var colors = map[string]string{
	"header": "\033[95m",
	"blue":   "\033[94m",
	"green":  "\033[92m",
	"yellow": "\033[93m",
	"red":    "\033[91m",
	"bold":   "\033[1m",
	"end":    "\033[0m",
}

func color(color string, s string) string {
	return fmt.Sprintf("%s%s%s", colors[color], s, colors["end"])
}

var rexes = map[string]*regexp.Regexp{
	"pep8":      regexp.MustCompile(`\w+:(\d+):(\d+):\s(\w+)\s(.+)(?m)$`),
	"pylint":    regexp.MustCompile(`(?m)^(\w):\s+(\d+),\s*(\d+):\s(.+)$`),
	"blameName": regexp.MustCompile(`\(([\w\s]+)\d{4}`),
    "goBuild": regexp.MustCompile(`\w+:(\d+):\s(.+)(?m)$`),
}

var config = map[string]string{
	"workingDir": "",
}

type Environment struct {
	gitPath string
	gitName string
}

func (c *Environment) GitPath() string {
	if len(c.gitPath) == 0 {
		cmd := exec.Command("git", "rev-parse", "--show-toplevel")
		out, err := cmd.Output()
		if err != nil {
			log.Fatal("Failed to find git parent path.")
		}
		c.gitPath = strings.TrimSpace(string(out))
	}
	return c.gitPath
}

func (c *Environment) GitName() string {
	if len(c.gitName) == 0 {
		cmd := exec.Command("git", "config", "user.name")
		out, err := cmd.Output()
		if err != nil {
			c.gitName = "None"
		} else {
			c.gitName = strings.TrimSpace(string(out))
		}
	}
	return c.gitName
}

func (c Environment) CurrentGitBranch() string {
	cmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD")
	out, err := cmd.Output()
	if err != nil {
		log.Fatal("Failed to get git branch")
	}
	return strings.TrimSpace(string(out))
}

var env = Environment{}

type Times []time.Time
func (s Times) Len() int { return len(s) }
func (s Times) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

type ByTime struct{ Times }
func (s ByTime) Less(i, j int) bool { return s.Times[i].Before(s.Times[j]) }

type ModifiedTimes struct {
	timeMap map[string]time.Time
}

func (m *ModifiedTimes) CheckTime(path string) bool {
	hasChanged := false

    fileInfo, err := os.Stat(path)
	if err != nil {
		log.Println("Couldn't access ", path, ". Skipping it.")
	} else {
		if fileInfo != nil {
			mt := fileInfo.ModTime()
            if storedTime, ok := m.timeMap[path]; ok {
                if !storedTime.Equal(mt) {
                    hasChanged = true
                }
            } else {
                hasChanged = true
            }
            if hasChanged {
                m.timeMap[path] = mt
            }
		}
	}
	return hasChanged
}

func (m ModifiedTimes) MostRecent() string {
	var returnPath string
	var mostRecentTime time.Time
	for path, time := range m.timeMap {
		if mostRecentTime.Before(time) {
			returnPath = path
			mostRecentTime = time
		}
	}
	return returnPath
}

func (m ModifiedTimes) PathsByModTime() []string {
    size := len(m.timeMap)
    times := make(Times, size)
    timesToPaths := make(map[time.Time]string, size)
    returnSlice := make([]string, size)
    i := 0
    for path, time_ := range m.timeMap {
        times[i] = time_
        timesToPaths[time_] = path
        i += 1
    }
    sort.Sort(ByTime{times})

    for i, time_ := range times {
        returnSlice[i] = timesToPaths[time_]
    }
    return returnSlice
}

func NewModifiedTimes() *ModifiedTimes {
    return &ModifiedTimes{timeMap: make(map[string]time.Time, 9)}
}

type Wart struct {
	Reporter  string
	Line      int
	Column    int
	IssueCode string
	Message   string
}

func (w Wart) String() string {
	return fmt.Sprintf("%d: [%s %s] %s", w.Line, w.Reporter, w.IssueCode, w.Message)
}

type TargetFile struct {
	Path         string
	ContentLines []string
	BlameLines   []string
	Warts        map[int][]Wart
}

func (tf *TargetFile) Blame() {
	os.Chdir(config["workingDir"])
	cmd := exec.Command("git", "blame", tf.Path)
	results, err := cmd.Output()
	if err != nil {
		tf.BlameLines = make([]string, 0)
	} else {
    	tf.BlameLines = strings.Split(string(results), "\n")
    }
}

func NewWart(reporter string, line string, column string, issueCode string, message string) Wart {

	line64, err := strconv.ParseInt(line, 10, 0)
	if err != nil {
		log.Fatal("Failed parsing line number %s", line)
	}
	col64, err := strconv.ParseInt(column, 10, 0)
	if err != nil {
		log.Fatal("Failed parsing column number %s", column)
	}
	w := Wart{
		Reporter:  reporter,
		Line:      int(line64),
		Column:    int(col64),
		IssueCode: issueCode,
		Message:   message,
	}
	return w
}

func (tf TargetFile) ExtEquals(ext string) bool {
    return filepath.Ext(tf.Path) == ext
}

func (tf *TargetFile) AddWart(wart Wart) {
    if _, ok := tf.Warts[wart.Line]; !ok {
        tf.Warts[wart.Line] = make([]Wart, 0)
    }
    tf.Warts[wart.Line] = append(tf.Warts[wart.Line], wart)
}

func (tf *TargetFile) Pep8() {
	if filepath.Ext(tf.Path) != ".py" {
		return
	}
	cmd := exec.Command("pep8", tf.Path)
	results, _ := cmd.Output()
	parsed := rexes["pep8"].FindAllStringSubmatch(string(results), -1)
	for _, group := range parsed {
		wart := NewWart("PEP8", group[1], group[2], group[3], group[4])
        tf.AddWart(wart)
	}
}

func (tf *TargetFile) GoBuild() {
    if !tf.ExtEquals(".go") { return }
    os.Chdir(config["workingDir"])
    _, file := filepath.Split(tf.Path)
    cmd := exec.Command("go", "build", file)
    results, _ := cmd.CombinedOutput()
    parsed := rexes["goBuild"].FindAllStringSubmatch(string(results), -1)
    for _, group := range parsed {
        wart := NewWart("gobuild", group[1], "0", "-", group[2])
        tf.AddWart(wart)
    }
}

func (tf *TargetFile) PyLint() {
	if filepath.Ext(tf.Path) != ".py" {
		return
	}
	cmd := exec.Command("pylint", "--output-format=text", tf.Path)
	results, _ := cmd.Output()
	parsed := rexes["pylint"].FindAllStringSubmatch(string(results), -1)
    for _, group := range parsed {
        wart := NewWart("Pylint", group[2], group[3], group[1], group[4])
        tf.AddWart(wart)
    }
}

func (tf TargetFile) BlameName(line int) string {
    if len(tf.BlameLines) == 0 {
        return "-"
    }
	match := rexes["blameName"].FindStringSubmatch(tf.BlameLines[line - 1])
	return strings.TrimSpace(match[1])
}

func NewTargetFile(path string) *TargetFile {
	tf := TargetFile{
		Path:  path,
		Warts: make(map[int][]Wart),
	}
	bytes, err := ioutil.ReadFile(path)
	if err != nil {
		log.Fatal("Unable to read file ", path)
	}
	tf.ContentLines = strings.Split(string(bytes), "\n")
	tf.Blame()
	tf.Pep8()
    tf.PyLint()
    tf.GoBuild()
	return &tf
}

func getDirFiles(dirPath string) []string {
	files, err := ioutil.ReadDir(dirPath)
	if err != nil {
		log.Fatal("Could not read directory", dirPath)
	}
	filepaths := make([]string, len(files))
	for i, fileInfo := range files {
		filepaths[i] = path.Join(dirPath, fileInfo.Name())
	}
	return filterFiles(filepaths)
}

func gitBranchFiles() []string {
	dirtyFilesCmd := exec.Command("git", "diff", "--name-only")
	dirtyFiles, err := dirtyFilesCmd.Output()
	if err != nil {
		log.Fatal("Failed to list dirty files")
	}

	branchFilesCmd := exec.Command("git", "diff", "--name-only", "master..HEAD")
	branchFiles, err := branchFilesCmd.Output()
	if err != nil {
		log.Print("branchFiles: ", branchFiles)
		log.Fatal("Failed to list branch files:", err)
	}

	allFiles := append(
		strings.Split(string(dirtyFiles), "\n"),
		strings.Split(string(branchFiles), "\n")...,
	)
	return filterFiles(allFiles)
}

func filterFiles(filepaths []string) []string {
	goodstuffs := make([]string, 0)
	for _, filepath := range filepaths {
		if len(filepath) > 0 {
			match, err := regexp.MatchString(".py|.go", path.Ext(filepath))
			if err != nil {
				log.Fatalf("Failed checking %s's extension", filepath)
			}
            if match == true {
                if !strings.HasPrefix(filepath, "/") {
                    filepath = path.Join(config["workingDir"], filepath)
                }
				goodstuffs = append(goodstuffs, filepath)
			}
		}
	}
	return goodstuffs
}

func printWarts(targetFile *TargetFile) {
	fmt.Println(color("green", targetFile.Path))
	if len(targetFile.Warts) == 0 {
		fmt.Println(color("bold", "- All clean!"))
	}
	for line, warts := range targetFile.Warts {
		blameName := targetFile.BlameName(line)
		nameColor := "blue"
		if blameName == env.GitName() {
			nameColor = "yellow"
		}
		fmt.Printf(
			"%s: (%s) %s\n",
			color("bold", fmt.Sprintf("%d", line)),
			color(nameColor, blameName),
			strings.TrimSpace(targetFile.ContentLines[line-1]),
		)
		for _, wart := range warts {
			fmt.Printf(
				"    [%s %s] %s\n",
				wart.Reporter,
				wart.IssueCode,
				color("bold", wart.Message),
			)
		}
	}
}

func clear() {
	cmd := exec.Command("clear")
	cmd.Stdout = os.Stdout
	cmd.Run()
    fmt.Println(color("header", "--- LintBlame ---"))
}

func makeTargetFile(filepath string, c chan *TargetFile) {
	tf := NewTargetFile(filepath)
	c <- tf
}

func update(filepaths []string) {
	c := make(chan *TargetFile)
	for _, path := range filepaths {
		go makeTargetFile(path, c)
	}
	cleared := false
	for i := 0; i < len(filepaths); i++ {
		if !cleared {
			clear()
			cleared = true
		}
		tf := <-c
		printWarts(tf)
        fmt.Println("")
	}
}

func initialPaths() []string {
    var branch bool
    flag.BoolVar(&branch, "b", false, "Run against current branch")
    flag.Parse()

    var filepaths []string
    if branch {
        config["workingDir"] = env.GitPath()
        filepaths = gitBranchFiles()
    } else {
        args := flag.Args()
        if len(args) > 0 {
            target := args[0]
            stat, err := os.Stat(target)
            if err != nil {
                log.Fatal("Unable to process argument: ", target)
            }
            absPath, err := filepath.Abs(target)
            if err != nil {
                log.Fatal("Unable to get absolute path of ", target)
            }
            if stat.IsDir() {
                config["workingDir"] = absPath
                filepaths = getDirFiles(absPath)
            } else {
                dir, _ := filepath.Split(absPath)
                config["workingDir"] = dir
                filepaths = filterFiles([]string{absPath})
            }
        }
    }
    return filepaths
}

func main() {
    filepaths := initialPaths()
	modTimes := NewModifiedTimes()

	for _, file := range filepaths {
		modTimes.CheckTime(file)
	}
	update(modTimes.PathsByModTime())
	for {
		runUpdate := false
		for _, file := range filepaths {
			if modTimes.CheckTime(file) {
				runUpdate = true
				break
			}
		}
		if runUpdate {
			update(modTimes.PathsByModTime())
		}
		time.Sleep(1 * time.Second)
	}
}
<|endoftext|>


<commit_before>package exp_test

import (
	"testing"

	"github.com/doug-martin/goqu/v9/exp"
	"github.com/stretchr/testify/suite"
)

type bitwiseExpressionSuite struct {
	suite.Suite
}

func TestBitwiseExpressionSuite(t *testing.T) {
	suite.Run(t, &bitwiseExpressionSuite{})
}

func (bes *bitwiseExpressionSuite) TestClone() {
	be := exp.NewBitwiseExpression(exp.BitwiseAndOp, exp.NewIdentifierExpression("", "", "col"), 1)
	bes.Equal(be, be.Clone())
}

func (bes *bitwiseExpressionSuite) TestExpression() {
	be := exp.NewBitwiseExpression(exp.BitwiseAndOp, exp.NewIdentifierExpression("", "", "col"), 1)
	bes.Equal(be, be.Expression())
}

func (bes *bitwiseExpressionSuite) TestAs() {
	be := exp.NewBitwiseExpression(exp.BitwiseInversionOp, exp.NewIdentifierExpression("", "", "col"), 1)
	bes.Equal(exp.NewAliasExpression(be, "a"), be.As("a"))
}

func (bes *bitwiseExpressionSuite) TestAsc() {
	be := exp.NewBitwiseExpression(exp.BitwiseAndOp, exp.NewIdentifierExpression("", "", "col"), 1)
	bes.Equal(exp.NewOrderedExpression(be, exp.AscDir, exp.NoNullsSortType), be.Asc())
}

func (bes *bitwiseExpressionSuite) TestDesc() {
	be := exp.NewBitwiseExpression(exp.BitwiseOrOp, exp.NewIdentifierExpression("", "", "col"), 1)
	bes.Equal(exp.NewOrderedExpression(be, exp.DescSortDir, exp.NoNullsSortType), be.Desc())
}

func (bes *bitwiseExpressionSuite) TestAllOthers() {
	be := exp.NewBitwiseExpression(exp.BitwiseRightShiftOp, exp.NewIdentifierExpression("", "", "col"), 1)
	rv := exp.NewRangeVal(1, 2)
	pattern := "cast like%"
	inVals := []interface{}{1, 2}
	testCases := []struct {
		Ex       exp.Expression
		Expected exp.Expression
	}{
		{Ex: be.Eq(1), Expected: exp.NewBooleanExpression(exp.EqOp, be, 1)},
		{Ex: be.Neq(1), Expected: exp.NewBooleanExpression(exp.NeqOp, be, 1)},
		{Ex: be.Gt(1), Expected: exp.NewBooleanExpression(exp.GtOp, be, 1)},
		{Ex: be.Gte(1), Expected: exp.NewBooleanExpression(exp.GteOp, be, 1)},
		{Ex: be.Lt(1), Expected: exp.NewBooleanExpression(exp.LtOp, be, 1)},
		{Ex: be.Lte(1), Expected: exp.NewBooleanExpression(exp.LteOp, be, 1)},
		{Ex: be.Between(rv), Expected: exp.NewRangeExpression(exp.BetweenOp, be, rv)},
		{Ex: be.NotBetween(rv), Expected: exp.NewRangeExpression(exp.NotBetweenOp, be, rv)},
		{Ex: be.Like(pattern), Expected: exp.NewBooleanExpression(exp.LikeOp, be, pattern)},
		{Ex: be.NotLike(pattern), Expected: exp.NewBooleanExpression(exp.NotLikeOp, be, pattern)},
		{Ex: be.ILike(pattern), Expected: exp.NewBooleanExpression(exp.ILikeOp, be, pattern)},
		{Ex: be.NotILike(pattern), Expected: exp.NewBooleanExpression(exp.NotILikeOp, be, pattern)},
		{Ex: be.RegexpLike(pattern), Expected: exp.NewBooleanExpression(exp.RegexpLikeOp, be, pattern)},
		{Ex: be.RegexpNotLike(pattern), Expected: exp.NewBooleanExpression(exp.RegexpNotLikeOp, be, pattern)},
		{Ex: be.RegexpILike(pattern), Expected: exp.NewBooleanExpression(exp.RegexpILikeOp, be, pattern)},
		{Ex: be.RegexpNotILike(pattern), Expected: exp.NewBooleanExpression(exp.RegexpNotILikeOp, be, pattern)},
		{Ex: be.In(inVals), Expected: exp.NewBooleanExpression(exp.InOp, be, inVals)},
		{Ex: be.NotIn(inVals), Expected: exp.NewBooleanExpression(exp.NotInOp, be, inVals)},
		{Ex: be.Is(true), Expected: exp.NewBooleanExpression(exp.IsOp, be, true)},
		{Ex: be.IsNot(true), Expected: exp.NewBooleanExpression(exp.IsNotOp, be, true)},
		{Ex: be.IsNull(), Expected: exp.NewBooleanExpression(exp.IsOp, be, nil)},
		{Ex: be.IsNotNull(), Expected: exp.NewBooleanExpression(exp.IsNotOp, be, nil)},
		{Ex: be.IsTrue(), Expected: exp.NewBooleanExpression(exp.IsOp, be, true)},
		{Ex: be.IsNotTrue(), Expected: exp.NewBooleanExpression(exp.IsNotOp, be, true)},
		{Ex: be.IsFalse(), Expected: exp.NewBooleanExpression(exp.IsOp, be, false)},
		{Ex: be.IsNotFalse(), Expected: exp.NewBooleanExpression(exp.IsNotOp, be, false)},
		{Ex: be.Distinct(), Expected: exp.NewSQLFunctionExpression("DISTINCT", be)},
	}

	for _, tc := range testCases {
		bes.Equal(tc.Expected, tc.Ex)
	}
}
<commit_msg>chore: fix linting issues<commit_after>package exp_test

import (
	"testing"

	"github.com/doug-martin/goqu/v9/exp"
	"github.com/stretchr/testify/suite"
)

type bitwiseExpressionSuite struct {
	suite.Suite
}

func TestBitwiseExpressionSuite(t *testing.T) {
	suite.Run(t, &bitwiseExpressionSuite{})
}

func (bes *bitwiseExpressionSuite) TestClone() {
	be := exp.NewBitwiseExpression(exp.BitwiseAndOp, exp.NewIdentifierExpression("", "", "col"), 1)
	bes.Equal(be, be.Clone())
}

func (bes *bitwiseExpressionSuite) TestExpression() {
	be := exp.NewBitwiseExpression(exp.BitwiseAndOp, exp.NewIdentifierExpression("", "", "col"), 1)
	bes.Equal(be, be.Expression())
}

func (bes *bitwiseExpressionSuite) TestAs() {
	be := exp.NewBitwiseExpression(exp.BitwiseInversionOp, exp.NewIdentifierExpression("", "", "col"), 1)
	bes.Equal(exp.NewAliasExpression(be, "a"), be.As("a"))
}

func (bes *bitwiseExpressionSuite) TestAsc() {
	be := exp.NewBitwiseExpression(exp.BitwiseAndOp, exp.NewIdentifierExpression("", "", "col"), 1)
	bes.Equal(exp.NewOrderedExpression(be, exp.AscDir, exp.NoNullsSortType), be.Asc())
}

func (bes *bitwiseExpressionSuite) TestDesc() {
	be := exp.NewBitwiseExpression(exp.BitwiseOrOp, exp.NewIdentifierExpression("", "", "col"), 1)
	bes.Equal(exp.NewOrderedExpression(be, exp.DescSortDir, exp.NoNullsSortType), be.Desc())
}

func (bes *bitwiseExpressionSuite) TestAllOthers() {
	be := exp.NewBitwiseExpression(exp.BitwiseRightShiftOp, exp.NewIdentifierExpression("", "", "col"), 1)
	rv := exp.NewRangeVal(1, 2)
	pattern := "bitwiseExp like%"
	inVals := []interface{}{1, 2}
	testCases := []struct {
		Ex       exp.Expression
		Expected exp.Expression
	}{
		{Ex: be.Eq(1), Expected: exp.NewBooleanExpression(exp.EqOp, be, 1)},
		{Ex: be.Neq(1), Expected: exp.NewBooleanExpression(exp.NeqOp, be, 1)},
		{Ex: be.Gt(1), Expected: exp.NewBooleanExpression(exp.GtOp, be, 1)},
		{Ex: be.Gte(1), Expected: exp.NewBooleanExpression(exp.GteOp, be, 1)},
		{Ex: be.Lt(1), Expected: exp.NewBooleanExpression(exp.LtOp, be, 1)},
		{Ex: be.Lte(1), Expected: exp.NewBooleanExpression(exp.LteOp, be, 1)},
		{Ex: be.Between(rv), Expected: exp.NewRangeExpression(exp.BetweenOp, be, rv)},
		{Ex: be.NotBetween(rv), Expected: exp.NewRangeExpression(exp.NotBetweenOp, be, rv)},
		{Ex: be.Like(pattern), Expected: exp.NewBooleanExpression(exp.LikeOp, be, pattern)},
		{Ex: be.NotLike(pattern), Expected: exp.NewBooleanExpression(exp.NotLikeOp, be, pattern)},
		{Ex: be.ILike(pattern), Expected: exp.NewBooleanExpression(exp.ILikeOp, be, pattern)},
		{Ex: be.NotILike(pattern), Expected: exp.NewBooleanExpression(exp.NotILikeOp, be, pattern)},
		{Ex: be.RegexpLike(pattern), Expected: exp.NewBooleanExpression(exp.RegexpLikeOp, be, pattern)},
		{Ex: be.RegexpNotLike(pattern), Expected: exp.NewBooleanExpression(exp.RegexpNotLikeOp, be, pattern)},
		{Ex: be.RegexpILike(pattern), Expected: exp.NewBooleanExpression(exp.RegexpILikeOp, be, pattern)},
		{Ex: be.RegexpNotILike(pattern), Expected: exp.NewBooleanExpression(exp.RegexpNotILikeOp, be, pattern)},
		{Ex: be.In(inVals), Expected: exp.NewBooleanExpression(exp.InOp, be, inVals)},
		{Ex: be.NotIn(inVals), Expected: exp.NewBooleanExpression(exp.NotInOp, be, inVals)},
		{Ex: be.Is(true), Expected: exp.NewBooleanExpression(exp.IsOp, be, true)},
		{Ex: be.IsNot(true), Expected: exp.NewBooleanExpression(exp.IsNotOp, be, true)},
		{Ex: be.IsNull(), Expected: exp.NewBooleanExpression(exp.IsOp, be, nil)},
		{Ex: be.IsNotNull(), Expected: exp.NewBooleanExpression(exp.IsNotOp, be, nil)},
		{Ex: be.IsTrue(), Expected: exp.NewBooleanExpression(exp.IsOp, be, true)},
		{Ex: be.IsNotTrue(), Expected: exp.NewBooleanExpression(exp.IsNotOp, be, true)},
		{Ex: be.IsFalse(), Expected: exp.NewBooleanExpression(exp.IsOp, be, false)},
		{Ex: be.IsNotFalse(), Expected: exp.NewBooleanExpression(exp.IsNotOp, be, false)},
		{Ex: be.Distinct(), Expected: exp.NewSQLFunctionExpression("DISTINCT", be)},
	}

	for _, tc := range testCases {
		bes.Equal(tc.Expected, tc.Ex)
	}
}
<|endoftext|>