<commit_before>package openstack

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
)

func resourceNetworkingSubnetV2() *schema.Resource {
	return &schema.Resource{
		Create: resourceNetworkingSubnetV2Create,
		Read:   resourceNetworkingSubnetV2Read,
		Update: resourceNetworkingSubnetV2Update,
		Delete: resourceNetworkingSubnetV2Delete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Timeouts: &schema.ResourceTimeout{
			Create: schema.DefaultTimeout(10 * time.Minute),
			Delete: schema.DefaultTimeout(10 * time.Minute),
		},

		Schema: map[string]*schema.Schema{
			"region": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"network_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"cidr": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
			},
			"tenant_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Computed: true,
			},
			"allocation_pools": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"start": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"end": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
			},
			"gateway_ip": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
				Computed: true,
			},
			"no_gateway": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				ForceNew: false,
			},
			"ip_version": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  4,
				ForceNew: true,
			},
			"enable_dhcp": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				ForceNew: false,
				Default:  true,
			},
			"dns_nameservers": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				ForceNew: false,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},
			"host_routes": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: false,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"destination_cidr": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"next_hop": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
			},
			"value_specs": &schema.Schema{
				Type:     schema.TypeMap,
				Optional: true,
				ForceNew: true,
			},
		},
	}
}

func resourceNetworkingSubnetV2Create(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	createOpts := SubnetCreateOpts{
		subnets.CreateOpts{
			NetworkID:       d.Get("network_id").(string),
			CIDR:            d.Get("cidr").(string),
			Name:            d.Get("name").(string),
			TenantID:        d.Get("tenant_id").(string),
			AllocationPools: resourceSubnetAllocationPoolsV2(d),
			DNSNameservers:  resourceSubnetDNSNameserversV2(d),
			HostRoutes:      resourceSubnetHostRoutesV2(d),
			EnableDHCP:      nil,
		},
		MapValueSpecs(d),
	}

	noGateway := d.Get("no_gateway").(bool)
	gatewayIP := d.Get("gateway_ip").(string)

	if gatewayIP != "" && noGateway {
		return fmt.Errorf("Both gateway_ip and no_gateway cannot be set")
	}

	if gatewayIP != "" {
		createOpts.GatewayIP = &gatewayIP
	}

	if noGateway {
		disableGateway := ""
		createOpts.GatewayIP = &disableGateway
	}

	enableDHCP := d.Get("enable_dhcp").(bool)
	createOpts.EnableDHCP = &enableDHCP

	if v, ok := d.GetOk("ip_version"); ok {
		ipVersion := resourceNetworkingSubnetV2DetermineIPVersion(v.(int))
		createOpts.IPVersion = ipVersion
	}

	s, err := subnets.Create(networkingClient, createOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error creating OpenStack Neutron subnet: %s", err)
	}

	log.Printf("[DEBUG] Waiting for Subnet (%s) to become available", s.ID)
	stateConf := &resource.StateChangeConf{
		Target:     []string{"ACTIVE"},
		Refresh:    waitForSubnetActive(networkingClient, s.ID),
		Timeout:    d.Timeout(schema.TimeoutCreate),
		Delay:      5 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()

	d.SetId(s.ID)

	log.Printf("[DEBUG] Created Subnet %s: %#v", s.ID, s)
	return resourceNetworkingSubnetV2Read(d, meta)
}

func resourceNetworkingSubnetV2Read(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	s, err := subnets.Get(networkingClient, d.Id()).Extract()
	if err != nil {
		return CheckDeleted(d, err, "subnet")
	}

	log.Printf("[DEBUG] Retrieved Subnet %s: %#v", d.Id(), s)

	d.Set("network_id", s.NetworkID)
	d.Set("cidr", s.CIDR)
	d.Set("ip_version", s.IPVersion)
	d.Set("name", s.Name)
	d.Set("tenant_id", s.TenantID)
	d.Set("gateway_ip", s.GatewayIP)
	d.Set("dns_nameservers", s.DNSNameservers)
	d.Set("host_routes", s.HostRoutes)
	d.Set("enable_dhcp", s.EnableDHCP)
	d.Set("network_id", s.NetworkID)

	// Set the allocation_pools
	var allocationPools []map[string]interface{}
	for _, v := range s.AllocationPools {
		pool := make(map[string]interface{})
		pool["start"] = v.Start
		pool["end"] = v.End

		allocationPools = append(allocationPools, pool)
	}
	d.Set("allocation_pools", allocationPools)

	d.Set("region", GetRegion(d, config))

	return nil
}

func resourceNetworkingSubnetV2Update(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	// Check if both gateway_ip and no_gateway are set
	if _, ok := d.GetOk("gateway_ip"); ok {
		noGateway := d.Get("no_gateway").(bool)
		if noGateway {
			return fmt.Errorf("Both gateway_ip and no_gateway cannot be set.")
		}
	}

	var updateOpts subnets.UpdateOpts

	noGateway := d.Get("no_gateway").(bool)
	gatewayIP := d.Get("gateway_ip").(string)

	if gatewayIP != "" && noGateway {
		return fmt.Errorf("Both gateway_ip and no_gateway cannot be set")
	}

	if d.HasChange("name") {
		updateOpts.Name = d.Get("name").(string)
	}

	if d.HasChange("gateway_ip") {
		updateOpts.GatewayIP = nil
		if v, ok := d.GetOk("gateway_ip"); ok {
			gatewayIP := v.(string)
			updateOpts.GatewayIP = &gatewayIP
		}
	}

	if d.HasChange("no_gateway") {
		if d.Get("no_gateway").(bool) {
			gatewayIP := ""
			updateOpts.GatewayIP = &gatewayIP
		}
	}

	if d.HasChange("dns_nameservers") {
		updateOpts.DNSNameservers = resourceSubnetDNSNameserversV2(d)
	}

	if d.HasChange("host_routes") {
		updateOpts.HostRoutes = resourceSubnetHostRoutesV2(d)
	}

	if d.HasChange("enable_dhcp") {
		v := d.Get("enable_dhcp").(bool)
		updateOpts.EnableDHCP = &v
	}

	if d.HasChange("allocation_pools") {
		updateOpts.AllocationPools = resourceSubnetAllocationPoolsV2(d)
	}

	log.Printf("[DEBUG] Updating Subnet %s with options: %+v", d.Id(), updateOpts)

	_, err = subnets.Update(networkingClient, d.Id(), updateOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error updating OpenStack Neutron Subnet: %s", err)
	}

	return resourceNetworkingSubnetV2Read(d, meta)
}

func resourceNetworkingSubnetV2Delete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"ACTIVE"},
		Target:     []string{"DELETED"},
		Refresh:    waitForSubnetDelete(networkingClient, d.Id()),
		Timeout:    d.Timeout(schema.TimeoutDelete),
		Delay:      5 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return fmt.Errorf("Error deleting OpenStack Neutron Subnet: %s", err)
	}

	d.SetId("")
	return nil
}

func resourceSubnetAllocationPoolsV2(d *schema.ResourceData) []subnets.AllocationPool {
	rawAPs := d.Get("allocation_pools").([]interface{})
	aps := make([]subnets.AllocationPool, len(rawAPs))
	for i, raw := range rawAPs {
		rawMap := raw.(map[string]interface{})
		aps[i] = subnets.AllocationPool{
			Start: rawMap["start"].(string),
			End:   rawMap["end"].(string),
		}
	}
	return aps
}

func resourceSubnetDNSNameserversV2(d *schema.ResourceData) []string {
	rawDNSN := d.Get("dns_nameservers").(*schema.Set)
	dnsn := make([]string, rawDNSN.Len())
	for i, raw := range rawDNSN.List() {
		dnsn[i] = raw.(string)
	}
	return dnsn
}

func resourceSubnetHostRoutesV2(d *schema.ResourceData) []subnets.HostRoute {
	rawHR := d.Get("host_routes").([]interface{})
	hr := make([]subnets.HostRoute, len(rawHR))
	for i, raw := range rawHR {
		rawMap := raw.(map[string]interface{})
		hr[i] = subnets.HostRoute{
			DestinationCIDR: rawMap["destination_cidr"].(string),
			NextHop:         rawMap["next_hop"].(string),
		}
	}
	return hr
}

func resourceNetworkingSubnetV2DetermineIPVersion(v int) gophercloud.IPVersion {
	var ipVersion gophercloud.IPVersion
	switch v {
	case 4:
		ipVersion = gophercloud.IPv4
	case 6:
		ipVersion = gophercloud.IPv6
	}

	return ipVersion
}

func waitForSubnetActive(networkingClient *gophercloud.ServiceClient, subnetId string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		s, err := subnets.Get(networkingClient, subnetId).Extract()
		if err != nil {
			return nil, "", err
		}

		log.Printf("[DEBUG] OpenStack Neutron Subnet: %+v", s)
		return s, "ACTIVE", nil
	}
}

func waitForSubnetDelete(networkingClient *gophercloud.ServiceClient, subnetId string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		log.Printf("[DEBUG] Attempting to delete OpenStack Subnet %s.\n", subnetId)

		s, err := subnets.Get(networkingClient, subnetId).Extract()
		if err != nil {
			if _, ok := err.(gophercloud.ErrDefault404); ok {
				log.Printf("[DEBUG] Successfully deleted OpenStack Subnet %s", subnetId)
				return s, "DELETED", nil
			}
			return s, "ACTIVE", err
		}

		err = subnets.Delete(networkingClient, subnetId).ExtractErr()
		if err != nil {
			if _, ok := err.(gophercloud.ErrDefault404); ok {
				log.Printf("[DEBUG] Successfully deleted OpenStack Subnet %s", subnetId)
				return s, "DELETED", nil
			}
			if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok {
				if errCode.Actual == 409 {
					return s, "ACTIVE", nil
				}
			}
			return s, "ACTIVE", err
		}

		log.Printf("[DEBUG] OpenStack Subnet %s still active.\n", subnetId)
		return s, "ACTIVE", nil
	}
}
<commit_msg>Networking v2: ConflictsWith for Subnet Gateway (#136)<commit_after>package openstack

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
)

func resourceNetworkingSubnetV2() *schema.Resource {
	return &schema.Resource{
		Create: resourceNetworkingSubnetV2Create,
		Read:   resourceNetworkingSubnetV2Read,
		Update: resourceNetworkingSubnetV2Update,
		Delete: resourceNetworkingSubnetV2Delete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Timeouts: &schema.ResourceTimeout{
			Create: schema.DefaultTimeout(10 * time.Minute),
			Delete: schema.DefaultTimeout(10 * time.Minute),
		},

		Schema: map[string]*schema.Schema{
			"region": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"network_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"cidr": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
			},
			"tenant_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Computed: true,
			},
			"allocation_pools": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"start": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"end": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
			},
			"gateway_ip": &schema.Schema{
				Type:          schema.TypeString,
				ConflictsWith: []string{"no_gateway"},
				Optional:      true,
				ForceNew:      false,
				Computed:      true,
			},
			"no_gateway": &schema.Schema{
				Type:          schema.TypeBool,
				ConflictsWith: []string{"gateway_ip"},
				Optional:      true,
				Default:       false,
				ForceNew:      false,
			},
			"ip_version": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  4,
				ForceNew: true,
			},
			"enable_dhcp": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				ForceNew: false,
				Default:  true,
			},
			"dns_nameservers": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				ForceNew: false,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},
			"host_routes": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: false,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"destination_cidr": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"next_hop": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
			},
			"value_specs": &schema.Schema{
				Type:     schema.TypeMap,
				Optional: true,
				ForceNew: true,
			},
		},
	}
}

func resourceNetworkingSubnetV2Create(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	createOpts := SubnetCreateOpts{
		subnets.CreateOpts{
			NetworkID:       d.Get("network_id").(string),
			CIDR:            d.Get("cidr").(string),
			Name:            d.Get("name").(string),
			TenantID:        d.Get("tenant_id").(string),
			AllocationPools: resourceSubnetAllocationPoolsV2(d),
			DNSNameservers:  resourceSubnetDNSNameserversV2(d),
			HostRoutes:      resourceSubnetHostRoutesV2(d),
			EnableDHCP:      nil,
		},
		MapValueSpecs(d),
	}

	if v, ok := d.GetOk("gateway_ip"); ok {
		gatewayIP := v.(string)
		createOpts.GatewayIP = &gatewayIP
	}

	noGateway := d.Get("no_gateway").(bool)
	if noGateway {
		gatewayIP := ""
		createOpts.GatewayIP = &gatewayIP
	}

	enableDHCP := d.Get("enable_dhcp").(bool)
	createOpts.EnableDHCP = &enableDHCP

	if v, ok := d.GetOk("ip_version"); ok {
		ipVersion := resourceNetworkingSubnetV2DetermineIPVersion(v.(int))
		createOpts.IPVersion = ipVersion
	}

	s, err := subnets.Create(networkingClient, createOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error creating OpenStack Neutron subnet: %s", err)
	}

	log.Printf("[DEBUG] Waiting for Subnet (%s) to become available", s.ID)
	stateConf := &resource.StateChangeConf{
		Target:     []string{"ACTIVE"},
		Refresh:    waitForSubnetActive(networkingClient, s.ID),
		Timeout:    d.Timeout(schema.TimeoutCreate),
		Delay:      5 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()

	d.SetId(s.ID)

	log.Printf("[DEBUG] Created Subnet %s: %#v", s.ID, s)
	return resourceNetworkingSubnetV2Read(d, meta)
}

func resourceNetworkingSubnetV2Read(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	s, err := subnets.Get(networkingClient, d.Id()).Extract()
	if err != nil {
		return CheckDeleted(d, err, "subnet")
	}

	log.Printf("[DEBUG] Retrieved Subnet %s: %#v", d.Id(), s)

	d.Set("network_id", s.NetworkID)
	d.Set("cidr", s.CIDR)
	d.Set("ip_version", s.IPVersion)
	d.Set("name", s.Name)
	d.Set("tenant_id", s.TenantID)
	d.Set("dns_nameservers", s.DNSNameservers)
	d.Set("host_routes", s.HostRoutes)
	d.Set("enable_dhcp", s.EnableDHCP)
	d.Set("network_id", s.NetworkID)

	// Set the allocation_pools
	var allocationPools []map[string]interface{}
	for _, v := range s.AllocationPools {
		pool := make(map[string]interface{})
		pool["start"] = v.Start
		pool["end"] = v.End

		allocationPools = append(allocationPools, pool)
	}
	d.Set("allocation_pools", allocationPools)

	// Set the subnet's Gateway IP.
	gatewayIP := s.GatewayIP
	d.Set("gateway_ip", s.GatewayIP)

	// Based on the subnet's Gateway IP, set `no_gateway` accordingly.
	if gatewayIP == "" {
		d.Set("no_gateway", true)
	} else {
		d.Set("no_gateway", false)
	}

	d.Set("region", GetRegion(d, config))

	return nil
}

func resourceNetworkingSubnetV2Update(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	var updateOpts subnets.UpdateOpts

	if d.HasChange("name") {
		updateOpts.Name = d.Get("name").(string)
	}

	if d.HasChange("gateway_ip") {
		updateOpts.GatewayIP = nil
		if v, ok := d.GetOk("gateway_ip"); ok {
			gatewayIP := v.(string)
			updateOpts.GatewayIP = &gatewayIP
		}
	}

	if d.HasChange("no_gateway") {
		if d.Get("no_gateway").(bool) {
			gatewayIP := ""
			updateOpts.GatewayIP = &gatewayIP
		}
	}

	if d.HasChange("dns_nameservers") {
		updateOpts.DNSNameservers = resourceSubnetDNSNameserversV2(d)
	}

	if d.HasChange("host_routes") {
		updateOpts.HostRoutes = resourceSubnetHostRoutesV2(d)
	}

	if d.HasChange("enable_dhcp") {
		v := d.Get("enable_dhcp").(bool)
		updateOpts.EnableDHCP = &v
	}

	if d.HasChange("allocation_pools") {
		updateOpts.AllocationPools = resourceSubnetAllocationPoolsV2(d)
	}

	log.Printf("[DEBUG] Updating Subnet %s with options: %+v", d.Id(), updateOpts)

	_, err = subnets.Update(networkingClient, d.Id(), updateOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error updating OpenStack Neutron Subnet: %s", err)
	}

	return resourceNetworkingSubnetV2Read(d, meta)
}

func resourceNetworkingSubnetV2Delete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"ACTIVE"},
		Target:     []string{"DELETED"},
		Refresh:    waitForSubnetDelete(networkingClient, d.Id()),
		Timeout:    d.Timeout(schema.TimeoutDelete),
		Delay:      5 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return fmt.Errorf("Error deleting OpenStack Neutron Subnet: %s", err)
	}

	d.SetId("")
	return nil
}

func resourceSubnetAllocationPoolsV2(d *schema.ResourceData) []subnets.AllocationPool {
	rawAPs := d.Get("allocation_pools").([]interface{})
	aps := make([]subnets.AllocationPool, len(rawAPs))
	for i, raw := range rawAPs {
		rawMap := raw.(map[string]interface{})
		aps[i] = subnets.AllocationPool{
			Start: rawMap["start"].(string),
			End:   rawMap["end"].(string),
		}
	}
	return aps
}

func resourceSubnetDNSNameserversV2(d *schema.ResourceData) []string {
	rawDNSN := d.Get("dns_nameservers").(*schema.Set)
	dnsn := make([]string, rawDNSN.Len())
	for i, raw := range rawDNSN.List() {
		dnsn[i] = raw.(string)
	}
	return dnsn
}

func resourceSubnetHostRoutesV2(d *schema.ResourceData) []subnets.HostRoute {
	rawHR := d.Get("host_routes").([]interface{})
	hr := make([]subnets.HostRoute, len(rawHR))
	for i, raw := range rawHR {
		rawMap := raw.(map[string]interface{})
		hr[i] = subnets.HostRoute{
			DestinationCIDR: rawMap["destination_cidr"].(string),
			NextHop:         rawMap["next_hop"].(string),
		}
	}
	return hr
}

func resourceNetworkingSubnetV2DetermineIPVersion(v int) gophercloud.IPVersion {
	var ipVersion gophercloud.IPVersion
	switch v {
	case 4:
		ipVersion = gophercloud.IPv4
	case 6:
		ipVersion = gophercloud.IPv6
	}

	return ipVersion
}

func waitForSubnetActive(networkingClient *gophercloud.ServiceClient, subnetId string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		s, err := subnets.Get(networkingClient, subnetId).Extract()
		if err != nil {
			return nil, "", err
		}

		log.Printf("[DEBUG] OpenStack Neutron Subnet: %+v", s)
		return s, "ACTIVE", nil
	}
}

func waitForSubnetDelete(networkingClient *gophercloud.ServiceClient, subnetId string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		log.Printf("[DEBUG] Attempting to delete OpenStack Subnet %s.\n", subnetId)

		s, err := subnets.Get(networkingClient, subnetId).Extract()
		if err != nil {
			if _, ok := err.(gophercloud.ErrDefault404); ok {
				log.Printf("[DEBUG] Successfully deleted OpenStack Subnet %s", subnetId)
				return s, "DELETED", nil
			}
			return s, "ACTIVE", err
		}

		err = subnets.Delete(networkingClient, subnetId).ExtractErr()
		if err != nil {
			if _, ok := err.(gophercloud.ErrDefault404); ok {
				log.Printf("[DEBUG] Successfully deleted OpenStack Subnet %s", subnetId)
				return s, "DELETED", nil
			}
			if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok {
				if errCode.Actual == 409 {
					return s, "ACTIVE", nil
				}
			}
			return s, "ACTIVE", err
		}

		log.Printf("[DEBUG] OpenStack Subnet %s still active.\n", subnetId)
		return s, "ACTIVE", nil
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"path"
	"strconv"
	"strings"
)

var (
	form url.Values
	header http.Header
	cookies []*http.Cookie
	writer http.ResponseWriter
	request http.Request
	exit_error bool
)

func initServer() {
	if config.Port == 0 {
		config.Port = 80
	}
	listener,err := net.Listen("tcp", config.Domain+":"+strconv.Itoa(config.Port))
	if(err != nil) {
		error_log.Write(err.Error())
		fmt.Printf("Failed listening on "+config.Domain+":%d, see log for details",config.Port)
		os.Exit(2)
	}
	http.Handle("/", makeHandler(fileHandle))
	http.Handle("/manage",makeHandler(callManageFunction))
	http.Handle("/post",makeHandler(makePost))
	//http.Handle("/util",makeHandler(utilHandler))
	http.Serve(listener, nil)
}

func fileHandle(w http.ResponseWriter, r *http.Request) {
	request = *r
	writer = w
	cookies = request.Cookies()
	request.ParseForm()
	form = request.Form
	request_url := request.URL.Path

	filepath := path.Join(config.DocumentRoot, request_url)
	results,err := os.Stat(filepath)

	if err == nil {
		//the file exists, or there is a folder here
		if results.IsDir() {
			found_index := false
			newpath := ""

			//check to see if one of the specified index pages exists
			for i := 0; i < len(config.FirstPage); i++ {
				newpath = path.Join(filepath,config.FirstPage[i])
				_,err := os.Stat(newpath)
				if err == nil {
					serveFile(w, newpath)
					found_index = true
					break
				}
			}

			if !found_index {
				error404()
			}
		} else {
			//the file exists, and is not a folder
			//writer.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d, public, must-revalidate, proxy-revalidate", 500))
			serveFile(w, filepath)
		}
	} else {
		//there is nothing at the requested address
		error404()
	}
}

func makeHandler(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		//defer serverError()
		if !exit_error {
			fn(w, r)
			exit_error = false
		} else {
			exit_error = false
		}
	}
}

func exitWithErrorPage(w http.ResponseWriter, err string) {
	error_page_bytes,_ := ioutil.ReadFile("templates/error.html")
	error_page := string(error_page_bytes)
	error_page = strings.Replace(error_page,"{ERRORTEXT}", err,-1)
	fmt.Fprintf(w,error_page)
	exit_error = true
}

func redirect(location string) {
	http.Redirect(writer,&request,location,http.StatusFound)
}

func error404() {
	http.ServeFile(writer, &request, path.Join(config.DocumentRoot, "/error/404.html"))
	error_log.Write("Error: 404 Not Found from " + request.RemoteAddr + " @ " + request.RequestURI)
}

func serverError() {
	if _, ok := recover().(error); ok {
		//something went wrong, now we need to throw a 500
		http.ServeFile(writer,&request, path.Join(config.DocumentRoot, "/error/500.html"))
		error_log.Write("Error: 500 Internal Server error from " + request.RemoteAddr + " @ " + request.RequestURI)
		return
	}
}

func serveFile(w http.ResponseWriter, filepath string) {
	http.ServeFile(w, &request, filepath)
	access_log.Write("Success: 200 from " + request.RemoteAddr + " @ " + request.RequestURI)
}<commit_msg>fixing merge<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"path"
	"strconv"
	"strings"
)

var (
	form url.Values
	header http.Header
	cookies []*http.Cookie
	writer http.ResponseWriter
	request http.Request
	exit_error bool
)

func initServer() {
	if config.Port == 0 {
		config.Port = 80
	}
	listener,err := net.Listen("tcp", config.Domain+":"+strconv.Itoa(config.Port))
	if(err != nil) {
		error_log.Write(err.Error())
		fmt.Printf("Failed listening on "+config.Domain+":%d, see log for details",config.Port)
		os.Exit(2)
	}
	http.Handle("/", makeHandler(fileHandle))
	http.Handle("/manage",makeHandler(callManageFunction))
	http.Handle("/post",makeHandler(makePost))
	//http.Handle("/util",makeHandler(utilHandler))
	http.Serve(listener, nil)
}

func fileHandle(w http.ResponseWriter, r *http.Request) {
	request = *r
	writer = w
	cookies = request.Cookies()
	request.ParseForm()
	form = request.Form
	request_url := request.URL.Path

	filepath := path.Join(config.DocumentRoot, request_url)
	results,err := os.Stat(filepath)

	if err == nil {
		//the file exists, or there is a folder here
		if results.IsDir() {
			found_index := false
			newpath := ""

			//check to see if one of the specified index pages exists
			for i := 0; i < len(config.FirstPage); i++ {
				newpath = path.Join(filepath,config.FirstPage[i])
				_,err := os.Stat(newpath)
				if err == nil {
					serveFile(w, newpath)
					found_index = true
					break
				}
			}

			if !found_index {
				error404()
			}
		} else {
			//the file exists, and is not a folder
			//writer.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d, public, must-revalidate, proxy-revalidate", 500))
			serveFile(w, filepath)
		}
	} else {
		//there is nothing at the requested address
		error404()
	}
}

func makeHandler(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		//defer serverError()
		if !exit_error {
			fn(w, r)
			exit_error = false
		} else {
			exit_error = false
		}
	}
}

<<<<<<< HEAD
func exitWithErrorPage(w http.ResponseWriter, err string) {
=======
func exitWithErrorPage(writer http.ResponseWriter, err string) {
>>>>>>> 0b6e2bc132fad7f323348b27857431ea8674c382
	error_page_bytes,_ := ioutil.ReadFile("templates/error.html")
	error_page := string(error_page_bytes)
	error_page = strings.Replace(error_page,"{ERRORTEXT}", err,-1)
	fmt.Fprintf(w,error_page)
	exit_error = true
}

func redirect(location string) {
	http.Redirect(writer,&request,location,http.StatusFound)
}

func error404() {
	http.ServeFile(writer, &request, path.Join(config.DocumentRoot, "/error/404.html"))
	error_log.Write("Error: 404 Not Found from " + request.RemoteAddr + " @ " + request.RequestURI)
}

func serverError() {
	if _, ok := recover().(error); ok {
		//something went wrong, now we need to throw a 500
		http.ServeFile(writer,&request, path.Join(config.DocumentRoot, "/error/500.html"))
		error_log.Write("Error: 500 Internal Server error from " + request.RemoteAddr + " @ " + request.RequestURI)
		return
	}
}

func serveFile(w http.ResponseWriter, filepath string) {
	http.ServeFile(w, &request, filepath)
	access_log.Write("Success: 200 from " + request.RemoteAddr + " @ " + request.RequestURI)
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package build

import (
	"bytes"
	"fmt"
	"text/template"

	bundle "github.com/GoogleCloudPlatform/k8s-cluster-bundle/pkg/apis/bundle/v1alpha1"
	"github.com/GoogleCloudPlatform/k8s-cluster-bundle/pkg/converter"
	"github.com/GoogleCloudPlatform/k8s-cluster-bundle/pkg/filter"
	"github.com/GoogleCloudPlatform/k8s-cluster-bundle/pkg/options"
	"github.com/GoogleCloudPlatform/k8s-cluster-bundle/pkg/options/openapi"
	"github.com/GoogleCloudPlatform/k8s-cluster-bundle/pkg/wrapper"
	apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// PatchTemplate renders a PatchTemplate from a PatchTemplateBuilder and options.
func PatchTemplate(ptb *bundle.PatchTemplateBuilder, opts options.JSONOptions) (*bundle.PatchTemplate, error) {
	name := ptb.GetName()
	if ptb.Template == "" {
		return nil, fmt.Errorf("cannot build PatchTemplate from PatchTemplateBuilder %q: it has an empty template", name)
	}

	tmpl, err := template.New("ptb").Parse(ptb.Template)
	if err != nil {
		return nil, fmt.Errorf("cannot build PatchTemplate from PatchTemplateBuilder %q: error parsing template: %v", name, err)
	}

	if opts == nil {
		opts = make(options.JSONOptions)
	}

	if ptb.BuildSchema != nil {
		opts, err = openapi.ApplyDefaults(opts, ptb.BuildSchema)
		if err != nil {
			return nil, err
		}
	}

	// This is a hack to allow us to pass through runtime templates variables
	// It is only one level-deep. TODO(jbelamaric): fix it to support nested schema
	if ptb.TargetSchema != nil && ptb.TargetSchema.Properties != nil {
		addParamDefaults("", ptb.TargetSchema.Properties, opts)
	}

	tmpl = tmpl.Option("missingkey=error")
	var buf bytes.Buffer
	err = tmpl.Execute(&buf, opts)
	if err != nil {
		return nil, fmt.Errorf("cannot build PatchTemplate from PatchTemplateBuilder %q: error executing template: %v", name, err)
	}

	pt := &bundle.PatchTemplate{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "bundle.gke.io/v1alpha1",
			Kind:       "PatchTemplate",
		},
		PatchType:     ptb.PatchType,
		ObjectMeta:    *ptb.ObjectMeta.DeepCopy(),
		OptionsSchema: ptb.TargetSchema.DeepCopy(),
		Template:      buf.String(),
	}
	return pt, nil
}

// ComponentPatchTemplates iterates through all PatchTemplateBuilders in a
// Components Objects, and converts them into PatchTemplates.
func ComponentPatchTemplates(c *bundle.Component, fopts *filter.Options, opts options.JSONOptions) (*bundle.Component, error) {
	ptbFilter := fopts
	if ptbFilter == nil {
		ptbFilter = &filter.Options{}
	}
	ptbFilter.Kinds = []string{`PatchTemplateBuilder`}

	f := filter.NewFilter()
	// select all patch template builders that match the filter
	ptbs, objs := f.PartitionObjects(c.Spec.Objects, ptbFilter)
	c.Spec.Objects = objs

	// loop through each and generate a patch template
	for _, obj := range ptbs {
		var ptb bundle.PatchTemplateBuilder
		err := converter.FromUnstructured(obj).ToObject(&ptb)
		if err != nil {
			return nil, err
		}

		pt, err := PatchTemplate(&ptb, opts)
		if err != nil {
			return nil, err
		}
		y, err := converter.FromObject(pt).ToYAML()
		if err != nil {
			return nil, err
		}
		o, err := converter.FromYAML(y).ToUnstructured()
		if err != nil {
			return nil, err
		}
		c.Spec.Objects = append(c.Spec.Objects, o)
	}

	return c, nil
}

// AllPatchTemplates is a convenience method to build all PatchTemplateBuilders into
// PatchTemplates for all Components in a Bundle.
func AllPatchTemplates(bw *wrapper.BundleWrapper, fopts *filter.Options, opts options.JSONOptions) (*wrapper.BundleWrapper, error) {
	switch bw.Kind() {
	case "Component":
		comp, err := ComponentPatchTemplates(bw.Component(), fopts, opts)
		if err != nil {
			return nil, err
		}
		bw = wrapper.FromComponent(comp)
	case "Bundle":
		bun := bw.Bundle()
		var comps []*bundle.Component
		for _, comp := range bun.Components {
			comp, err := ComponentPatchTemplates(comp, fopts, opts)
			if err != nil {
				return nil, err
			}
			comps = append(comps, comp)
		}
		bun.Components = comps
		bw = wrapper.FromBundle(bun)
	default:
		return nil, fmt.Errorf("bundle kind %q not supported for patching", bw.Kind())
	}

	return bw, nil
}

// addParamDefaults is a hack to allow us to pass through runtime templates
// variables, which works by looking at the properties in the target schema in
// a PatchTemplateBuilder. It only works for templates that only use simple
// template variables.
func addParamDefaults(prefix string, props map[string]apiextensions.JSONSchemaProps, op options.JSONOptions) error {
	for k, val := range props {
		tmplKey := prefix + "." + k

		if val.Properties != nil {
			// The schema indicates that the this key-value pair has an object
			// substructure, and so we have to recurse into this structure.
			var nestedOpts options.JSONOptions
			optVal, hasVal := op[k]
			if hasVal && optVal != nil {
				nopt, ok := optVal.(map[string]interface{})
				if !ok {
					return fmt.Errorf("Option value with key %q was expected to be an object-type, but was %v", tmplKey, optVal)
				}
				nestedOpts = nopt
			} else {
				nestedOpts = make(options.JSONOptions)
				op[k] = nestedOpts
			}
			// This property contains nested properties. Recurse into these
			// properties and modify the prefix
			addParamDefaults(tmplKey, val.Properties, nestedOpts)
		} else {
			op[k] = `{{` + tmplKey + `}}`
		}
	}
	return nil
}
<commit_msg>Ensure that the `selector` field of PatchTemplateBuilders gets copied to the generated PatchTemplates. (#315)<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package build

import (
	"bytes"
	"fmt"
	"text/template"

	bundle "github.com/GoogleCloudPlatform/k8s-cluster-bundle/pkg/apis/bundle/v1alpha1"
	"github.com/GoogleCloudPlatform/k8s-cluster-bundle/pkg/converter"
	"github.com/GoogleCloudPlatform/k8s-cluster-bundle/pkg/filter"
	"github.com/GoogleCloudPlatform/k8s-cluster-bundle/pkg/options"
	"github.com/GoogleCloudPlatform/k8s-cluster-bundle/pkg/options/openapi"
	"github.com/GoogleCloudPlatform/k8s-cluster-bundle/pkg/wrapper"
	apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// PatchTemplate renders a PatchTemplate from a PatchTemplateBuilder and options.
func PatchTemplate(ptb *bundle.PatchTemplateBuilder, opts options.JSONOptions) (*bundle.PatchTemplate, error) {
	name := ptb.GetName()
	if ptb.Template == "" {
		return nil, fmt.Errorf("cannot build PatchTemplate from PatchTemplateBuilder %q: it has an empty template", name)
	}

	tmpl, err := template.New("ptb").Parse(ptb.Template)
	if err != nil {
		return nil, fmt.Errorf("cannot build PatchTemplate from PatchTemplateBuilder %q: error parsing template: %v", name, err)
	}

	if opts == nil {
		opts = make(options.JSONOptions)
	}

	if ptb.BuildSchema != nil {
		opts, err = openapi.ApplyDefaults(opts, ptb.BuildSchema)
		if err != nil {
			return nil, err
		}
	}

	// This is a hack to allow us to pass through runtime templates variables
	// It is only one level-deep. TODO(jbelamaric): fix it to support nested schema
	if ptb.TargetSchema != nil && ptb.TargetSchema.Properties != nil {
		addParamDefaults("", ptb.TargetSchema.Properties, opts)
	}

	tmpl = tmpl.Option("missingkey=error")
	var buf bytes.Buffer
	err = tmpl.Execute(&buf, opts)
	if err != nil {
		return nil, fmt.Errorf("cannot build PatchTemplate from PatchTemplateBuilder %q: error executing template: %v", name, err)
	}

	pt := &bundle.PatchTemplate{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "bundle.gke.io/v1alpha1",
			Kind:       "PatchTemplate",
		},
		PatchType:     ptb.PatchType,
		ObjectMeta:    *ptb.ObjectMeta.DeepCopy(),
		OptionsSchema: ptb.TargetSchema.DeepCopy(),
		Selector:      ptb.Selector.DeepCopy(),
		Template:      buf.String(),
	}
	return pt, nil
}

// ComponentPatchTemplates iterates through all PatchTemplateBuilders in a
// Components Objects, and converts them into PatchTemplates.
func ComponentPatchTemplates(c *bundle.Component, fopts *filter.Options, opts options.JSONOptions) (*bundle.Component, error) {
	ptbFilter := fopts
	if ptbFilter == nil {
		ptbFilter = &filter.Options{}
	}
	ptbFilter.Kinds = []string{`PatchTemplateBuilder`}

	f := filter.NewFilter()
	// select all patch template builders that match the filter
	ptbs, objs := f.PartitionObjects(c.Spec.Objects, ptbFilter)
	c.Spec.Objects = objs

	// loop through each and generate a patch template
	for _, obj := range ptbs {
		var ptb bundle.PatchTemplateBuilder
		err := converter.FromUnstructured(obj).ToObject(&ptb)
		if err != nil {
			return nil, err
		}

		pt, err := PatchTemplate(&ptb, opts)
		if err != nil {
			return nil, err
		}
		y, err := converter.FromObject(pt).ToYAML()
		if err != nil {
			return nil, err
		}
		o, err := converter.FromYAML(y).ToUnstructured()
		if err != nil {
			return nil, err
		}
		c.Spec.Objects = append(c.Spec.Objects, o)
	}

	return c, nil
}

// AllPatchTemplates is a convenience method to build all PatchTemplateBuilders into
// PatchTemplates for all Components in a Bundle.
func AllPatchTemplates(bw *wrapper.BundleWrapper, fopts *filter.Options, opts options.JSONOptions) (*wrapper.BundleWrapper, error) {
	switch bw.Kind() {
	case "Component":
		comp, err := ComponentPatchTemplates(bw.Component(), fopts, opts)
		if err != nil {
			return nil, err
		}
		bw = wrapper.FromComponent(comp)
	case "Bundle":
		bun := bw.Bundle()
		var comps []*bundle.Component
		for _, comp := range bun.Components {
			comp, err := ComponentPatchTemplates(comp, fopts, opts)
			if err != nil {
				return nil, err
			}
			comps = append(comps, comp)
		}
		bun.Components = comps
		bw = wrapper.FromBundle(bun)
	default:
		return nil, fmt.Errorf("bundle kind %q not supported for patching", bw.Kind())
	}

	return bw, nil
}

// addParamDefaults is a hack to allow us to pass through runtime templates
// variables, which works by looking at the properties in the target schema in
// a PatchTemplateBuilder. It only works for templates that only use simple
// template variables.
func addParamDefaults(prefix string, props map[string]apiextensions.JSONSchemaProps, op options.JSONOptions) error {
	for k, val := range props {
		tmplKey := prefix + "." + k

		if val.Properties != nil {
			// The schema indicates that the this key-value pair has an object
			// substructure, and so we have to recurse into this structure.
			var nestedOpts options.JSONOptions
			optVal, hasVal := op[k]
			if hasVal && optVal != nil {
				nopt, ok := optVal.(map[string]interface{})
				if !ok {
					return fmt.Errorf("Option value with key %q was expected to be an object-type, but was %v", tmplKey, optVal)
				}
				nestedOpts = nopt
			} else {
				nestedOpts = make(options.JSONOptions)
				op[k] = nestedOpts
			}
			// This property contains nested properties. Recurse into these
			// properties and modify the prefix
			addParamDefaults(tmplKey, val.Properties, nestedOpts)
		} else {
			op[k] = `{{` + tmplKey + `}}`
		}
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative Authors

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package logconfig

import (
	"fmt"
	"os"
)

const (
	// Named Loggers are used to override the default log level. config-logging.yaml will use the follow:
	//
	// loglevel.controller: "info"
	// loglevel.webhook: "info"

	// Controller is the name of the override key used inside of the logging config for Controller.
	Controller = "controller"

	// Webhook is the name of the override key used inside of the logging config for Webhook Controller.
	WebhookNameEnv = "WEBHOOK_NAME"
)

// DEPRECATED: use knative.dev/pkg/webhook.NameFromEnv()
func WebhookName() string {
	if webhook := os.Getenv(WebhookNameEnv); webhook != "" {
		return webhook
	}

	panic(fmt.Sprintf(`The environment variable %q is not set

If this is a process running on Kubernetes, then it should be using the downward
API to initialize this variable via:

  env:
  - name: WEBHOOK_NAME
    value: webhook
`, WebhookNameEnv))
}
<commit_msg>remove deprecated function WebhookName (#4590)<commit_after>/*
Copyright 2018 The Knative Authors

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package logconfig

const (
	// Named Loggers are used to override the default log level. config-logging.yaml will use the follow:
	//
	// loglevel.controller: "info"
	// loglevel.webhook: "info"

	// Controller is the name of the override key used inside of the logging config for Controller.
	Controller = "controller"
)
<|endoftext|>


<commit_before>package middleware

import (
	"net/http"

	log "github.com/Sirupsen/logrus"
	"github.com/hellofresh/janus/pkg/stats"
)

type Stats struct {
	statsClient *stats.StatsClient
}

func NewStats(statsClient *stats.StatsClient) *Stats {
	return &Stats{statsClient}
}

func (m *Stats) Handler(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Debug("Starting Stats middleware")

		timing := m.statsClient.StatsDClient.NewTiming()

		handler.ServeHTTP(w, r)

		m.statsClient.TrackRequest(timing, r)
	})
}
<commit_msg>Use original request method/url for tracking stats<commit_after>package middleware

import (
	"net/http"
	"net/url"

	log "github.com/Sirupsen/logrus"
	"github.com/hellofresh/janus/pkg/stats"
)

type Stats struct {
	statsClient *stats.StatsClient
}

func NewStats(statsClient *stats.StatsClient) *Stats {
	return &Stats{statsClient}
}

func (m *Stats) Handler(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Debug("Starting Stats middleware")

		timing := m.statsClient.StatsDClient.NewTiming()

		// reverse proxy replaces original request with target request, so keep required fields of the original one
		originalURL := &url.URL{}
		*originalURL = *r.URL
		originalRequest := &http.Request{Method: r.Method, URL: originalURL}

		handler.ServeHTTP(w, r)

		m.statsClient.TrackRequest(timing, originalRequest)
	})
}
<|endoftext|>


<commit_before>package riskanalysis

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"

	"github.com/pkg/errors"
)

// Options is used to run a risk analysis to determine how severe or unusual
// the test failures in an openshift-tests run were.
type Options struct {
	Out, ErrOut io.Writer
	JUnitDir    string
}

const testFailureSummaryFilePrefix = "test-failures-summary"

// Run performs the test risk analysis by reading the output files from the test run, submitting them to sippy,
// and writing out the analysis result as a new artifact.
func (opt *Options) Run() error {
	fmt.Fprintf(opt.Out, "Scanning for %s files in: %s\n", testFailureSummaryFilePrefix, opt.JUnitDir)

	resultFiles, err := filepath.Glob(fmt.Sprintf("%s/%s*.json", opt.JUnitDir, testFailureSummaryFilePrefix))
	if err != nil {
		return err
	}
	fmt.Fprintf(opt.Out, "Found files: %v\n", resultFiles)

	prowJobRuns := []*ProwJobRun{}
	// Read each result file into a ProwJobRun struct:
	for _, rf := range resultFiles {
		data, err := os.ReadFile(rf)
		if err != nil {
			return err
		}
		jobRun := &ProwJobRun{}
		err = json.Unmarshal(data, jobRun)
		if err != nil {
			return errors.Wrapf(err, "error unmarshalling ProwJob json")
		}
		prowJobRuns = append(prowJobRuns, jobRun)
	}

	// We will often have more than one output file for this job run because openshift-tests is often
	// invoked multiple times (pre/post upgrade). We need to merge the data together in this case.
	var finalProwJobRun *ProwJobRun
	for _, pjr := range prowJobRuns {
		if finalProwJobRun == nil {
			finalProwJobRun = pjr
			continue
		}
		if pjr.ProwJob.Name != finalProwJobRun.ProwJob.Name {
			return fmt.Errorf("mismatched job names found in %s files, %s != %s",
				testFailureSummaryFilePrefix, finalProwJobRun.ProwJob.Name, pjr.ProwJob.Name)
		}
		finalProwJobRun.Tests = append(finalProwJobRun.Tests, pjr.Tests...)
	}

	// TODO: query sippy
	url := "http://localhost:8080/api/jobs/runs/risk_analysis"
	inputBytes, err := json.Marshal(finalProwJobRun)
	if err != nil {
		return errors.Wrap(err, "error marshalling results")
	}

	req, err := http.NewRequest("GET", url, bytes.NewBuffer(inputBytes))
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return errors.Wrap(err, "error requesting risk analysis from sippy")
	}
	defer resp.Body.Close()

	riskAnalysisBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return errors.Wrap(err, "error reading risk analysis request body from sippy")
	}
	fmt.Println("response Body:", string(riskAnalysisBytes))

	outputFile := filepath.Join(opt.JUnitDir, "risk-analysis.json")
	err = ioutil.WriteFile(outputFile, riskAnalysisBytes, 0644)
	if err != nil {
		return errors.Wrap(err, "error writing risk analysis json artifact")
	}
	fmt.Fprintf(opt.Out, "Successfully wrote: %s\n", outputFile)

	return nil
}
<commit_msg>Fix to use actual sippy api instead of localhost.<commit_after>package riskanalysis

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"

	"github.com/pkg/errors"
)

// Options is used to run a risk analysis to determine how severe or unusual
// the test failures in an openshift-tests run were.
type Options struct {
	Out, ErrOut io.Writer
	JUnitDir    string
}

const testFailureSummaryFilePrefix = "test-failures-summary"

// Run performs the test risk analysis by reading the output files from the test run, submitting them to sippy,
// and writing out the analysis result as a new artifact.
func (opt *Options) Run() error {
	fmt.Fprintf(opt.Out, "Scanning for %s files in: %s\n", testFailureSummaryFilePrefix, opt.JUnitDir)

	resultFiles, err := filepath.Glob(fmt.Sprintf("%s/%s*.json", opt.JUnitDir, testFailureSummaryFilePrefix))
	if err != nil {
		return err
	}
	fmt.Fprintf(opt.Out, "Found files: %v\n", resultFiles)

	prowJobRuns := []*ProwJobRun{}
	// Read each result file into a ProwJobRun struct:
	for _, rf := range resultFiles {
		data, err := os.ReadFile(rf)
		if err != nil {
			return err
		}
		jobRun := &ProwJobRun{}
		err = json.Unmarshal(data, jobRun)
		if err != nil {
			return errors.Wrapf(err, "error unmarshalling ProwJob json")
		}
		prowJobRuns = append(prowJobRuns, jobRun)
	}

	// We will often have more than one output file for this job run because openshift-tests is often
	// invoked multiple times (pre/post upgrade). We need to merge the data together in this case.
	var finalProwJobRun *ProwJobRun
	for _, pjr := range prowJobRuns {
		if finalProwJobRun == nil {
			finalProwJobRun = pjr
			continue
		}
		if pjr.ProwJob.Name != finalProwJobRun.ProwJob.Name {
			return fmt.Errorf("mismatched job names found in %s files, %s != %s",
				testFailureSummaryFilePrefix, finalProwJobRun.ProwJob.Name, pjr.ProwJob.Name)
		}
		finalProwJobRun.Tests = append(finalProwJobRun.Tests, pjr.Tests...)
	}

	url := "https://sippy.dptools.openshift.org/api/jobs/runs/risk_analysis"
	inputBytes, err := json.Marshal(finalProwJobRun)
	if err != nil {
		return errors.Wrap(err, "error marshalling results")
	}

	req, err := http.NewRequest("GET", url, bytes.NewBuffer(inputBytes))
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return errors.Wrap(err, "error requesting risk analysis from sippy")
	}
	defer resp.Body.Close()

	riskAnalysisBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return errors.Wrap(err, "error reading risk analysis request body from sippy")
	}
	fmt.Println("response Body:", string(riskAnalysisBytes))

	outputFile := filepath.Join(opt.JUnitDir, "risk-analysis.json")
	err = ioutil.WriteFile(outputFile, riskAnalysisBytes, 0644)
	if err != nil {
		return errors.Wrap(err, "error writing risk analysis json artifact")
	}
	fmt.Fprintf(opt.Out, "Successfully wrote: %s\n", outputFile)

	return nil
}
<|endoftext|>


<commit_before>package true_git

import (
	"archive/tar"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strings"

	uuid "github.com/satori/go.uuid"
)

type ArchiveOptions struct {
	Commit     string
	PathFilter PathFilter
}

type ArchiveDescriptor struct {
	Type    ArchiveType
	IsEmpty bool
}

type ArchiveType string

const (
	FileArchive      ArchiveType = "file"
	DirectoryArchive ArchiveType = "directory"
)

func ArchiveWithSubmodules(out io.Writer, gitDir, workTreeDir string, opts ArchiveOptions) (*ArchiveDescriptor, error) {
	return writeArchive(out, gitDir, workTreeDir, true, opts)
}

func Archive(out io.Writer, gitDir, workTreeDir string, opts ArchiveOptions) (*ArchiveDescriptor, error) {
	return writeArchive(out, gitDir, workTreeDir, false, opts)
}

func debugArchive() bool {
	return os.Getenv("DAPP_TRUE_GIT_DEBUG_ARCHIVE") == "1"
}

func writeArchive(out io.Writer, gitDir, workTreeDir string, withSubmodules bool, opts ArchiveOptions) (*ArchiveDescriptor, error) {
	var err error

	gitDir, err = filepath.Abs(gitDir)
	if err != nil {
		return nil, fmt.Errorf("bad git dir `%s`: %s", gitDir, err)
	}

	workTreeDir, err = filepath.Abs(workTreeDir)
	if err != nil {
		return nil, fmt.Errorf("bad work tree dir `%s`: %s", workTreeDir, err)
	}

	if withSubmodules {
		err := checkSubmoduleConstraint()
		if err != nil {
			return nil, err
		}
	}

	err = SwitchWorkTree(gitDir, workTreeDir, opts.Commit)
	if err != nil {
		return nil, fmt.Errorf("cannot reset work tree `%s` to commit `%s`: %s", workTreeDir, opts.Commit, err)
	}

	if withSubmodules {
		err := UpdateSubmodules(gitDir, workTreeDir)
		if err != nil {
			return nil, fmt.Errorf("cannot update submodules: %s", err)
		}
	}

	desc := &ArchiveDescriptor{
		IsEmpty: true,
	}

	tw := tar.NewWriter(out)

	err = filepath.Walk(workTreeDir, func(absPath string, info os.FileInfo, accessErr error) error {
		if accessErr != nil {
			return fmt.Errorf("error accessing `%s`: %s", absPath, accessErr)
		}

		baseName := filepath.Base(absPath)
		for _, p := range []string{".git", ".gitmodules", ".gitkeep", ".gitignore"} {
			if baseName == p {
				return nil
			}
		}

		var path string
		if absPath == workTreeDir {
			path = "."
		} else {
			path = strings.TrimPrefix(absPath, NormalizeDirectoryPrefix(workTreeDir))
		}

		if NormalizeAbsolutePath(path) == NormalizeAbsolutePath(opts.PathFilter.BasePath) {
			if info.IsDir() {
				desc.Type = DirectoryArchive

				if debugArchive() {
					fmt.Printf("Found BasePath `%s` directory: directory archive type\n", path)
				}
			} else {
				desc.Type = FileArchive

				if debugArchive() {
					fmt.Printf("Found BasePath `%s` file: file archive\n", path)
				}
			}
		}

		if info.IsDir() {
			return nil
		}

		if !opts.PathFilter.IsFilePathValid(path) {
			if debugArchive() {
				fmt.Printf("Excluded path `%s` by path filter %s\n", path, opts.PathFilter.String())
			}
			return nil
		}

		archivePath := opts.PathFilter.TrimFileBasePath(path)

		desc.IsEmpty = false

		if info.Mode()&os.ModeSymlink != 0 {
			linkname, err := os.Readlink(absPath)
			if err != nil {
				return fmt.Errorf("cannot read symlink `%s`: %s", absPath, err)
			}

			err = tw.WriteHeader(&tar.Header{
				Format:     tar.FormatGNU,
				Typeflag:   tar.TypeSymlink,
				Name:       archivePath,
				Linkname:   string(linkname),
				Mode:       int64(info.Mode()),
				Size:       info.Size(),
				ModTime:    info.ModTime(),
				AccessTime: info.ModTime(),
				ChangeTime: info.ModTime(),
			})
			if err != nil {
				return fmt.Errorf("unable to write tar symlink header for file `%s`: %s", archivePath, err)
			}

			if debugArchive() {
				fmt.Printf("Added archive symlink `%s` -> `%s`\n", path, linkname)
			}

			return nil
		}

		err = tw.WriteHeader(&tar.Header{
			Format:     tar.FormatGNU,
			Name:       archivePath,
			Mode:       int64(info.Mode()),
			Size:       info.Size(),
			ModTime:    info.ModTime(),
			AccessTime: info.ModTime(),
			ChangeTime: info.ModTime(),
		})
		if err != nil {
			return fmt.Errorf("unable to write tar header for file `%s`: %s", archivePath, err)
		}

		file, err := os.Open(absPath)
		if err != nil {
			return fmt.Errorf("unable to open file `%s`: %s", absPath, err)
		}

		_, err = io.Copy(tw, file)
		if err != nil {
			return fmt.Errorf("unable to write data to tar archive from file `%s`: %s", path, err)
		}

		if debugArchive() {
			fmt.Printf("Added archive file `%s`\n", path)
		}

		return nil
	})

	err = tw.Close()
	if err != nil {
		return nil, fmt.Errorf("cannot write tar archive: %s", err)
	}

	if desc.Type == "" {
		return nil, fmt.Errorf("base path `%s` entry not found repo", opts.PathFilter.BasePath)
	}

	return desc, nil
}

func startMemprofile() {
	runtime.MemProfileRate = 1
}

func stopMemprofile() {
	memprofilePath := fmt.Sprintf("/tmp/create-tar-memprofile-%s", uuid.NewV4())
	fmt.Printf("Creating mem profile: %s\n", memprofilePath)
	f, err := os.Create(memprofilePath)
	if err != nil {
		log.Fatal("could not create memory profile: ", err)
	}
	runtime.GC() // get up-to-date statistics
	if err := pprof.WriteHeapProfile(f); err != nil {
		log.Fatal("could not write memory profile: ", err)
	}
	f.Close()
}
<commit_msg>(go-deeper) preemptive bug fix: properply handle git-archive creation errors<commit_after>package true_git

import (
	"archive/tar"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strings"

	uuid "github.com/satori/go.uuid"
)

type ArchiveOptions struct {
	Commit     string
	PathFilter PathFilter
}

type ArchiveDescriptor struct {
	Type    ArchiveType
	IsEmpty bool
}

type ArchiveType string

const (
	FileArchive      ArchiveType = "file"
	DirectoryArchive ArchiveType = "directory"
)

func ArchiveWithSubmodules(out io.Writer, gitDir, workTreeDir string, opts ArchiveOptions) (*ArchiveDescriptor, error) {
	return writeArchive(out, gitDir, workTreeDir, true, opts)
}

func Archive(out io.Writer, gitDir, workTreeDir string, opts ArchiveOptions) (*ArchiveDescriptor, error) {
	return writeArchive(out, gitDir, workTreeDir, false, opts)
}

func debugArchive() bool {
	return os.Getenv("DAPP_TRUE_GIT_DEBUG_ARCHIVE") == "1"
}

func writeArchive(out io.Writer, gitDir, workTreeDir string, withSubmodules bool, opts ArchiveOptions) (*ArchiveDescriptor, error) {
	var err error

	gitDir, err = filepath.Abs(gitDir)
	if err != nil {
		return nil, fmt.Errorf("bad git dir `%s`: %s", gitDir, err)
	}

	workTreeDir, err = filepath.Abs(workTreeDir)
	if err != nil {
		return nil, fmt.Errorf("bad work tree dir `%s`: %s", workTreeDir, err)
	}

	if withSubmodules {
		err := checkSubmoduleConstraint()
		if err != nil {
			return nil, err
		}
	}

	err = SwitchWorkTree(gitDir, workTreeDir, opts.Commit)
	if err != nil {
		return nil, fmt.Errorf("cannot reset work tree `%s` to commit `%s`: %s", workTreeDir, opts.Commit, err)
	}

	if withSubmodules {
		err := UpdateSubmodules(gitDir, workTreeDir)
		if err != nil {
			return nil, fmt.Errorf("cannot update submodules: %s", err)
		}
	}

	desc := &ArchiveDescriptor{
		IsEmpty: true,
	}

	tw := tar.NewWriter(out)

	err = filepath.Walk(workTreeDir, func(absPath string, info os.FileInfo, accessErr error) error {
		if accessErr != nil {
			return fmt.Errorf("error accessing `%s`: %s", absPath, accessErr)
		}

		baseName := filepath.Base(absPath)
		for _, p := range []string{".git", ".gitmodules", ".gitkeep", ".gitignore"} {
			if baseName == p {
				return nil
			}
		}

		var path string
		if absPath == workTreeDir {
			path = "."
		} else {
			path = strings.TrimPrefix(absPath, NormalizeDirectoryPrefix(workTreeDir))
		}

		if NormalizeAbsolutePath(path) == NormalizeAbsolutePath(opts.PathFilter.BasePath) {
			if info.IsDir() {
				desc.Type = DirectoryArchive

				if debugArchive() {
					fmt.Printf("Found BasePath `%s` directory: directory archive type\n", path)
				}
			} else {
				desc.Type = FileArchive

				if debugArchive() {
					fmt.Printf("Found BasePath `%s` file: file archive\n", path)
				}
			}
		}

		if info.IsDir() {
			return nil
		}

		if !opts.PathFilter.IsFilePathValid(path) {
			if debugArchive() {
				fmt.Printf("Excluded path `%s` by path filter %s\n", path, opts.PathFilter.String())
			}
			return nil
		}

		archivePath := opts.PathFilter.TrimFileBasePath(path)

		desc.IsEmpty = false

		if info.Mode()&os.ModeSymlink != 0 {
			linkname, err := os.Readlink(absPath)
			if err != nil {
				return fmt.Errorf("cannot read symlink `%s`: %s", absPath, err)
			}

			err = tw.WriteHeader(&tar.Header{
				Format:     tar.FormatGNU,
				Typeflag:   tar.TypeSymlink,
				Name:       archivePath,
				Linkname:   string(linkname),
				Mode:       int64(info.Mode()),
				Size:       info.Size(),
				ModTime:    info.ModTime(),
				AccessTime: info.ModTime(),
				ChangeTime: info.ModTime(),
			})
			if err != nil {
				return fmt.Errorf("unable to write tar symlink header for file `%s`: %s", archivePath, err)
			}

			if debugArchive() {
				fmt.Printf("Added archive symlink `%s` -> `%s`\n", path, linkname)
			}

			return nil
		}

		err = tw.WriteHeader(&tar.Header{
			Format:     tar.FormatGNU,
			Name:       archivePath,
			Mode:       int64(info.Mode()),
			Size:       info.Size(),
			ModTime:    info.ModTime(),
			AccessTime: info.ModTime(),
			ChangeTime: info.ModTime(),
		})
		if err != nil {
			return fmt.Errorf("unable to write tar header for file `%s`: %s", archivePath, err)
		}

		file, err := os.Open(absPath)
		if err != nil {
			return fmt.Errorf("unable to open file `%s`: %s", absPath, err)
		}

		_, err = io.Copy(tw, file)
		if err != nil {
			return fmt.Errorf("unable to write data to tar archive from file `%s`: %s", path, err)
		}

		if debugArchive() {
			fmt.Printf("Added archive file `%s`\n", path)
		}

		return nil
	})

	if err != nil {
		return nil, fmt.Errorf("entries iteration failed in `%s`: %s", workTreeDir, err)
	}

	err = tw.Close()
	if err != nil {
		return nil, fmt.Errorf("cannot write tar archive: %s", err)
	}

	if desc.Type == "" {
		return nil, fmt.Errorf("base path `%s` entry not found repo", opts.PathFilter.BasePath)
	}

	return desc, nil
}

func startMemprofile() {
	runtime.MemProfileRate = 1
}

func stopMemprofile() {
	memprofilePath := fmt.Sprintf("/tmp/create-tar-memprofile-%s", uuid.NewV4())
	fmt.Printf("Creating mem profile: %s\n", memprofilePath)
	f, err := os.Create(memprofilePath)
	if err != nil {
		log.Fatal("could not create memory profile: ", err)
	}
	runtime.GC() // get up-to-date statistics
	if err := pprof.WriteHeapProfile(f); err != nil {
		log.Fatal("could not write memory profile: ", err)
	}
	f.Close()
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// TODO(thockin): This whole pkg is pretty linux-centric.  As soon as we have
// an alternate platform, we will need to abstract further.
package mount

import (
	"os"
	"path/filepath"
	"strings"
	"syscall"
)

type FileType string

const (
	// Default mount command if mounter path is not specified
	defaultMountCommand           = "mount"
	MountsInGlobalPDPath          = "mounts"
	FileTypeDirectory    FileType = "Directory"
	FileTypeFile         FileType = "File"
	FileTypeSocket       FileType = "Socket"
	FileTypeCharDev      FileType = "CharDevice"
	FileTypeBlockDev     FileType = "BlockDevice"
)

type Interface interface {
	// Mount mounts source to target as fstype with given options.
	Mount(source string, target string, fstype string, options []string) error
	// Unmount unmounts given target.
	Unmount(target string) error
	// List returns a list of all mounted filesystems.  This can be large.
	// On some platforms, reading mounts is not guaranteed consistent (i.e.
	// it could change between chunked reads). This is guaranteed to be
	// consistent.
	List() ([]MountPoint, error)
	// IsMountPointMatch determines if the mountpoint matches the dir
	IsMountPointMatch(mp MountPoint, dir string) bool
	// IsNotMountPoint determines if a directory is a mountpoint.
	// It should return ErrNotExist when the directory does not exist.
	// IsNotMountPoint is more expensive than IsLikelyNotMountPoint.
	// IsNotMountPoint detects bind mounts in linux.
	// IsNotMountPoint enumerates all the mountpoints using List() and
	// the list of mountpoints may be large, then it uses
	// IsMountPointMatch to evaluate whether the directory is a mountpoint
	IsNotMountPoint(file string) (bool, error)
	// IsLikelyNotMountPoint uses heuristics to determine if a directory
	// is a mountpoint.
	// It should return ErrNotExist when the directory does not exist.
	// IsLikelyNotMountPoint does NOT properly detect all mountpoint types
	// most notably linux bind mounts.
	IsLikelyNotMountPoint(file string) (bool, error)
	// DeviceOpened determines if the device is in use elsewhere
	// on the system, i.e. still mounted.
	DeviceOpened(pathname string) (bool, error)
	// PathIsDevice determines if a path is a device.
	PathIsDevice(pathname string) (bool, error)
	// GetDeviceNameFromMount finds the device name by checking the mount path
	// to get the global mount path which matches its plugin directory
	GetDeviceNameFromMount(mountPath, pluginDir string) (string, error)
	// MakeRShared checks that given path is on a mount with 'rshared' mount
	// propagation. If not, it bind-mounts the path as rshared.
	MakeRShared(path string) error
	// GetFileType checks for file/directory/socket/block/character devices.
	// Will operate in the host mount namespace if kubelet is running in a container
	GetFileType(pathname string) (FileType, error)
	// MakeFile creates an empty file.
	// Will operate in the host mount namespace if kubelet is running in a container
	MakeFile(pathname string) error
	// MakeDir creates a new directory.
	// Will operate in the host mount namespace if kubelet is running in a container
	MakeDir(pathname string) error
	// SafeMakeDir makes sure that the created directory does not escape given
	// base directory mis-using symlinks. The directory is created in the same
	// mount namespace as where kubelet is running. Note that the function makes
	// sure that it creates the directory somewhere under the base, nothing
	// else. E.g. if the directory already exists, it may exists outside of the
	// base due to symlinks.
	SafeMakeDir(pathname string, base string, perm os.FileMode) error
	// ExistsPath checks whether the path exists.
	// Will operate in the host mount namespace if kubelet is running in a container
	ExistsPath(pathname string) bool
	// CleanSubPaths removes any bind-mounts created by PrepareSafeSubpath in given
	// pod volume directory.
	CleanSubPaths(podDir string, volumeName string) error
	// PrepareSafeSubpath does everything that's necessary to prepare a subPath
	// that's 1) inside given volumePath and 2) immutable after this call.
	//
	// newHostPath - location of prepared subPath. It should be used instead of
	// hostName when running the container.
	// cleanupAction - action to run when the container is running or it failed to start.
	//
	// CleanupAction must be called immediately after the container with given
	// subpath starts. On the other hand, Interface.CleanSubPaths must be called
	// when the pod finishes.
	PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error)
}

type Subpath struct {
	// index of the VolumeMount for this container
	VolumeMountIndex int
	// Full path to the subpath directory on the host
	Path string
	// name of the volume that is a valid directory name.
	VolumeName string
	// Full path to the volume path
	VolumePath string
	// Path to the pod's directory, including pod UID
	PodDir string
	// Name of the container
	ContainerName string
}

// Exec executes command where mount utilities are. This can be either the host,
// container where kubelet runs or even a remote pod with mount utilities.
// Usual pkg/util/exec interface is not used because kubelet.RunInContainer does
// not provide stdin/stdout/stderr streams.
type Exec interface {
	// Run executes a command and returns its stdout + stderr combined in one
	// stream.
	Run(cmd string, args ...string) ([]byte, error)
}

// Compile-time check to ensure all Mounter implementations satisfy
// the mount interface
var _ Interface = &Mounter{}

// This represents a single line in /proc/mounts or /etc/fstab.
type MountPoint struct {
	Device string
	Path   string
	Type   string
	Opts   []string
	Freq   int
	Pass   int
}

// SafeFormatAndMount probes a device to see if it is formatted.
// Namely it checks to see if a file system is present. If so it
// mounts it otherwise the device is formatted first then mounted.
type SafeFormatAndMount struct {
	Interface
	Exec
}

// FormatAndMount formats the given disk, if needed, and mounts it.
// That is if the disk is not formatted and it is not being mounted as
// read-only it will format it first then mount it. Otherwise, if the
// disk is already formatted or it is being mounted as read-only, it
// will be mounted without formatting.
func (mounter *SafeFormatAndMount) FormatAndMount(source string, target string, fstype string, options []string) error {
	return mounter.formatAndMount(source, target, fstype, options)
}

// GetMountRefsByDev finds all references to the device provided
// by mountPath; returns a list of paths.
func GetMountRefsByDev(mounter Interface, mountPath string) ([]string, error) {
	mps, err := mounter.List()
	if err != nil {
		return nil, err
	}
	slTarget, err := filepath.EvalSymlinks(mountPath)
	if err != nil {
		slTarget = mountPath
	}

	// Finding the device mounted to mountPath
	diskDev := ""
	for i := range mps {
		if slTarget == mps[i].Path {
			diskDev = mps[i].Device
			break
		}
	}

	// Find all references to the device.
	var refs []string
	for i := range mps {
		if mps[i].Device == diskDev || mps[i].Device == slTarget {
			if mps[i].Path != slTarget {
				refs = append(refs, mps[i].Path)
			}
		}
	}
	return refs, nil
}

// GetDeviceNameFromMount: given a mnt point, find the device from /proc/mounts
// returns the device name, reference count, and error code
func GetDeviceNameFromMount(mounter Interface, mountPath string) (string, int, error) {
	mps, err := mounter.List()
	if err != nil {
		return "", 0, err
	}

	// Find the device name.
	// FIXME if multiple devices mounted on the same mount path, only the first one is returned
	device := ""
	// If mountPath is symlink, need get its target path.
	slTarget, err := filepath.EvalSymlinks(mountPath)
	if err != nil {
		slTarget = mountPath
	}
	for i := range mps {
		if mps[i].Path == slTarget {
			device = mps[i].Device
			break
		}
	}

	// Find all references to the device.
	refCount := 0
	for i := range mps {
		if mps[i].Device == device {
			refCount++
		}
	}
	return device, refCount, nil
}

func isNotDirErr(err error) bool {
	if e, ok := err.(*os.PathError); ok && e.Err == syscall.ENOTDIR {
		return true
	}
	return false
}

// IsNotMountPoint determines if a directory is a mountpoint.
// It should return ErrNotExist when the directory does not exist.
// This method uses the List() of all mountpoints
// It is more extensive than IsLikelyNotMountPoint
// and it detects bind mounts in linux
func IsNotMountPoint(mounter Interface, file string) (bool, error) {
	// IsLikelyNotMountPoint provides a quick check
	// to determine whether file IS A mountpoint
	notMnt, notMntErr := mounter.IsLikelyNotMountPoint(file)
	if notMntErr != nil && os.IsPermission(notMntErr) {
		// We were not allowed to do the simple stat() check, e.g. on NFS with
		// root_squash. Fall back to /proc/mounts check below.
		notMnt = true
		notMntErr = nil
	}
	if notMntErr != nil && isNotDirErr(notMntErr) {
		return notMnt, notMntErr
	}
	// identified as mountpoint, so return this fact
	if notMnt == false {
		return notMnt, nil
	}
	// check all mountpoints since IsLikelyNotMountPoint
	// is not reliable for some mountpoint types
	mountPoints, mountPointsErr := mounter.List()
	if mountPointsErr != nil {
		return notMnt, mountPointsErr
	}
	for _, mp := range mountPoints {
		if mounter.IsMountPointMatch(mp, file) {
			notMnt = false
			break
		}
	}
	return notMnt, nil
}

// isBind detects whether a bind mount is being requested and makes the remount options to
// use in case of bind mount, due to the fact that bind mount doesn't respect mount options.
// The list equals:
//   options - 'bind' + 'remount' (no duplicate)
func isBind(options []string) (bool, []string) {
	bindRemountOpts := []string{"remount"}
	bind := false

	if len(options) != 0 {
		for _, option := range options {
			switch option {
			case "bind":
				bind = true
				break
			case "remount":
				break
			default:
				bindRemountOpts = append(bindRemountOpts, option)
			}
		}
	}

	return bind, bindRemountOpts
}

// TODO: this is a workaround for the unmount device issue caused by gci mounter.
// In GCI cluster, if gci mounter is used for mounting, the container started by mounter
// script will cause additional mounts created in the container. Since these mounts are
// irrelevant to the original mounts, they should be not considered when checking the
// mount references. Current solution is to filter out those mount paths that contain
// the string of original mount path.
// Plan to work on better approach to solve this issue.

func HasMountRefs(mountPath string, mountRefs []string) bool {
	count := 0
	for _, ref := range mountRefs {
		if !strings.Contains(ref, mountPath) {
			count = count + 1
		}
	}
	return count > 0
}

// pathWithinBase checks if give path is within given base directory.
func pathWithinBase(fullPath, basePath string) bool {
	rel, err := filepath.Rel(basePath, fullPath)
	if err != nil {
		return false
	}
	if startsWithBackstep(rel) {
		// Needed to escape the base path
		return false
	}
	return true
}

// startsWithBackstep checks if the given path starts with a backstep segment
func startsWithBackstep(rel string) bool {
	// normalize to / and check for ../
	return rel == ".." || strings.HasPrefix(filepath.ToSlash(rel), "../")
}
<commit_msg>Remove isNotDir error check<commit_after>/*
Copyright 2014 The Kubernetes Authors.

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// TODO(thockin): This whole pkg is pretty linux-centric.  As soon as we have
// an alternate platform, we will need to abstract further.
package mount

import (
	"os"
	"path/filepath"
	"strings"
)

type FileType string

const (
	// Default mount command if mounter path is not specified
	defaultMountCommand           = "mount"
	MountsInGlobalPDPath          = "mounts"
	FileTypeDirectory    FileType = "Directory"
	FileTypeFile         FileType = "File"
	FileTypeSocket       FileType = "Socket"
	FileTypeCharDev      FileType = "CharDevice"
	FileTypeBlockDev     FileType = "BlockDevice"
)

type Interface interface {
	// Mount mounts source to target as fstype with given options.
	Mount(source string, target string, fstype string, options []string) error
	// Unmount unmounts given target.
	Unmount(target string) error
	// List returns a list of all mounted filesystems.  This can be large.
	// On some platforms, reading mounts is not guaranteed consistent (i.e.
	// it could change between chunked reads). This is guaranteed to be
	// consistent.
	List() ([]MountPoint, error)
	// IsMountPointMatch determines if the mountpoint matches the dir
	IsMountPointMatch(mp MountPoint, dir string) bool
	// IsNotMountPoint determines if a directory is a mountpoint.
	// It should return ErrNotExist when the directory does not exist.
	// IsNotMountPoint is more expensive than IsLikelyNotMountPoint.
	// IsNotMountPoint detects bind mounts in linux.
	// IsNotMountPoint enumerates all the mountpoints using List() and
	// the list of mountpoints may be large, then it uses
	// IsMountPointMatch to evaluate whether the directory is a mountpoint
	IsNotMountPoint(file string) (bool, error)
	// IsLikelyNotMountPoint uses heuristics to determine if a directory
	// is a mountpoint.
	// It should return ErrNotExist when the directory does not exist.
	// IsLikelyNotMountPoint does NOT properly detect all mountpoint types
	// most notably linux bind mounts.
	IsLikelyNotMountPoint(file string) (bool, error)
	// DeviceOpened determines if the device is in use elsewhere
	// on the system, i.e. still mounted.
	DeviceOpened(pathname string) (bool, error)
	// PathIsDevice determines if a path is a device.
	PathIsDevice(pathname string) (bool, error)
	// GetDeviceNameFromMount finds the device name by checking the mount path
	// to get the global mount path which matches its plugin directory
	GetDeviceNameFromMount(mountPath, pluginDir string) (string, error)
	// MakeRShared checks that given path is on a mount with 'rshared' mount
	// propagation. If not, it bind-mounts the path as rshared.
	MakeRShared(path string) error
	// GetFileType checks for file/directory/socket/block/character devices.
	// Will operate in the host mount namespace if kubelet is running in a container
	GetFileType(pathname string) (FileType, error)
	// MakeFile creates an empty file.
	// Will operate in the host mount namespace if kubelet is running in a container
	MakeFile(pathname string) error
	// MakeDir creates a new directory.
	// Will operate in the host mount namespace if kubelet is running in a container
	MakeDir(pathname string) error
	// SafeMakeDir makes sure that the created directory does not escape given
	// base directory mis-using symlinks. The directory is created in the same
	// mount namespace as where kubelet is running. Note that the function makes
	// sure that it creates the directory somewhere under the base, nothing
	// else. E.g. if the directory already exists, it may exists outside of the
	// base due to symlinks.
	SafeMakeDir(pathname string, base string, perm os.FileMode) error
	// ExistsPath checks whether the path exists.
	// Will operate in the host mount namespace if kubelet is running in a container
	ExistsPath(pathname string) bool
	// CleanSubPaths removes any bind-mounts created by PrepareSafeSubpath in given
	// pod volume directory.
	CleanSubPaths(podDir string, volumeName string) error
	// PrepareSafeSubpath does everything that's necessary to prepare a subPath
	// that's 1) inside given volumePath and 2) immutable after this call.
	//
	// newHostPath - location of prepared subPath. It should be used instead of
	// hostName when running the container.
	// cleanupAction - action to run when the container is running or it failed to start.
	//
	// CleanupAction must be called immediately after the container with given
	// subpath starts. On the other hand, Interface.CleanSubPaths must be called
	// when the pod finishes.
	PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error)
}

type Subpath struct {
	// index of the VolumeMount for this container
	VolumeMountIndex int
	// Full path to the subpath directory on the host
	Path string
	// name of the volume that is a valid directory name.
	VolumeName string
	// Full path to the volume path
	VolumePath string
	// Path to the pod's directory, including pod UID
	PodDir string
	// Name of the container
	ContainerName string
}

// Exec executes command where mount utilities are. This can be either the host,
// container where kubelet runs or even a remote pod with mount utilities.
// Usual pkg/util/exec interface is not used because kubelet.RunInContainer does
// not provide stdin/stdout/stderr streams.
type Exec interface {
	// Run executes a command and returns its stdout + stderr combined in one
	// stream.
	Run(cmd string, args ...string) ([]byte, error)
}

// Compile-time check to ensure all Mounter implementations satisfy
// the mount interface
var _ Interface = &Mounter{}

// This represents a single line in /proc/mounts or /etc/fstab.
type MountPoint struct {
	Device string
	Path   string
	Type   string
	Opts   []string
	Freq   int
	Pass   int
}

// SafeFormatAndMount probes a device to see if it is formatted.
// Namely it checks to see if a file system is present. If so it
// mounts it otherwise the device is formatted first then mounted.
type SafeFormatAndMount struct {
	Interface
	Exec
}

// FormatAndMount formats the given disk, if needed, and mounts it.
// That is if the disk is not formatted and it is not being mounted as
// read-only it will format it first then mount it. Otherwise, if the
// disk is already formatted or it is being mounted as read-only, it
// will be mounted without formatting.
func (mounter *SafeFormatAndMount) FormatAndMount(source string, target string, fstype string, options []string) error {
	return mounter.formatAndMount(source, target, fstype, options)
}

// GetMountRefsByDev finds all references to the device provided
// by mountPath; returns a list of paths.
func GetMountRefsByDev(mounter Interface, mountPath string) ([]string, error) {
	mps, err := mounter.List()
	if err != nil {
		return nil, err
	}
	slTarget, err := filepath.EvalSymlinks(mountPath)
	if err != nil {
		slTarget = mountPath
	}

	// Finding the device mounted to mountPath
	diskDev := ""
	for i := range mps {
		if slTarget == mps[i].Path {
			diskDev = mps[i].Device
			break
		}
	}

	// Find all references to the device.
	var refs []string
	for i := range mps {
		if mps[i].Device == diskDev || mps[i].Device == slTarget {
			if mps[i].Path != slTarget {
				refs = append(refs, mps[i].Path)
			}
		}
	}
	return refs, nil
}

// GetDeviceNameFromMount: given a mnt point, find the device from /proc/mounts
// returns the device name, reference count, and error code
func GetDeviceNameFromMount(mounter Interface, mountPath string) (string, int, error) {
	mps, err := mounter.List()
	if err != nil {
		return "", 0, err
	}

	// Find the device name.
	// FIXME if multiple devices mounted on the same mount path, only the first one is returned
	device := ""
	// If mountPath is symlink, need get its target path.
	slTarget, err := filepath.EvalSymlinks(mountPath)
	if err != nil {
		slTarget = mountPath
	}
	for i := range mps {
		if mps[i].Path == slTarget {
			device = mps[i].Device
			break
		}
	}

	// Find all references to the device.
	refCount := 0
	for i := range mps {
		if mps[i].Device == device {
			refCount++
		}
	}
	return device, refCount, nil
}

// IsNotMountPoint determines if a directory is a mountpoint.
// It should return ErrNotExist when the directory does not exist.
// This method uses the List() of all mountpoints
// It is more extensive than IsLikelyNotMountPoint
// and it detects bind mounts in linux
func IsNotMountPoint(mounter Interface, file string) (bool, error) {
	// IsLikelyNotMountPoint provides a quick check
	// to determine whether file IS A mountpoint
	notMnt, notMntErr := mounter.IsLikelyNotMountPoint(file)
	if notMntErr != nil && os.IsPermission(notMntErr) {
		// We were not allowed to do the simple stat() check, e.g. on NFS with
		// root_squash. Fall back to /proc/mounts check below.
		notMnt = true
		notMntErr = nil
	}
	if notMntErr != nil {
		return notMnt, notMntErr
	}
	// identified as mountpoint, so return this fact
	if notMnt == false {
		return notMnt, nil
	}
	// check all mountpoints since IsLikelyNotMountPoint
	// is not reliable for some mountpoint types
	mountPoints, mountPointsErr := mounter.List()
	if mountPointsErr != nil {
		return notMnt, mountPointsErr
	}
	for _, mp := range mountPoints {
		if mounter.IsMountPointMatch(mp, file) {
			notMnt = false
			break
		}
	}
	return notMnt, nil
}

// isBind detects whether a bind mount is being requested and makes the remount options to
// use in case of bind mount, due to the fact that bind mount doesn't respect mount options.
// The list equals:
//   options - 'bind' + 'remount' (no duplicate)
func isBind(options []string) (bool, []string) {
	bindRemountOpts := []string{"remount"}
	bind := false

	if len(options) != 0 {
		for _, option := range options {
			switch option {
			case "bind":
				bind = true
				break
			case "remount":
				break
			default:
				bindRemountOpts = append(bindRemountOpts, option)
			}
		}
	}

	return bind, bindRemountOpts
}

// TODO: this is a workaround for the unmount device issue caused by gci mounter.
// In GCI cluster, if gci mounter is used for mounting, the container started by mounter
// script will cause additional mounts created in the container. Since these mounts are
// irrelevant to the original mounts, they should be not considered when checking the
// mount references. Current solution is to filter out those mount paths that contain
// the string of original mount path.
// Plan to work on better approach to solve this issue.

func HasMountRefs(mountPath string, mountRefs []string) bool {
	count := 0
	for _, ref := range mountRefs {
		if !strings.Contains(ref, mountPath) {
			count = count + 1
		}
	}
	return count > 0
}

// pathWithinBase checks if give path is within given base directory.
func pathWithinBase(fullPath, basePath string) bool {
	rel, err := filepath.Rel(basePath, fullPath)
	if err != nil {
		return false
	}
	if startsWithBackstep(rel) {
		// Needed to escape the base path
		return false
	}
	return true
}

// startsWithBackstep checks if the given path starts with a backstep segment
func startsWithBackstep(rel string) bool {
	// normalize to / and check for ../
	return rel == ".." || strings.HasPrefix(filepath.ToSlash(rel), "../")
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Google Inc. All rights reserved.

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package util

import (
	"os"
	"path"

	"github.com/golang/glog"
)

const readyFileName = "ready"

// IsReady checks for the existence of a regular file
// called 'ready' in the given directory and returns
// true if that file exists.
func IsReady(dir string) bool {
	readyFile := path.Join(dir, readyFileName)
	s, err := os.Stat(readyFile)
	if err != nil {
		return false
	}

	if !s.Mode().IsRegular() {
		glog.Errorf("ready-file is not a file: %s", readyFile)
		return false
	}

	return true
}

// SetReady creates a file called 'ready' in the given
// directory.  It logs an error if the file cannot be
// created.
func SetReady(dir string) {
	if err := os.MkdirAll(dir, 0750); err != nil && !os.IsExist(err) {
		glog.Errorf("Can't mkdir %s: %v", dir, err)
		return
	}

	readyFile := path.Join(dir, readyFileName)
	file, err := os.Create(readyFile)
	if err != nil {
		glog.Errorf("Can't touch %s: %v", readyFile, err)
		return
	}
	file.Close()
}
<commit_msg>Make copyright ownership statement generic<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package util

import (
	"os"
	"path"

	"github.com/golang/glog"
)

const readyFileName = "ready"

// IsReady checks for the existence of a regular file
// called 'ready' in the given directory and returns
// true if that file exists.
func IsReady(dir string) bool {
	readyFile := path.Join(dir, readyFileName)
	s, err := os.Stat(readyFile)
	if err != nil {
		return false
	}

	if !s.Mode().IsRegular() {
		glog.Errorf("ready-file is not a file: %s", readyFile)
		return false
	}

	return true
}

// SetReady creates a file called 'ready' in the given
// directory.  It logs an error if the file cannot be
// created.
func SetReady(dir string) {
	if err := os.MkdirAll(dir, 0750); err != nil && !os.IsExist(err) {
		glog.Errorf("Can't mkdir %s: %v", dir, err)
		return
	}

	readyFile := path.Join(dir, readyFileName)
	file, err := os.Create(readyFile)
	if err != nil {
		glog.Errorf("Can't touch %s: %v", readyFile, err)
		return
	}
	file.Close()
}
<|endoftext|>


<commit_before>// +build !linux,!freebsd

package platform

import "fmt"

func Getexe() (string, error) {
	return "", fmt.Errorf("This platform is unsupported")
}
<commit_msg>I think the unsupported file is unnecessary, failure to build is good enough<commit_after><|endoftext|>


<commit_before>package bluckstore

import (
	"io/ioutil"
	"strings"
	"os"
	"bufio"
	"strconv"
	"github.com/BenJoyenConseil/bluckdb/util"
)

const extension = ".blk"
const filename = "data"
const path = "/tmp/"

type DiskKVStore struct {}

func (store *DiskKVStore) Get(key string) string {
	var value string
	file := buildPartitionFilePathString(util.String(key))
	body, _ := ioutil.ReadFile(file)
	lines := strings.Split(string(body), "\n")

	for i := range lines {
		keyValuePair := strings.Split(lines[i], ":")
		if keyValuePair[0] == key {
			value = keyValuePair[1]
		}
	}
	if len(value) > 0 {
		return value
	}
	return "no such key"
}

func (store *DiskKVStore) Put(k, value string)  {

	file := buildPartitionFilePathString(util.String(k))
	f, err := os.OpenFile(file, os.O_APPEND|os.O_RDWR, 0600)
	if err != nil {
		panic(err)
	}
	defer f.Close()

	writer := bufio.NewWriter(f)
	writer.WriteString(k)
	writer.WriteString(":")
	writer.WriteString(value)
	writer.WriteString("\n")
	writer.Flush()
}

func NewDiskStore() KVStore {

	for i := 0; i < BUCKET_NUMER; i++ {
		file := buildPartitionFilePathString(util.String(strconv.Itoa(i)))
		f, _ := os.OpenFile(file, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0600)
		f.Close()
	}
	return &DiskKVStore{}
}

func buildPartitionFilePathString(key util.String) string{
	bucketId := strconv.Itoa(key.Hash() % BUCKET_NUMER)
	return path + filename + bucketId + extension
}
<commit_msg>improve the search : by starting at the end of file<commit_after>package bluckstore

import (
	"io/ioutil"
	"strings"
	"os"
	"bufio"
	"strconv"
	"github.com/BenJoyenConseil/bluckdb/util"
)

const extension = ".blk"
const filename = "data"
const path = "/tmp/"

type DiskKVStore struct {}

func (store *DiskKVStore) Get(key string) string {
	file := buildPartitionFilePathString(util.String(key))
	body, _ := ioutil.ReadFile(file)
	lines := strings.Split(string(body), "\n")

	for i := len(lines) -1; i >= 0 ; i-- {
		keyValuePair := strings.Split(lines[i], ":")
		if keyValuePair[0] == key {
			return keyValuePair[1]
		}
	}
	return "no such key"
}

func (store *DiskKVStore) Put(k, value string)  {

	file := buildPartitionFilePathString(util.String(k))
	f, err := os.OpenFile(file, os.O_APPEND|os.O_RDWR, 0600)
	if err != nil {
		panic(err)
	}
	defer f.Close()

	writer := bufio.NewWriter(f)
	writer.WriteString(k)
	writer.WriteString(":")
	writer.WriteString(value)
	writer.WriteString("\n")
	writer.Flush()
}

func NewDiskStore() KVStore {

	for i := 0; i < BUCKET_NUMER; i++ {
		file := buildPartitionFilePathString(util.String(strconv.Itoa(i)))
		f, _ := os.OpenFile(file, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0600)
		f.Close()
	}
	return &DiskKVStore{}
}

func buildPartitionFilePathString(key util.String) string{
	bucketId := strconv.Itoa(key.Hash() % BUCKET_NUMER)
	return path + filename + bucketId + extension
}
<|endoftext|>


<commit_before>// This is free and unencumbered software released into the public
// domain.  For more information, see <http://unlicense.org> or the
// accompanying UNLICENSE file.

package gocode

import (
	"context"
	"log"
	"sync"

	"github.com/nelsam/gxui"
	"github.com/nelsam/gxui/math"
	"github.com/nelsam/gxui/themes/basic"
	"github.com/nelsam/vidar/commander/input"
	"github.com/nelsam/vidar/commands/cursor"
	"github.com/nelsam/vidar/settings"
)

type Projecter interface {
	Project() settings.Project
}

func New(theme *basic.Theme, driver gxui.Driver) (*Completions, *GoCode) {
	g := GoCode{
		driver:  driver,
		lists:   make(map[Editor]*suggestionList),
		cancels: make(map[Editor]func()),
	}
	c := Completions{
		gocode: &g,
	}
	c.Theme = theme
	return &c, &g
}

func ctxCancelled(ctx context.Context) bool {
	select {
	case <-ctx.Done():
		return true
	default:
		return false
	}
}

type GoCode struct {
	driver gxui.Driver

	mu      sync.RWMutex
	lists   map[Editor]*suggestionList
	cancels map[Editor]func()
}

func (g *GoCode) Name() string {
	return "gocode-updates"
}

func (g *GoCode) OpNames() []string {
	return []string{"cursor-movement", "input-handler"}
}

func (g *GoCode) cancel(e Editor) {
	g.mu.Lock()
	defer g.mu.Unlock()
	if cancel, ok := g.cancels[e]; ok {
		cancel()
		delete(g.cancels, e)
	}
}

func (g *GoCode) show(ctx context.Context, l *suggestionList, pos int) {
	n := l.show(ctx, pos)
	if n == 0 || ctxCancelled(ctx) {
		log.Printf("cancelled or %d == 0", n)
		return
	}

	bounds := l.editor.Size().Rect().Contract(l.editor.Padding())
	line := l.editor.Line(l.editor.LineIndex(pos))
	lineOffset := gxui.ChildToParent(math.ZeroPoint, line, l.editor)
	target := line.PositionAt(pos).Add(lineOffset)
	cs := l.DesiredSize(math.ZeroSize, bounds.Size())

	g.driver.Call(func() {
		if ctxCancelled(ctx) {
			log.Printf("cancelled")
			return
		}
		l.SetSize(cs)
		c := l.editor.AddChild(l)
		c.Layout(cs.Rect().Offset(target).Intersect(bounds))
		l.Redraw()
		l.editor.Redraw()
	})
}

func (g *GoCode) set(e Editor, l *suggestionList, pos int) {
	g.mu.Lock()
	defer g.mu.Unlock()
	if cancel, ok := g.cancels[e]; ok {
		cancel()
	}
	g.lists[e] = l
	ctx, cancel := context.WithCancel(context.Background())
	g.cancels[e] = cancel
	go g.show(ctx, l, pos)
}

func (g *GoCode) Moving(ie input.Editor, d cursor.Direction, cursors []int) cursor.Direction {
	e := ie.(Editor)
	g.mu.RLock()
	defer g.mu.RUnlock()
	l, ok := g.lists[e]
	if !ok {
		return d
	}
	if !l.Attached() {
		if cancel, ok := g.cancels[e]; ok {
			cancel()
		}
		return d
	}
	if len(cursors) != 1 {
		g.stop(e)
		return d
	}
	switch d {
	case cursor.Up:
		l.SelectPrevious()
	case cursor.Down:
		l.SelectNext()
	default:
		return d
	}
	return cursor.NoDirection
}

func (g *GoCode) Moved(ie input.Editor, d cursor.Direction, cursors []int) {
	e := ie.(Editor)
	g.mu.RLock()
	defer g.mu.RUnlock()
	l, ok := g.lists[e]
	if !ok {
		return
	}
	if !l.Attached() {
		return
	}
	if len(cursors) != 1 {
		return
	}
	pos := cursors[0]

	if cancel, ok := g.cancels[e]; ok {
		cancel()
	}
	ctx, cancel := context.WithCancel(context.Background())
	g.cancels[e] = cancel
	e.RemoveChild(l)
	go g.show(ctx, l, pos)
}

func (g *GoCode) Cancel(ie input.Editor) bool {
	g.mu.Lock()
	defer g.mu.Unlock()
	return g.stop(ie.(Editor))
}

func (g *GoCode) stop(e Editor) bool {
	if cancel, ok := g.cancels[e]; ok {
		cancel()
		delete(g.cancels, e)
	}
	if l, ok := g.lists[e]; ok {
		e.RemoveChild(l)
		delete(g.lists, e)
		return true
	}
	return false
}

func (g *GoCode) Confirm(ie input.Editor) bool {
	e := ie.(Editor)
	g.mu.Lock()
	defer g.mu.Unlock()
	l, ok := g.lists[e]
	if !ok {
		return false
	}
	g.stop(e)
	l.apply()
	return true
}
<commit_msg>Don't try to remove suggestion list if it's not attached<commit_after>// This is free and unencumbered software released into the public
// domain.  For more information, see <http://unlicense.org> or the
// accompanying UNLICENSE file.

package gocode

import (
	"context"
	"log"
	"sync"

	"github.com/nelsam/gxui"
	"github.com/nelsam/gxui/math"
	"github.com/nelsam/gxui/themes/basic"
	"github.com/nelsam/vidar/commander/input"
	"github.com/nelsam/vidar/commands/cursor"
	"github.com/nelsam/vidar/settings"
)

type Projecter interface {
	Project() settings.Project
}

func New(theme *basic.Theme, driver gxui.Driver) (*Completions, *GoCode) {
	g := GoCode{
		driver:  driver,
		lists:   make(map[Editor]*suggestionList),
		cancels: make(map[Editor]func()),
	}
	c := Completions{
		gocode: &g,
	}
	c.Theme = theme
	return &c, &g
}

func ctxCancelled(ctx context.Context) bool {
	select {
	case <-ctx.Done():
		return true
	default:
		return false
	}
}

type GoCode struct {
	driver gxui.Driver

	mu      sync.RWMutex
	lists   map[Editor]*suggestionList
	cancels map[Editor]func()
}

func (g *GoCode) Name() string {
	return "gocode-updates"
}

func (g *GoCode) OpNames() []string {
	return []string{"cursor-movement", "input-handler"}
}

func (g *GoCode) cancel(e Editor) {
	g.mu.Lock()
	defer g.mu.Unlock()
	if cancel, ok := g.cancels[e]; ok {
		cancel()
		delete(g.cancels, e)
	}
}

func (g *GoCode) show(ctx context.Context, l *suggestionList, pos int) {
	n := l.show(ctx, pos)
	if n == 0 || ctxCancelled(ctx) {
		log.Printf("cancelled or %d == 0", n)
		return
	}

	bounds := l.editor.Size().Rect().Contract(l.editor.Padding())
	line := l.editor.Line(l.editor.LineIndex(pos))
	lineOffset := gxui.ChildToParent(math.ZeroPoint, line, l.editor)
	target := line.PositionAt(pos).Add(lineOffset)
	cs := l.DesiredSize(math.ZeroSize, bounds.Size())

	g.driver.Call(func() {
		if ctxCancelled(ctx) {
			log.Printf("cancelled")
			return
		}
		l.SetSize(cs)
		c := l.editor.AddChild(l)
		c.Layout(cs.Rect().Offset(target).Intersect(bounds))
		l.Redraw()
		l.editor.Redraw()
	})
}

func (g *GoCode) set(e Editor, l *suggestionList, pos int) {
	g.mu.Lock()
	defer g.mu.Unlock()
	if cancel, ok := g.cancels[e]; ok {
		cancel()
	}
	g.lists[e] = l
	ctx, cancel := context.WithCancel(context.Background())
	g.cancels[e] = cancel
	go g.show(ctx, l, pos)
}

func (g *GoCode) Moving(ie input.Editor, d cursor.Direction, cursors []int) cursor.Direction {
	e := ie.(Editor)
	g.mu.RLock()
	defer g.mu.RUnlock()
	l, ok := g.lists[e]
	if !ok {
		return d
	}
	if !l.Attached() {
		if cancel, ok := g.cancels[e]; ok {
			cancel()
		}
		return d
	}
	if len(cursors) != 1 {
		g.stop(e)
		return d
	}
	switch d {
	case cursor.Up:
		l.SelectPrevious()
	case cursor.Down:
		l.SelectNext()
	default:
		return d
	}
	return cursor.NoDirection
}

func (g *GoCode) Moved(ie input.Editor, d cursor.Direction, cursors []int) {
	e := ie.(Editor)
	g.mu.RLock()
	defer g.mu.RUnlock()
	l, ok := g.lists[e]
	if !ok {
		return
	}
	if !l.Attached() {
		return
	}
	if len(cursors) != 1 {
		return
	}
	pos := cursors[0]

	if cancel, ok := g.cancels[e]; ok {
		cancel()
	}
	ctx, cancel := context.WithCancel(context.Background())
	g.cancels[e] = cancel
	e.RemoveChild(l)
	go g.show(ctx, l, pos)
}

func (g *GoCode) Cancel(ie input.Editor) bool {
	g.mu.Lock()
	defer g.mu.Unlock()
	return g.stop(ie.(Editor))
}

func (g *GoCode) stop(e Editor) bool {
	if cancel, ok := g.cancels[e]; ok {
		cancel()
		delete(g.cancels, e)
	}
	if l, ok := g.lists[e]; ok {
		if e.Children().Find(l) != nil {
			e.RemoveChild(l)
		}
		delete(g.lists, e)
		return true
	}
	return false
}

func (g *GoCode) Confirm(ie input.Editor) bool {
	e := ie.(Editor)
	g.mu.Lock()
	defer g.mu.Unlock()
	l, ok := g.lists[e]
	if !ok {
		return false
	}
	g.stop(e)
	l.apply()
	return true
}
<|endoftext|>