<commit_before>package cacheddownloader

import (
	"bytes"
	"crypto/md5"
	"crypto/tls"
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

const MAX_DOWNLOAD_ATTEMPTS = 3

var ErrDownloadCancelled error = errors.New("Download cancelled")

type Downloader struct {
	client                    *http.Client
	concurrentDownloadBarrier chan struct{}
}

func NewDownloader(timeout time.Duration, maxConcurrentDownloads int, skipSSLVerification bool) *Downloader {
	transport := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 30 * time.Second,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: skipSSLVerification,
			MinVersion:         tls.VersionTLS10,
		},
		ResponseHeaderTimeout: timeout,
	}
	client := &http.Client{
		Transport: transport,
	}

	return &Downloader{
		client: client,
		concurrentDownloadBarrier: make(chan struct{}, maxConcurrentDownloads),
	}
}

func (downloader *Downloader) Download(
	url *url.URL,
	createDestination func() (*os.File, error),
	cachingInfoIn CachingInfoType,
	cancelChan <-chan struct{},
) (path string, cachingInfoOut CachingInfoType, err error) {

	select {
	case downloader.concurrentDownloadBarrier <- struct{}{}:
	case <-cancelChan:
		return "", CachingInfoType{}, ErrDownloadCancelled
	}

	defer func() {
		<-downloader.concurrentDownloadBarrier
	}()

	for attempt := 0; attempt < MAX_DOWNLOAD_ATTEMPTS; attempt++ {
		path, cachingInfoOut, err = downloader.fetchToFile(url, createDestination, cachingInfoIn, cancelChan)

		if err == ErrDownloadCancelled || err == nil {
			break
		}
	}

	if err != nil {
		return "", CachingInfoType{}, err
	}

	return
}

func (downloader *Downloader) fetchToFile(
	url *url.URL,
	createDestination func() (*os.File, error),
	cachingInfoIn CachingInfoType,
	cancelChan <-chan struct{},
) (string, CachingInfoType, error) {
	var req *http.Request
	var err error

	req, err = http.NewRequest("GET", url.String(), nil)
	if err != nil {
		return "", CachingInfoType{}, err
	}

	if cachingInfoIn.ETag != "" {
		req.Header.Add("If-None-Match", cachingInfoIn.ETag)
	}
	if cachingInfoIn.LastModified != "" {
		req.Header.Add("If-Modified-Since", cachingInfoIn.LastModified)
	}

	completeChan := make(chan struct{})
	defer close(completeChan)

	if transport, ok := downloader.client.Transport.(*http.Transport); ok {
		go func() {
			select {
			case <-completeChan:
			case <-cancelChan:
				transport.CancelRequest(req)
			}
		}()
	}

	var resp *http.Response
	resp, err = downloader.client.Do(req)
	if err != nil {
		select {
		case <-cancelChan:
			err = ErrDownloadCancelled
		default:
		}
		return "", CachingInfoType{}, err
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusNotModified {
		return "", CachingInfoType{}, nil
	}

	if resp.StatusCode != http.StatusOK {
		return "", CachingInfoType{}, fmt.Errorf("Download failed: Status code %d", resp.StatusCode)
	}

	var destinationFile *os.File
	destinationFile, err = createDestination()
	if err != nil {
		return "", CachingInfoType{}, err
	}

	defer func() {
		destinationFile.Close()
		if err != nil {
			os.Remove(destinationFile.Name())
		}
	}()

	_, err = destinationFile.Seek(0, 0)
	if err != nil {
		return "", CachingInfoType{}, err
	}

	err = destinationFile.Truncate(0)
	if err != nil {
		return "", CachingInfoType{}, err
	}

	go func() {
		select {
		case <-completeChan:
		case <-cancelChan:
			resp.Body.Close()
		}
	}()

	hash := md5.New()

	_, err = io.Copy(io.MultiWriter(destinationFile, hash), resp.Body)
	if err != nil {
		select {
		case <-cancelChan:
			err = ErrDownloadCancelled
		default:
		}
		return "", CachingInfoType{}, err
	}

	cachingInfoOut := CachingInfoType{
		ETag:         resp.Header.Get("ETag"),
		LastModified: resp.Header.Get("Last-Modified"),
	}

	etagChecksum, ok := convertETagToChecksum(cachingInfoOut.ETag)

	if ok && !bytes.Equal(etagChecksum, hash.Sum(nil)) {
		err = fmt.Errorf("Download failed: Checksum mismatch")
		return "", CachingInfoType{}, err
	}

	return destinationFile.Name(), cachingInfoOut, nil
}

// convertETagToChecksum returns true if ETag is a valid MD5 hash, so a checksum action was intended.
// See here for our motivation: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTCommonResponseHeaders.html
func convertETagToChecksum(etag string) ([]byte, bool) {
	etag = strings.Trim(etag, `"`)

	if len(etag) != 32 {
		return nil, false
	}

	c, err := hex.DecodeString(etag)
	if err != nil {
		return nil, false
	}

	return c, true
}
<commit_msg>Replace ResponseHeaderTimeout with Timeout<commit_after>package cacheddownloader

import (
	"bytes"
	"crypto/md5"
	"crypto/tls"
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

const MAX_DOWNLOAD_ATTEMPTS = 3

var ErrDownloadCancelled error = errors.New("Download cancelled")

type Downloader struct {
	client                    *http.Client
	concurrentDownloadBarrier chan struct{}
}

func NewDownloader(timeout time.Duration, maxConcurrentDownloads int, skipSSLVerification bool) *Downloader {
	transport := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 30 * time.Second,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: skipSSLVerification,
			MinVersion:         tls.VersionTLS10,
		},
	}

	client := &http.Client{
		Transport: transport,
		Timeout:   timeout,
	}

	return &Downloader{
		client: client,
		concurrentDownloadBarrier: make(chan struct{}, maxConcurrentDownloads),
	}
}

func (downloader *Downloader) Download(
	url *url.URL,
	createDestination func() (*os.File, error),
	cachingInfoIn CachingInfoType,
	cancelChan <-chan struct{},
) (path string, cachingInfoOut CachingInfoType, err error) {

	select {
	case downloader.concurrentDownloadBarrier <- struct{}{}:
	case <-cancelChan:
		return "", CachingInfoType{}, ErrDownloadCancelled
	}

	defer func() {
		<-downloader.concurrentDownloadBarrier
	}()

	for attempt := 0; attempt < MAX_DOWNLOAD_ATTEMPTS; attempt++ {
		path, cachingInfoOut, err = downloader.fetchToFile(url, createDestination, cachingInfoIn, cancelChan)

		if err == ErrDownloadCancelled || err == nil {
			break
		}
	}

	if err != nil {
		return "", CachingInfoType{}, err
	}

	return
}

func (downloader *Downloader) fetchToFile(
	url *url.URL,
	createDestination func() (*os.File, error),
	cachingInfoIn CachingInfoType,
	cancelChan <-chan struct{},
) (string, CachingInfoType, error) {
	var req *http.Request
	var err error

	req, err = http.NewRequest("GET", url.String(), nil)
	if err != nil {
		return "", CachingInfoType{}, err
	}

	if cachingInfoIn.ETag != "" {
		req.Header.Add("If-None-Match", cachingInfoIn.ETag)
	}
	if cachingInfoIn.LastModified != "" {
		req.Header.Add("If-Modified-Since", cachingInfoIn.LastModified)
	}

	completeChan := make(chan struct{})
	defer close(completeChan)

	if transport, ok := downloader.client.Transport.(*http.Transport); ok {
		go func() {
			select {
			case <-completeChan:
			case <-cancelChan:
				transport.CancelRequest(req)
			}
		}()
	}

	var resp *http.Response
	resp, err = downloader.client.Do(req)
	if err != nil {
		select {
		case <-cancelChan:
			err = ErrDownloadCancelled
		default:
		}
		return "", CachingInfoType{}, err
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusNotModified {
		return "", CachingInfoType{}, nil
	}

	if resp.StatusCode != http.StatusOK {
		return "", CachingInfoType{}, fmt.Errorf("Download failed: Status code %d", resp.StatusCode)
	}

	var destinationFile *os.File
	destinationFile, err = createDestination()
	if err != nil {
		return "", CachingInfoType{}, err
	}

	defer func() {
		destinationFile.Close()
		if err != nil {
			os.Remove(destinationFile.Name())
		}
	}()

	_, err = destinationFile.Seek(0, 0)
	if err != nil {
		return "", CachingInfoType{}, err
	}

	err = destinationFile.Truncate(0)
	if err != nil {
		return "", CachingInfoType{}, err
	}

	go func() {
		select {
		case <-completeChan:
		case <-cancelChan:
			resp.Body.Close()
		}
	}()

	hash := md5.New()

	_, err = io.Copy(io.MultiWriter(destinationFile, hash), resp.Body)
	if err != nil {
		select {
		case <-cancelChan:
			err = ErrDownloadCancelled
		default:
		}
		return "", CachingInfoType{}, err
	}

	cachingInfoOut := CachingInfoType{
		ETag:         resp.Header.Get("ETag"),
		LastModified: resp.Header.Get("Last-Modified"),
	}

	etagChecksum, ok := convertETagToChecksum(cachingInfoOut.ETag)

	if ok && !bytes.Equal(etagChecksum, hash.Sum(nil)) {
		err = fmt.Errorf("Download failed: Checksum mismatch")
		return "", CachingInfoType{}, err
	}

	return destinationFile.Name(), cachingInfoOut, nil
}

// convertETagToChecksum returns true if ETag is a valid MD5 hash, so a checksum action was intended.
// See here for our motivation: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTCommonResponseHeaders.html
func convertETagToChecksum(etag string) ([]byte, bool) {
	etag = strings.Trim(etag, `"`)

	if len(etag) != 32 {
		return nil, false
	}

	c, err := hex.DecodeString(etag)
	if err != nil {
		return nil, false
	}

	return c, true
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2014 The foocsim 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 caches

import (
	"fmt"
	"github.com/lpabon/godbc"
)

/* -------------------------------------------------------- */
type IoCacheBlockInfo struct {
	key  string
	used bool
}

type IoCacheBlocks struct {
	cacheblocks []IoCacheBlockInfo
	size        uint64
	index       uint64
}

func NewIoCacheBlocks(cachesize uint64) *IoCacheBlocks {
	icb := &IoCacheBlocks{}
	icb.cacheblocks = make([]IoCacheBlockInfo, cachesize)
	icb.size = cachesize
	return icb
}

func (c *IoCacheBlocks) Insert(key string) (evictkey string, newindex uint64, err error) {
	for {
		for ; c.index < c.size; c.index++ {
			if c.cacheblocks[c.index].used == true {
				c.cacheblocks[c.index].used = false
			} else {
				evictkey = c.cacheblocks[c.index].key
				newindex = c.index
				err = nil
				c.cacheblocks[c.index].key = key
				c.cacheblocks[c.index].used = true
				return
			}
		}
		c.index = 0
	}
}

func (c *IoCacheBlocks) Using(index uint64) {
	c.cacheblocks[index].used = true
}

func (c *IoCacheBlocks) Free(index uint64) {
	c.cacheblocks[index].used = false
}

/* -------------------------------------------------------- */

type IoCache struct {
	stats        CacheStats
	cachemap     map[string]uint64
	cachesize    uint64
	writethrough bool
	cacheblocks  *IoCacheBlocks
}

func NewIoCache(cachesize uint64, writethrough bool) *IoCache {
	godbc.Require(cachesize > 0)

	cache := &IoCache{}
	cache.cacheblocks = NewIoCacheBlocks(cachesize)
	cache.cachemap = make(map[string]uint64)
	cache.cachesize = cachesize
	cache.writethrough = writethrough

	godbc.Ensure(cache.cachesize > 0)

	return cache
}

func (s *IoCache) Close() {

}

func (c *IoCache) Invalidate(key string) {
	if val, ok := c.cachemap[key]; ok {
		c.stats.writehits++
		c.stats.invalidations++
		c.cacheblocks.Free(val)
		delete(c.cachemap, key)
	}
}

func (c *IoCache) Insert(key string) {
	c.stats.insertions++

	evictkey, index, _ := c.cacheblocks.Insert(key)

	// Check for evictions
	if evictkey != "" {
		delete(c.cachemap, evictkey)
	}

	// Insert new key in cache map
	c.cachemap[key] = index
}

func (c *IoCache) Write(obj string, chunk string) {
	c.stats.writes++

	key := obj + chunk

	// Invalidate
	c.Invalidate(key)

	// We would do back end IO here

	// Insert
	if c.writethrough {
		c.Insert(key)
	}
}

func (c *IoCache) Read(obj, chunk string) {
	c.stats.reads++

	key := obj + chunk

	if val, ok := c.cachemap[key]; ok {
		// Read Hit
		c.stats.readhits++

		// Clock Algorithm: Set that we looked
		// at it
		c.cacheblocks.Using(val)
	} else {
		// Read miss
		// We would do IO here
		c.Insert(key)
	}
}

func (c *IoCache) Delete(obj string) {
	// Not supported
}

func (c *IoCache) String() string {
	return fmt.Sprintf(
		"== Cache Information ==\n"+
			"Cache Utilization: %.2f %%\n",
		float64(len(c.cachemap))/float64(c.cachesize)*100.0) +
		c.stats.String()
}

func (c *IoCache) Stats() *CacheStats {
	return c.stats.Copy()
}
<commit_msg>Fixed iocache evictions<commit_after>//
// Copyright (c) 2014 The foocsim 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 caches

import (
	"fmt"
	"github.com/lpabon/godbc"
)

/* -------------------------------------------------------- */
type IoCacheBlockInfo struct {
	key  string
	mru  bool
	used bool
}

type IoCacheBlocks struct {
	cacheblocks []IoCacheBlockInfo
	size        uint64
	index       uint64
}

func NewIoCacheBlocks(cachesize uint64) *IoCacheBlocks {
	icb := &IoCacheBlocks{}
	icb.cacheblocks = make([]IoCacheBlockInfo, cachesize)
	icb.size = cachesize
	return icb
}

func (c *IoCacheBlocks) Insert(key string) (evictkey string, newindex uint64, err error) {
	for {
		for ; c.index < c.size; c.index++ {
			if c.cacheblocks[c.index].mru {
				c.cacheblocks[c.index].mru = false
			} else {
				if c.cacheblocks[c.index].used {
					evictkey = c.cacheblocks[c.index].key
				} else {
					evictkey = ""
				}
				newindex = c.index
				err = nil
				c.cacheblocks[c.index].key = key
				c.cacheblocks[c.index].mru = false
				c.cacheblocks[c.index].used = true
				c.index++
				return
			}
		}
		c.index = 0
	}
}

func (c *IoCacheBlocks) Using(index uint64) {
	c.cacheblocks[index].mru = true
}

func (c *IoCacheBlocks) Free(index uint64) {
	c.cacheblocks[index].mru = false
	c.cacheblocks[index].used = false
	c.cacheblocks[index].key = ""
}

/* -------------------------------------------------------- */

type IoCache struct {
	stats        CacheStats
	cachemap     map[string]uint64
	cachesize    uint64
	writethrough bool
	cacheblocks  *IoCacheBlocks
}

func NewIoCache(cachesize uint64, writethrough bool) *IoCache {
	godbc.Require(cachesize > 0)

	cache := &IoCache{}
	cache.cacheblocks = NewIoCacheBlocks(cachesize)
	cache.cachemap = make(map[string]uint64)
	cache.cachesize = cachesize
	cache.writethrough = writethrough

	godbc.Ensure(cache.cachesize > 0)

	return cache
}

func (s *IoCache) Close() {

}

func (c *IoCache) Invalidate(key string) {
	if val, ok := c.cachemap[key]; ok {
		c.stats.writehits++
		c.stats.invalidations++
		c.cacheblocks.Free(val)
		delete(c.cachemap, key)
	}
}

func (c *IoCache) Insert(key string) {
	c.stats.insertions++

	evictkey, index, _ := c.cacheblocks.Insert(key)

	// Check for evictions
	if evictkey != "" {
		c.stats.evictions++
		delete(c.cachemap, evictkey)
	}

	// Insert new key in cache map
	c.cachemap[key] = index
}

func (c *IoCache) Write(obj string, chunk string) {
	c.stats.writes++

	key := obj + chunk

	// Invalidate
	c.Invalidate(key)

	// We would do back end IO here

	// Insert
	if c.writethrough {
		c.Insert(key)
	}
}

func (c *IoCache) Read(obj, chunk string) {
	c.stats.reads++

	key := obj + chunk

	if val, ok := c.cachemap[key]; ok {
		// Read Hit
		c.stats.readhits++

		// Clock Algorithm: Set that we looked
		// at it
		c.cacheblocks.Using(val)
	} else {
		// Read miss
		// We would do IO here
		c.Insert(key)
	}
}

func (c *IoCache) Delete(obj string) {
	// Not supported
}

func (c *IoCache) String() string {
	return fmt.Sprintf(
		"== Cache Information ==\n"+
			"Cache Utilization: %.2f %%\n",
		float64(len(c.cachemap))/float64(c.cachesize)*100.0) +
		c.stats.String()
}

func (c *IoCache) Stats() *CacheStats {
	return c.stats.Copy()
}
<|endoftext|>


<commit_before>package kong

import (
	"fmt"
	"github.com/dghubble/sling"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"net/http"
)

// Route : Kong Route request object structure
type Route struct {
	ID           string   `json:"id,omitempty"`
	Protocols    []string `json:"protocols,omitempty"`
	Methods      []string `json:"methods"`
	Hosts        []string `json:"hosts"`
	Paths        []string `json:"paths"`
	StripPath    bool     `json:"strip_path,omitempty"`
	PreserveHost bool     `json:"preserve_host,omitempty"`
	Service      Service  `json:"service,omitempty"`
}

func resourceKongRoute() *schema.Resource {
	return &schema.Resource{
		Create: resourceKongRouteCreate,
		Read:   resourceKongRouteRead,
		Update: resourceKongRouteUpdate,
		Delete: resourceKongRouteDelete,

		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"protocols": {
				Type:     schema.TypeList,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Optional: true,
				Default:  nil,
				DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
					protocols := convertInterfaceArrToStrings(d.Get("protocols").([]interface{}))

					// TODO: Yeah...
					return len(protocols) == 2 &&
						((protocols[0] == "http" && protocols[1] == "https") ||
							(protocols[0] == "https" && protocols[1] == "http"))
				},
				Description: "A list of the protocols this Route should allow. By default it is [\"http\", \"https\"], which means that the Route accepts both. When set to [\"https\"], HTTP requests are answered with a request to upgrade to HTTPS.",
			},

			"methods": {
				Type:        schema.TypeList,
				Elem:        &schema.Schema{Type: schema.TypeString},
				Optional:    true,
				Default:     nil,
				Description: "A list of HTTP methods that match this Route. For example: [\"GET\", \"POST\"]. At least one of hosts, paths, or methods must be set.",
			},

			"hosts": {
				Type:        schema.TypeList,
				Elem:        &schema.Schema{Type: schema.TypeString},
				Optional:    true,
				Default:     nil,
				Description: "A list of domain names that match this Route. For example: example.com. At least one of hosts, paths, or methods must be set.",
			},

			"paths": {
				Type:        schema.TypeList,
				Elem:        &schema.Schema{Type: schema.TypeString},
				Optional:    true,
				Default:     nil,
				Description: "A list of paths that match this Route. For example: /my-path. At least one of hosts, paths, or methods must be set.",
			},

			"strip_path": {
				Type:        schema.TypeBool,
				Optional:    true,
				Default:     true,
				Description: "When matching a Route via one of the paths, strip the matching prefix from the upstream request URL. Defaults to true.",
			},

			"preserve_host": {
				Type:        schema.TypeBool,
				Optional:    true,
				Default:     false,
				Description: "When matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers. By default set to false, and the upstream Host header will be that of the Service's host.",
			},

			"service": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "The Service this Route is associated to. This is where the Route proxies traffic to.",
			},
		},
	}
}

func resourceKongRouteCreate(d *schema.ResourceData, meta interface{}) error {
	sling := meta.(*sling.Sling)

	route := getRouteFromResourceData(d)

	createdRoute := new(Route)
	response, error := sling.New().BodyJSON(route).Post("routes/").ReceiveSuccess(createdRoute)

	if error != nil {
		return fmt.Errorf("error while creating Route: " + error.Error())
	}

	if response.StatusCode == http.StatusConflict {
		return fmt.Errorf("409 Conflict - use terraform import to manage this route")
	} else if response.StatusCode != http.StatusCreated {
		return fmt.Errorf("unexpected status code received: " + response.Status)
	}

	setRouteToResourceData(d, createdRoute)

	return nil
}

func resourceKongRouteRead(d *schema.ResourceData, meta interface{}) error {
	sling := meta.(*sling.Sling)

	id := d.Id()
	route := new(Route)

	response, error := sling.New().Path("routes/").Get(id).ReceiveSuccess(route)

	if error != nil {
		return fmt.Errorf("error while updating Route" + error.Error())
	}

	if response.StatusCode == http.StatusNotFound {
		d.SetId("")
		return nil
	} else if response.StatusCode != http.StatusOK {
		return fmt.Errorf("unexpected status code received: " + response.Status)
	}

	setRouteToResourceData(d, route)

	return nil
}

func resourceKongRouteUpdate(d *schema.ResourceData, meta interface{}) error {
	sling := meta.(*sling.Sling)

	route := getRouteFromResourceData(d)

	updatedRoute := new(Route)

	response, error := sling.New().BodyJSON(route).Patch("routes/").Path(route.ID).ReceiveSuccess(updatedRoute)

	if error != nil {
		return fmt.Errorf("error while updating Route" + error.Error())
	}

	if response.StatusCode != http.StatusOK {
		return fmt.Errorf("unexpected status code received: " + response.Status)
	}

	setRouteToResourceData(d, updatedRoute)

	return nil
}

func resourceKongRouteDelete(d *schema.ResourceData, meta interface{}) error {
	sling := meta.(*sling.Sling)

	id := d.Id()

	response, error := sling.New().Delete("routes/").Path(id).ReceiveSuccess(nil)
	if error != nil {
		return fmt.Errorf("error while deleting Route" + error.Error())
	}

	if response.StatusCode != http.StatusNoContent {
		return fmt.Errorf("unexpected status code received: " + response.Status)
	}

	return nil
}

func getRouteFromResourceData(d *schema.ResourceData) *Route {
	route := &Route{
		ID:           d.Id(),
		Protocols:    convertInterfaceArrToStrings(d.Get("protocols").([]interface{})),
		Methods:      convertInterfaceArrToStrings(d.Get("methods").([]interface{})),
		Hosts:        convertInterfaceArrToStrings(d.Get("hosts").([]interface{})),
		Paths:        convertInterfaceArrToStrings(d.Get("paths").([]interface{})),
		StripPath:    d.Get("strip_path").(bool),
		PreserveHost: d.Get("preserve_host").(bool),
		Service: Service{
			ID: d.Get("service").(string),
		},
	}

	return route
}

func setRouteToResourceData(d *schema.ResourceData, route *Route) {
	d.SetId(route.ID)
	d.Set("protocols", route.Protocols)
	d.Set("methods", route.Methods)
	d.Set("hosts", route.Hosts)
	d.Set("paths", route.Paths)
	d.Set("strip_path", route.StripPath)
	d.Set("preserve_host", route.PreserveHost)
	d.Set("service", route.Service.ID)
}

func convertInterfaceArrToStrings(strs []interface{}) []string {
	arr := make([]string, len(strs))
	for i, str := range strs {
		arr[i] = str.(string)
	}
	return arr
}
<commit_msg>add headers parameter to route object<commit_after>package kong

import (
	"fmt"
	"net/http"

	"github.com/dghubble/sling"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

// Route : Kong Route request object structure
type Route struct {
	ID           string              `json:"id,omitempty"`
	Protocols    []string            `json:"protocols,omitempty"`
	Methods      []string            `json:"methods"`
	Hosts        []string            `json:"hosts"`
	Paths        []string            `json:"paths"`
	StripPath    bool                `json:"strip_path,omitempty"`
	PreserveHost bool                `json:"preserve_host,omitempty"`
	Headers      map[string][]string `json:"headers,omitempty"`
	Service      Service             `json:"service,omitempty"`
}

func resourceKongRoute() *schema.Resource {
	return &schema.Resource{
		Create: resourceKongRouteCreate,
		Read:   resourceKongRouteRead,
		Update: resourceKongRouteUpdate,
		Delete: resourceKongRouteDelete,

		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"protocols": {
				Type:     schema.TypeList,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Optional: true,
				Default:  nil,
				DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
					protocols := convertInterfaceArrToStrings(d.Get("protocols").([]interface{}))

					// TODO: Yeah...
					return len(protocols) == 2 &&
						((protocols[0] == "http" && protocols[1] == "https") ||
							(protocols[0] == "https" && protocols[1] == "http"))
				},
				Description: "A list of the protocols this Route should allow. By default it is [\"http\", \"https\"], which means that the Route accepts both. When set to [\"https\"], HTTP requests are answered with a request to upgrade to HTTPS.",
			},

			"methods": {
				Type:        schema.TypeList,
				Elem:        &schema.Schema{Type: schema.TypeString},
				Optional:    true,
				Default:     nil,
				Description: "A list of HTTP methods that match this Route. For example: [\"GET\", \"POST\"]. At least one of hosts, paths, or methods must be set.",
			},

			"hosts": {
				Type:        schema.TypeList,
				Elem:        &schema.Schema{Type: schema.TypeString},
				Optional:    true,
				Default:     nil,
				Description: "A list of domain names that match this Route. For example: example.com. At least one of hosts, paths, or methods must be set.",
			},

			"paths": {
				Type:        schema.TypeList,
				Elem:        &schema.Schema{Type: schema.TypeString},
				Optional:    true,
				Default:     nil,
				Description: "A list of paths that match this Route. For example: /my-path. At least one of hosts, paths, or methods must be set.",
			},

			"strip_path": {
				Type:        schema.TypeBool,
				Optional:    true,
				Default:     true,
				Description: "When matching a Route via one of the paths, strip the matching prefix from the upstream request URL. Defaults to true.",
			},

			"preserve_host": {
				Type:        schema.TypeBool,
				Optional:    true,
				Default:     false,
				Description: "When matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers. By default set to false, and the upstream Host header will be that of the Service's host.",
			},

			"service": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "The Service this Route is associated to. This is where the Route proxies traffic to.",
			},
			"header": {
				Type:     schema.TypeSet,
				Optional: true,
				ForceNew: false,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"name": {
							Type:     schema.TypeString,
							Required: true,
						},
						"values": {
							Type:     schema.TypeList,
							Required: true,
							Elem: &schema.Schema{
								Type: schema.TypeString,
							},
						},
					},
				},
				Description: "One or more lists of values indexed by header name that will cause this Route to match if present in the request.",
			},
		},
	}
}

func resourceKongRouteCreate(d *schema.ResourceData, meta interface{}) error {
	sling := meta.(*sling.Sling)

	route := getRouteFromResourceData(d)

	createdRoute := new(Route)
	response, error := sling.New().BodyJSON(route).Post("routes/").ReceiveSuccess(createdRoute)

	if error != nil {
		return fmt.Errorf("error while creating Route: " + error.Error())
	}

	if response.StatusCode == http.StatusConflict {
		return fmt.Errorf("409 Conflict - use terraform import to manage this route")
	} else if response.StatusCode != http.StatusCreated {
		return fmt.Errorf("unexpected status code received: " + response.Status)
	}

	setRouteToResourceData(d, createdRoute)

	return nil
}

func resourceKongRouteRead(d *schema.ResourceData, meta interface{}) error {
	sling := meta.(*sling.Sling)

	id := d.Id()
	route := new(Route)

	response, error := sling.New().Path("routes/").Get(id).ReceiveSuccess(route)

	if error != nil {
		return fmt.Errorf("error while updating Route" + error.Error())
	}

	if response.StatusCode == http.StatusNotFound {
		d.SetId("")
		return nil
	} else if response.StatusCode != http.StatusOK {
		return fmt.Errorf("unexpected status code received: " + response.Status)
	}

	setRouteToResourceData(d, route)

	return nil
}

func resourceKongRouteUpdate(d *schema.ResourceData, meta interface{}) error {
	sling := meta.(*sling.Sling)

	route := getRouteFromResourceData(d)

	updatedRoute := new(Route)

	response, error := sling.New().BodyJSON(route).Patch("routes/").Path(route.ID).ReceiveSuccess(updatedRoute)

	if error != nil {
		return fmt.Errorf("error while updating Route" + error.Error())
	}

	if response.StatusCode != http.StatusOK {
		return fmt.Errorf("unexpected status code received: " + response.Status)
	}

	setRouteToResourceData(d, updatedRoute)

	return nil
}

func resourceKongRouteDelete(d *schema.ResourceData, meta interface{}) error {
	sling := meta.(*sling.Sling)

	id := d.Id()

	response, error := sling.New().Delete("routes/").Path(id).ReceiveSuccess(nil)
	if error != nil {
		return fmt.Errorf("error while deleting Route" + error.Error())
	}

	if response.StatusCode != http.StatusNoContent {
		return fmt.Errorf("unexpected status code received: " + response.Status)
	}

	return nil
}

func getRouteFromResourceData(d *schema.ResourceData) *Route {
	route := &Route{
		ID:           d.Id(),
		Protocols:    convertInterfaceArrToStrings(d.Get("protocols").([]interface{})),
		Methods:      convertInterfaceArrToStrings(d.Get("methods").([]interface{})),
		Hosts:        convertInterfaceArrToStrings(d.Get("hosts").([]interface{})),
		Paths:        convertInterfaceArrToStrings(d.Get("paths").([]interface{})),
		StripPath:    d.Get("strip_path").(bool),
		PreserveHost: d.Get("preserve_host").(bool),
		Headers:      readMapStringArrayFromResource(d, "header"),
		Service: Service{
			ID: d.Get("service").(string),
		},
	}

	return route
}

func setRouteToResourceData(d *schema.ResourceData, route *Route) {
	d.SetId(route.ID)
	d.Set("protocols", route.Protocols)
	d.Set("methods", route.Methods)
	d.Set("hosts", route.Hosts)
	d.Set("paths", route.Paths)
	d.Set("strip_path", route.StripPath)
	d.Set("preserve_host", route.PreserveHost)
	d.Set("service", route.Service.ID)
}

func convertInterfaceArrToStrings(strs []interface{}) []string {
	arr := make([]string, len(strs))
	for i, str := range strs {
		arr[i] = str.(string)
	}
	return arr
}

func readMapStringArrayFromResource(d *schema.ResourceData, key string) map[string][]string {
	results := map[string][]string{}
	if attr, ok := d.GetOk(key); ok {
		set := attr.(*schema.Set)
		for _, item := range set.List() {
			m := item.(map[string]interface{})
			if name, ok := m["name"].(string); ok {
				if values, ok := m["values"].([]interface{}); ok {
					var vals []string
					for _, v := range values {
						vals = append(vals, v.(string))
					}
					results[name] = vals
				}
			}
		}
	}

	return results
}
<|endoftext|>


<commit_before>package pigae

import (
	"fmt"
	"net/http"

	. "github.com/Deleplace/programming-idioms/pig"
	"github.com/gorilla/mux"

	"appengine"
)

func randomIdiom(w http.ResponseWriter, r *http.Request) error {
	c := appengine.NewContext(r)
	vars := mux.Vars(r)
	havingLang := vars["havingLang"]
	notHavingLang := vars["notHavingLang"]
	if havingLang != "" && notHavingLang != "" {
		return fmt.Errorf("Can't have both filters:", havingLang, notHavingLang)
	}

	var idiom *Idiom
	var err error

	switch {
	case havingLang != "":
		havingLang = normLang(havingLang)
		c.Infof("Going to a random idiom having lang %v", havingLang)
		_, idiom, err = dao.randomIdiomHaving(c, havingLang)
	case notHavingLang != "":
		notHavingLang = normLang(notHavingLang)
		c.Infof("Going to a random idiom not having lang %v", notHavingLang)
		_, idiom, err = dao.randomIdiomNotHaving(c, notHavingLang)
	default:
		_, idiom, err = dao.randomIdiom(c)
	}

	if err != nil {
		return err
	}

	c.Infof("Picked idiom #%v: %v", idiom.Id, idiom.Title)
	http.Redirect(w, r, NiceIdiomURL(idiom), http.StatusFound)
	return nil
}
<commit_msg>random-idiom/having/{lang} -> redirect to specific impl in {lang}.<commit_after>package pigae

import (
	"fmt"
	"net/http"

	. "github.com/Deleplace/programming-idioms/pig"
	"github.com/gorilla/mux"

	"appengine"
)

func randomIdiom(w http.ResponseWriter, r *http.Request) error {
	c := appengine.NewContext(r)
	vars := mux.Vars(r)
	havingLang := vars["havingLang"]
	notHavingLang := vars["notHavingLang"]
	if havingLang != "" && notHavingLang != "" {
		return fmt.Errorf("Can't have both filters:", havingLang, notHavingLang)
	}

	var idiom *Idiom
	var url string
	var err error

	switch {
	case havingLang != "":
		havingLang = normLang(havingLang)
		c.Infof("Going to a random idiom having lang %v", havingLang)
		_, idiom, err = dao.randomIdiomHaving(c, havingLang)
		url = NiceIdiomURL(idiom)
		for _, impl := range idiom.Implementations {
			if impl.LanguageName == havingLang {
				url = NiceImplURL(idiom, impl.Id, havingLang)
			}
		}
	case notHavingLang != "":
		notHavingLang = normLang(notHavingLang)
		c.Infof("Going to a random idiom not having lang %v", notHavingLang)
		_, idiom, err = dao.randomIdiomNotHaving(c, notHavingLang)
		url = NiceIdiomURL(idiom)
	default:
		_, idiom, err = dao.randomIdiom(c)
		url = NiceIdiomURL(idiom)
	}

	if err != nil {
		return err
	}

	c.Infof("Picked idiom #%v: %v", idiom.Id, idiom.Title)
	http.Redirect(w, r, url, http.StatusFound)
	return nil
}
<|endoftext|>


<commit_before>package core

import (
	"context"
	"database/sql"
	"fmt"
	"math"
	"time"

	"chain/core/query"
	"chain/database/pg"
	"chain/errors"
	"chain/metrics"
	"chain/net/http/httpjson"
)

type Cursor struct {
	ID     string `json:"id,omitempty"`
	Alias  string `json:"alias,omitempty"`
	Filter string `json:"filter,omitempty"`
	After  string `json:"after,omitempty"`
	Order  string `json:"order,omitempty"`
}

// POST /create-cursor
func (a *api) createCursor(ctx context.Context, in struct {
	Alias  string
	Filter string

	// ClientToken is the application's unique token for the cursor. Every cursor
	// should have a unique client token. The client token is used to ensure
	// idempotency of create cursor requests. Duplicate create cursor requests
	// with the same client_token will only create one cursor.
	ClientToken *string `json:"client_token"`
}) (*Cursor, error) {
	defer metrics.RecordElapsed(time.Now())

	after := fmt.Sprintf("%x:%x-%x", a.c.Height(), math.MaxUint32, uint64(math.MaxUint64))
	cur := &Cursor{
		Alias:  in.Alias,
		Filter: in.Filter,
		After:  after,
	}

	return insertCursor(ctx, cur, in.ClientToken)
}

// insertCursor adds the cursor to the database. If the cursor has a client token,
// and there already exists a cursor with that client token, insertCursor will
// lookup and return the existing cursor instead.
func insertCursor(ctx context.Context, cur *Cursor, clientToken *string) (*Cursor, error) {
	const q = `
		INSERT INTO cursors (alias, filter, after, is_ascending, client_token)
		VALUES ($1, $2, $3, $4, $5)
		ON CONFLICT (client_token) DO NOTHING
		RETURNING id
	`

	isAscending := cur.Order == "asc"

	err := pg.QueryRow(
		ctx, q, cur.Alias, cur.Filter, cur.After,
		isAscending, clientToken).Scan(&cur.ID)

	if pg.IsUniqueViolation(err) {
		return nil, errors.WithDetail(httpjson.ErrBadRequest, "non-unique alias")
	} else if err == sql.ErrNoRows && clientToken != nil {
		// There is already a cursor with the provided client
		// token. We should return the existing cursor
		cur, err = cursorByClientToken(ctx, *clientToken)
		if err != nil {
			return nil, errors.Wrap(err, "retrieving existing cursor")
		}
	} else if err != nil {
		return nil, err
	}

	return cur, nil
}

func cursorByClientToken(ctx context.Context, clientToken string) (*Cursor, error) {
	const q = `
		SELECT id, alias, filter, after, is_ascending
		FROM cursors
		WHERE client_token=$1
	`

	var (
		cur         Cursor
		isAscending bool
	)
	err := pg.QueryRow(ctx, q, clientToken).Scan(&cur.ID, &cur.Alias, &cur.Filter, &cur.After, &isAscending)
	if err != nil {
		return nil, err
	}

	if isAscending {
		cur.Order = "asc"
	} else {
		cur.Order = "desc"
	}

	return &cur, nil
}

// POST /get-cursor
func getCursor(ctx context.Context, in struct {
	ID    string `json:"id,omitempty"`
	Alias string `json:"alias,omitempty"`
}) (*Cursor, error) {
	defer metrics.RecordElapsed(time.Now())

	where := ` WHERE `
	id := in.ID
	if in.ID != "" {
		where += `id=$1`
	} else {
		where += `alias=$1`
		id = in.Alias
	}

	q := `
		SELECT id, alias, filter, after, is_ascending
		FROM cursors
	` + where

	var (
		cur         Cursor
		isAscending bool
	)

	err := pg.QueryRow(ctx, q, id).Scan(&cur.ID, &cur.Alias, &cur.Filter, &cur.After, &isAscending)
	if err != nil {
		return nil, err
	}

	if isAscending {
		cur.Order = "asc"
	} else {
		cur.Order = "desc"
	}

	return &cur, nil
}

// POST /update-cursor
func updateCursor(ctx context.Context, in struct {
	ID    string `json:"id,omitempty"`
	Alias string `json:"alias,omitempty"`
	Prev  string `json:"prev"`
	After string `json:"after"`
}) (*Cursor, error) {
	defer metrics.RecordElapsed(time.Now())

	bad, err := isBefore(in.After, in.Prev)
	if err != nil {
		return nil, err
	}

	if bad {
		return nil, errors.WithDetail(httpjson.ErrBadRequest, "new After cannot be before Prev")
	}

	where := ` WHERE `
	id := in.ID
	if in.ID != "" {
		where += `id=$2`
	} else {
		where += `alias=$2`
		id = in.Alias
	}

	q := `
		UPDATE cursors SET after=$1
	` + where + ` AND after=$3`

	res, err := pg.Exec(ctx, q, in.After, id, in.Prev)
	if err != nil {
		return nil, err
	}

	affected, err := res.RowsAffected()
	if err != nil {
		return nil, err
	}

	if affected == 0 {
		return nil, errors.WithDetailf(errNotFound, "could not find cursor with id/alias=%s and prev=%s", id, in.Prev)
	}

	return &Cursor{
		ID:    in.ID,
		Alias: in.Alias,
		After: in.After,
	}, nil
}

// isBefore returns true if a is before b. It returns an error if either
// a or b are not valid query.TxAfters.
func isBefore(a, b string) (bool, error) {
	aAfter, err := query.DecodeTxAfter(a)
	if err != nil {
		return false, err
	}

	bAfter, err := query.DecodeTxAfter(b)
	if err != nil {
		return false, err
	}

	return aAfter.FromBlockHeight < bAfter.FromBlockHeight ||
		(aAfter.FromBlockHeight == bAfter.FromBlockHeight &&
			aAfter.FromPosition < bAfter.FromPosition), nil
}
<commit_msg>core: more conservative cursor bounds<commit_after>package core

import (
	"context"
	"database/sql"
	"fmt"
	"math"
	"time"

	"chain/core/query"
	"chain/database/pg"
	"chain/errors"
	"chain/metrics"
	"chain/net/http/httpjson"
)

type Cursor struct {
	ID     string `json:"id,omitempty"`
	Alias  string `json:"alias,omitempty"`
	Filter string `json:"filter,omitempty"`
	After  string `json:"after,omitempty"`
	Order  string `json:"order,omitempty"`
}

// POST /create-cursor
func (a *api) createCursor(ctx context.Context, in struct {
	Alias  string
	Filter string

	// ClientToken is the application's unique token for the cursor. Every cursor
	// should have a unique client token. The client token is used to ensure
	// idempotency of create cursor requests. Duplicate create cursor requests
	// with the same client_token will only create one cursor.
	ClientToken *string `json:"client_token"`
}) (*Cursor, error) {
	defer metrics.RecordElapsed(time.Now())

	after := fmt.Sprintf("%x:%x-%x", a.c.Height(), math.MaxInt32, uint64(math.MaxInt64))
	cur := &Cursor{
		Alias:  in.Alias,
		Filter: in.Filter,
		After:  after,
	}

	return insertCursor(ctx, cur, in.ClientToken)
}

// insertCursor adds the cursor to the database. If the cursor has a client token,
// and there already exists a cursor with that client token, insertCursor will
// lookup and return the existing cursor instead.
func insertCursor(ctx context.Context, cur *Cursor, clientToken *string) (*Cursor, error) {
	const q = `
		INSERT INTO cursors (alias, filter, after, is_ascending, client_token)
		VALUES ($1, $2, $3, $4, $5)
		ON CONFLICT (client_token) DO NOTHING
		RETURNING id
	`

	isAscending := cur.Order == "asc"

	err := pg.QueryRow(
		ctx, q, cur.Alias, cur.Filter, cur.After,
		isAscending, clientToken).Scan(&cur.ID)

	if pg.IsUniqueViolation(err) {
		return nil, errors.WithDetail(httpjson.ErrBadRequest, "non-unique alias")
	} else if err == sql.ErrNoRows && clientToken != nil {
		// There is already a cursor with the provided client
		// token. We should return the existing cursor
		cur, err = cursorByClientToken(ctx, *clientToken)
		if err != nil {
			return nil, errors.Wrap(err, "retrieving existing cursor")
		}
	} else if err != nil {
		return nil, err
	}

	return cur, nil
}

func cursorByClientToken(ctx context.Context, clientToken string) (*Cursor, error) {
	const q = `
		SELECT id, alias, filter, after, is_ascending
		FROM cursors
		WHERE client_token=$1
	`

	var (
		cur         Cursor
		isAscending bool
	)
	err := pg.QueryRow(ctx, q, clientToken).Scan(&cur.ID, &cur.Alias, &cur.Filter, &cur.After, &isAscending)
	if err != nil {
		return nil, err
	}

	if isAscending {
		cur.Order = "asc"
	} else {
		cur.Order = "desc"
	}

	return &cur, nil
}

// POST /get-cursor
func getCursor(ctx context.Context, in struct {
	ID    string `json:"id,omitempty"`
	Alias string `json:"alias,omitempty"`
}) (*Cursor, error) {
	defer metrics.RecordElapsed(time.Now())

	where := ` WHERE `
	id := in.ID
	if in.ID != "" {
		where += `id=$1`
	} else {
		where += `alias=$1`
		id = in.Alias
	}

	q := `
		SELECT id, alias, filter, after, is_ascending
		FROM cursors
	` + where

	var (
		cur         Cursor
		isAscending bool
	)

	err := pg.QueryRow(ctx, q, id).Scan(&cur.ID, &cur.Alias, &cur.Filter, &cur.After, &isAscending)
	if err != nil {
		return nil, err
	}

	if isAscending {
		cur.Order = "asc"
	} else {
		cur.Order = "desc"
	}

	return &cur, nil
}

// POST /update-cursor
func updateCursor(ctx context.Context, in struct {
	ID    string `json:"id,omitempty"`
	Alias string `json:"alias,omitempty"`
	Prev  string `json:"prev"`
	After string `json:"after"`
}) (*Cursor, error) {
	defer metrics.RecordElapsed(time.Now())

	bad, err := isBefore(in.After, in.Prev)
	if err != nil {
		return nil, err
	}

	if bad {
		return nil, errors.WithDetail(httpjson.ErrBadRequest, "new After cannot be before Prev")
	}

	where := ` WHERE `
	id := in.ID
	if in.ID != "" {
		where += `id=$2`
	} else {
		where += `alias=$2`
		id = in.Alias
	}

	q := `
		UPDATE cursors SET after=$1
	` + where + ` AND after=$3`

	res, err := pg.Exec(ctx, q, in.After, id, in.Prev)
	if err != nil {
		return nil, err
	}

	affected, err := res.RowsAffected()
	if err != nil {
		return nil, err
	}

	if affected == 0 {
		return nil, errors.WithDetailf(errNotFound, "could not find cursor with id/alias=%s and prev=%s", id, in.Prev)
	}

	return &Cursor{
		ID:    in.ID,
		Alias: in.Alias,
		After: in.After,
	}, nil
}

// isBefore returns true if a is before b. It returns an error if either
// a or b are not valid query.TxAfters.
func isBefore(a, b string) (bool, error) {
	aAfter, err := query.DecodeTxAfter(a)
	if err != nil {
		return false, err
	}

	bAfter, err := query.DecodeTxAfter(b)
	if err != nil {
		return false, err
	}

	return aAfter.FromBlockHeight < bAfter.FromBlockHeight ||
		(aAfter.FromBlockHeight == bAfter.FromBlockHeight &&
			aAfter.FromPosition < bAfter.FromPosition), nil
}
<|endoftext|>


<commit_before>package gorm

import (
	"errors"
	"fmt"
	"reflect"
)

// Define callbacks for querying
func init() {
	defaultCallback.Query().Register("gorm:query", queryCallback)
	defaultCallback.Query().Register("gorm:preload", preloadCallback)
	defaultCallback.Query().Register("gorm:after_query", afterQueryCallback)
}

// queryCallback used to query data from database
func queryCallback(scope *Scope) {
	defer scope.trace(NowFunc())

	var (
		isSlice    bool
		isPtr      bool
		results    = scope.IndirectValue()
		resultType reflect.Type
	)

	if orderBy, ok := scope.Get("gorm:order_by_primary_key"); ok {
		if primaryField := scope.PrimaryField(); primaryField != nil {
			scope.Search.Order(fmt.Sprintf("%v.%v %v", scope.QuotedTableName(), scope.Quote(primaryField.DBName), orderBy))
		}
	}

	if value, ok := scope.Get("gorm:query_destination"); ok {
		results = reflect.Indirect(reflect.ValueOf(value))
	}

	if kind := results.Kind(); kind == reflect.Slice {
		isSlice = true
		resultType = results.Type().Elem()
		results.Set(reflect.MakeSlice(results.Type(), 0, 0))

		if resultType.Kind() == reflect.Ptr {
			isPtr = true
			resultType = resultType.Elem()
		}
	} else if kind != reflect.Struct {
		scope.Err(errors.New("unsupported destination, should be slice or struct"))
		return
	}

	scope.prepareQuerySql()

	if !scope.HasError() {
		var extraOption string
		if str, ok := scope.Get("gorm:query_option"); ok {
			extraOption = fmt.Sprint(str)
		}
		scope.db.RowsAffected = 0

		if rows, err := scope.SqlDB().Query(scope.Sql+addExtraSpaceIfExist(extraOption), scope.SqlVars...); scope.Err(err) == nil {
			defer rows.Close()

			columns, _ := rows.Columns()
			for rows.Next() {
				scope.db.RowsAffected++

				elem := results
				if isSlice {
					elem = reflect.New(resultType).Elem()
				}

				scope.scan(rows, columns, scope.New(elem.Addr().Interface()).Fields())

				if isSlice {
					if isPtr {
						results.Set(reflect.Append(results, elem.Addr()))
					} else {
						results.Set(reflect.Append(results, elem))
					}
				}
			}

			if scope.db.RowsAffected == 0 && !isSlice {
				scope.Err(RecordNotFound)
			}
		}
	}
}

// afterQueryCallback will invoke `AfterFind` method after querying
func afterQueryCallback(scope *Scope) {
	if !scope.HasError() {
		scope.CallMethod("AfterFind")
	}
}
<commit_msg>Fix query with extra option<commit_after>package gorm

import (
	"errors"
	"fmt"
	"reflect"
)

// Define callbacks for querying
func init() {
	defaultCallback.Query().Register("gorm:query", queryCallback)
	defaultCallback.Query().Register("gorm:preload", preloadCallback)
	defaultCallback.Query().Register("gorm:after_query", afterQueryCallback)
}

// queryCallback used to query data from database
func queryCallback(scope *Scope) {
	defer scope.trace(NowFunc())

	var (
		isSlice    bool
		isPtr      bool
		results    = scope.IndirectValue()
		resultType reflect.Type
	)

	if orderBy, ok := scope.Get("gorm:order_by_primary_key"); ok {
		if primaryField := scope.PrimaryField(); primaryField != nil {
			scope.Search.Order(fmt.Sprintf("%v.%v %v", scope.QuotedTableName(), scope.Quote(primaryField.DBName), orderBy))
		}
	}

	if value, ok := scope.Get("gorm:query_destination"); ok {
		results = reflect.Indirect(reflect.ValueOf(value))
	}

	if kind := results.Kind(); kind == reflect.Slice {
		isSlice = true
		resultType = results.Type().Elem()
		results.Set(reflect.MakeSlice(results.Type(), 0, 0))

		if resultType.Kind() == reflect.Ptr {
			isPtr = true
			resultType = resultType.Elem()
		}
	} else if kind != reflect.Struct {
		scope.Err(errors.New("unsupported destination, should be slice or struct"))
		return
	}

	scope.prepareQuerySql()

	if !scope.HasError() {
		scope.db.RowsAffected = 0
		if str, ok := scope.Get("gorm:query_option"); ok {
			scope.Sql += addExtraSpaceIfExist(fmt.Sprint(str))
		}

		if rows, err := scope.SqlDB().Query(scope.Sql, scope.SqlVars...); scope.Err(err) == nil {
			defer rows.Close()

			columns, _ := rows.Columns()
			for rows.Next() {
				scope.db.RowsAffected++

				elem := results
				if isSlice {
					elem = reflect.New(resultType).Elem()
				}

				scope.scan(rows, columns, scope.New(elem.Addr().Interface()).Fields())

				if isSlice {
					if isPtr {
						results.Set(reflect.Append(results, elem.Addr()))
					} else {
						results.Set(reflect.Append(results, elem))
					}
				}
			}

			if scope.db.RowsAffected == 0 && !isSlice {
				scope.Err(RecordNotFound)
			}
		}
	}
}

// afterQueryCallback will invoke `AfterFind` method after querying
func afterQueryCallback(scope *Scope) {
	if !scope.HasError() {
		scope.CallMethod("AfterFind")
	}
}
<|endoftext|>


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

package testlapack

import (
	"fmt"
	"testing"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/floats"
)

type Dorg2rer interface {
	Dgeqrfer
	Dorg2r(m, n, k int, a []float64, lda int, tau []float64, work []float64)
}

func Dorg2rTest(t *testing.T, impl Dorg2rer) {
	rnd := rand.New(rand.NewSource(1))
	for _, test := range []struct {
		m, n, k, lda int
	}{
		{3, 3, 0, 0},
		{4, 3, 0, 0},
		{3, 3, 2, 0},
		{4, 3, 2, 0},

		{5, 5, 0, 20},
		{5, 5, 3, 20},
		{10, 5, 0, 20},
		{10, 5, 2, 20},
	} {
		m := test.m
		n := test.n
		lda := test.lda
		if lda == 0 {
			lda = test.n
		}
		a := make([]float64, m*lda)
		for i := range a {
			a[i] = rnd.NormFloat64()
		}
		k := min(m, n)
		tau := make([]float64, k)
		work := make([]float64, 1)
		impl.Dgeqrf(m, n, a, lda, tau, work, -1)
		work = make([]float64, int(work[0]))
		impl.Dgeqrf(m, n, a, lda, tau, work, len(work))

		k = test.k
		if k == 0 {
			k = n
		}
		q := constructQK("QR", m, n, k, a, lda, tau)

		impl.Dorg2r(m, n, k, a, lda, tau, work)

		// Check that the first n columns match.
		same := true
		for i := 0; i < m; i++ {
			for j := 0; j < n; j++ {
				if !floats.EqualWithinAbsOrRel(q.Data[i*q.Stride+j], a[i*lda+j], 1e-12, 1e-12) {
					same = false
					break
				}
			}
		}
		if !same {
			fmt.Println()
			fmt.Println("a =")
			printRowise(a, m, n, lda, false)
			fmt.Println("q =")
			printRowise(q.Data, q.Rows, q.Cols, q.Stride, false)
			t.Errorf("Q mismatch")
		}
	}
}
<commit_msg>lapack/testlapack: add implementation comments to Dorg2r test<commit_after>// Copyright ©2015 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package testlapack

import (
	"testing"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/floats"
)

type Dorg2rer interface {
	Dgeqrfer
	Dorg2r(m, n, k int, a []float64, lda int, tau []float64, work []float64)
}

func Dorg2rTest(t *testing.T, impl Dorg2rer) {
	rnd := rand.New(rand.NewSource(1))
	for ti, test := range []struct {
		m, n, k, lda int
	}{
		{3, 3, 0, 0},
		{4, 3, 0, 0},
		{3, 3, 2, 0},
		{4, 3, 2, 0},

		{5, 5, 0, 20},
		{5, 5, 3, 20},
		{10, 5, 0, 20},
		{10, 5, 2, 20},
	} {
		m := test.m
		n := test.n
		lda := test.lda
		if lda == 0 {
			lda = test.n
		}
		// Allocate m×n matrix A and fill it with random numbers.
		a := make([]float64, m*lda)
		for i := range a {
			a[i] = rnd.NormFloat64()
		}

		// Compute the QR decomposition of A.
		tau := make([]float64, min(m, n))
		work := make([]float64, 1)
		impl.Dgeqrf(m, n, a, lda, tau, work, -1)
		work = make([]float64, int(work[0]))
		impl.Dgeqrf(m, n, a, lda, tau, work, len(work))

		// Compute the matrix Q explicitly using the first k elementary reflectors.
		k := test.k
		if k == 0 {
			k = n
		}
		q := constructQK("QR", m, n, k, a, lda, tau)

		// Compute the matrix Q using Dorg2r.
		impl.Dorg2r(m, n, k, a, lda, tau, work)

		// Check that the first n columns of both results match.
		same := true
	loop:
		for i := 0; i < m; i++ {
			for j := 0; j < n; j++ {
				if !floats.EqualWithinAbsOrRel(q.Data[i*q.Stride+j], a[i*lda+j], 1e-12, 1e-12) {
					same = false
					break loop
				}
			}
		}
		if !same {
			t.Errorf("Case %v: Q mismatch", ti)
		}
	}
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package js

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/GeertJohan/go.rice"
	log "github.com/Sirupsen/logrus"
	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/stats"
	"github.com/robertkrimen/otto"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

const wrapper = "(function() { var e = {}; (function(exports) {%s\n})(e); return e; })();"

var (
	libBox      = rice.MustFindBox("lib")
	polyfillBox = rice.MustFindBox("node_modules/babel-polyfill")
)

type Runtime struct {
	VM      *otto.Otto
	Root    string
	Exports map[string]otto.Value
	Metrics map[string]*stats.Metric
	Options lib.Options

	lib map[string]otto.Value
}

func New() (*Runtime, error) {
	wd, err := os.Getwd()
	if err != nil {
		return nil, err
	}

	rt := &Runtime{
		VM:      otto.New(),
		Root:    wd,
		Exports: make(map[string]otto.Value),
		Metrics: make(map[string]*stats.Metric),
		lib:     make(map[string]otto.Value),
	}

	polyfillJS, err := polyfillBox.String("dist/polyfill.js")
	if err != nil {
		return nil, err
	}
	polyfill, err := rt.VM.Compile("polyfill.js", polyfillJS)
	if err != nil {
		return nil, err
	}
	if _, err := rt.VM.Run(polyfill); err != nil {
		return nil, err
	}

	if _, err := rt.loadLib("_global.js"); err != nil {
		return nil, err
	}

	return rt, nil
}

func (r *Runtime) Load(filename string) (otto.Value, error) {
	if err := r.VM.Set("__initapi__", InitAPI{r: r}); err != nil {
		return otto.UndefinedValue(), err
	}
	exp, err := r.loadFile(filename)
	if err := r.VM.Set("__initapi__", nil); err != nil {
		return otto.UndefinedValue(), err
	}
	return exp, err
}

func (r *Runtime) extractOptions(exports otto.Value, opts *lib.Options) error {
	expObj := exports.Object()
	if expObj == nil {
		return nil
	}

	v, err := expObj.Get("options")
	if err != nil {
		return err
	}
	ev, err := v.Export()
	if err != nil {
		return err
	}

	data, err := json.Marshal(ev)
	if err != nil {
		return err
	}
	if err := json.Unmarshal(data, opts); err != nil {
		return err
	}

	return nil
}

func (r *Runtime) loadFile(filename string) (otto.Value, error) {
	// To protect against directory traversal, prevent loading of files outside the root (pwd) dir
	path, err := filepath.Abs(filename)
	if err != nil {
		return otto.UndefinedValue(), err
	}
	if !strings.HasPrefix(path, r.Root) {
		return otto.UndefinedValue(), DirectoryTraversalError{Filename: filename, Root: r.Root}
	}

	// Don't re-compile repeated includes of the same module
	if exports, ok := r.Exports[path]; ok {
		return exports, nil
	}

	data, err := ioutil.ReadFile(path)
	if err != nil {
		return otto.UndefinedValue(), err
	}
	exports, err := r.load(path, data)
	if err != nil {
		return otto.UndefinedValue(), err
	}
	r.Exports[path] = exports

	log.WithField("path", path).Debug("File loaded")

	return exports, nil
}

func (r *Runtime) loadLib(filename string) (otto.Value, error) {
	if exports, ok := r.lib[filename]; ok {
		return exports, nil
	}

	data, err := libBox.Bytes(filename)
	if err != nil {
		return otto.UndefinedValue(), err
	}
	exports, err := r.load(filename, data)
	if err != nil {
		return otto.UndefinedValue(), err
	}
	r.lib[filename] = exports

	log.WithField("filename", filename).Debug("Library loaded")

	return exports, nil
}

func (r *Runtime) load(filename string, data []byte) (otto.Value, error) {
	// Compile the file with Babel; this subprocess invocation is TEMPORARY:
	// https://github.com/robertkrimen/otto/pull/205
	cmd := exec.Command(babel, "--presets", "latest", "--no-babelrc")
	cmd.Dir = babelDir
	cmd.Stdin = bytes.NewReader(data)
	cmd.Stderr = os.Stderr
	src, err := cmd.Output()
	if err != nil {
		return otto.UndefinedValue(), err
	}

	// Use a wrapper function to turn the script into an exported module
	s, err := r.VM.Compile(filename, fmt.Sprintf(wrapper, string(src)))
	if err != nil {
		return otto.UndefinedValue(), err
	}
	exports, err := r.VM.Run(s)
	if err != nil {
		return otto.UndefinedValue(), err
	}

	// Extract script-defined options.
	var opts lib.Options
	if err := r.extractOptions(exports, &opts); err != nil {
		return exports, err
	}
	r.Options = r.Options.Apply(opts)

	return exports, nil
}
<commit_msg>[feat] Try node, nodejs and node.exe<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package js

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/GeertJohan/go.rice"
	log "github.com/Sirupsen/logrus"
	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/stats"
	"github.com/pkg/errors"
	"github.com/robertkrimen/otto"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

const wrapper = "(function() { var e = {}; (function(exports) {%s\n})(e); return e; })();"

var (
	libBox      = rice.MustFindBox("lib")
	polyfillBox = rice.MustFindBox("node_modules/babel-polyfill")
)

type Runtime struct {
	VM      *otto.Otto
	Root    string
	Exports map[string]otto.Value
	Metrics map[string]*stats.Metric
	Options lib.Options

	lib map[string]otto.Value
}

func New() (*Runtime, error) {
	wd, err := os.Getwd()
	if err != nil {
		return nil, err
	}

	rt := &Runtime{
		VM:      otto.New(),
		Root:    wd,
		Exports: make(map[string]otto.Value),
		Metrics: make(map[string]*stats.Metric),
		lib:     make(map[string]otto.Value),
	}

	polyfillJS, err := polyfillBox.String("dist/polyfill.js")
	if err != nil {
		return nil, err
	}
	polyfill, err := rt.VM.Compile("polyfill.js", polyfillJS)
	if err != nil {
		return nil, err
	}
	if _, err := rt.VM.Run(polyfill); err != nil {
		return nil, err
	}

	if _, err := rt.loadLib("_global.js"); err != nil {
		return nil, err
	}

	return rt, nil
}

func (r *Runtime) Load(filename string) (otto.Value, error) {
	if err := r.VM.Set("__initapi__", InitAPI{r: r}); err != nil {
		return otto.UndefinedValue(), err
	}
	exp, err := r.loadFile(filename)
	if err := r.VM.Set("__initapi__", nil); err != nil {
		return otto.UndefinedValue(), err
	}
	return exp, err
}

func (r *Runtime) extractOptions(exports otto.Value, opts *lib.Options) error {
	expObj := exports.Object()
	if expObj == nil {
		return nil
	}

	v, err := expObj.Get("options")
	if err != nil {
		return err
	}
	ev, err := v.Export()
	if err != nil {
		return err
	}

	data, err := json.Marshal(ev)
	if err != nil {
		return err
	}
	if err := json.Unmarshal(data, opts); err != nil {
		return err
	}

	return nil
}

func (r *Runtime) loadFile(filename string) (otto.Value, error) {
	// To protect against directory traversal, prevent loading of files outside the root (pwd) dir
	path, err := filepath.Abs(filename)
	if err != nil {
		return otto.UndefinedValue(), err
	}
	if !strings.HasPrefix(path, r.Root) {
		return otto.UndefinedValue(), DirectoryTraversalError{Filename: filename, Root: r.Root}
	}

	// Don't re-compile repeated includes of the same module
	if exports, ok := r.Exports[path]; ok {
		return exports, nil
	}

	data, err := ioutil.ReadFile(path)
	if err != nil {
		return otto.UndefinedValue(), err
	}
	exports, err := r.load(path, data)
	if err != nil {
		return otto.UndefinedValue(), err
	}
	r.Exports[path] = exports

	log.WithField("path", path).Debug("File loaded")

	return exports, nil
}

func (r *Runtime) loadLib(filename string) (otto.Value, error) {
	if exports, ok := r.lib[filename]; ok {
		return exports, nil
	}

	data, err := libBox.Bytes(filename)
	if err != nil {
		return otto.UndefinedValue(), err
	}
	exports, err := r.load(filename, data)
	if err != nil {
		return otto.UndefinedValue(), err
	}
	r.lib[filename] = exports

	log.WithField("filename", filename).Debug("Library loaded")

	return exports, nil
}

func (r *Runtime) load(filename string, data []byte) (otto.Value, error) {
	nodeNames := []string{"node", "nodejs", "node.exe"}
	var nodePath string
	for _, name := range nodeNames {
		path, err := exec.LookPath(name)
		if err != nil {
			if e, ok := err.(*exec.Error); ok && e.Err != exec.ErrNotFound {
				return otto.UndefinedValue(), err
			}
			continue
		}
		nodePath = path
		break
	}
	if nodePath == "" {
		return otto.UndefinedValue(), errors.New(
			"Couldn't find node, make sure it's in your PATH. " +
				"This is a TEMPORARY dependency and will be removed. " +
				"See: https://github.com/loadimpact/k6/issues/14",
		)
	}

	// Compile the file with Babel; this subprocess invocation is TEMPORARY:
	// https://github.com/robertkrimen/otto/pull/205
	cmd := exec.Command(nodePath, babel, "--presets", "latest", "--no-babelrc")
	cmd.Dir = babelDir
	cmd.Stdin = bytes.NewReader(data)
	cmd.Stderr = os.Stderr
	src, err := cmd.Output()
	if err != nil {
		return otto.UndefinedValue(), err
	}

	// Use a wrapper function to turn the script into an exported module
	s, err := r.VM.Compile(filename, fmt.Sprintf(wrapper, string(src)))
	if err != nil {
		return otto.UndefinedValue(), err
	}
	exports, err := r.VM.Run(s)
	if err != nil {
		return otto.UndefinedValue(), err
	}

	// Extract script-defined options.
	var opts lib.Options
	if err := r.extractOptions(exports, &opts); err != nil {
		return exports, err
	}
	r.Options = r.Options.Apply(opts)

	return exports, nil
}
<|endoftext|>


<commit_before>package api

import (
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"
	"encoding/base64"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"

	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/metrics"
	"github.com/grafana/grafana/pkg/middleware"
	m "github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/setting"
	"github.com/grafana/grafana/pkg/social"
)

var (
	ErrProviderDeniedRequest = errors.New("Login provider denied login request")
	ErrEmailNotAllowed       = errors.New("Required email domain not fulfilled")
	ErrSignUpNotAllowed      = errors.New("Signup is not allowed for this adapter")
	ErrUsersQuotaReached     = errors.New("Users quota reached")
	ErrNoEmail               = errors.New("Login provider didn't return an email address")
)

func GenStateString() string {
	rnd := make([]byte, 32)
	rand.Read(rnd)
	return base64.StdEncoding.EncodeToString(rnd)
}

func OAuthLogin(ctx *middleware.Context) {
	if setting.OAuthService == nil {
		ctx.Handle(404, "login.OAuthLogin(oauth service not enabled)", nil)
		return
	}

	name := ctx.Params(":name")
	connect, ok := social.SocialMap[name]
	if !ok {
		ctx.Handle(404, "login.OAuthLogin(social login not enabled)", errors.New(name))
		return
	}

	error := ctx.Query("error")
	if error != "" {
		errorDesc := ctx.Query("error_description")
		redirectWithError(ctx, ErrProviderDeniedRequest, "error", error, "errorDesc", errorDesc)
		return
	}

	code := ctx.Query("code")
	if code == "" {
		state := GenStateString()
		ctx.Session.Set(middleware.SESS_KEY_OAUTH_STATE, state)
		if setting.OAuthService.OAuthInfos[name].HostedDomain == "" {
			ctx.Redirect(connect.AuthCodeURL(state, oauth2.AccessTypeOnline))
		} else {
			ctx.Redirect(connect.AuthCodeURL(state, oauth2.SetAuthURLParam("hd", setting.OAuthService.OAuthInfos[name].HostedDomain), oauth2.AccessTypeOnline))
		}
		return
	}

	// verify state string
	savedState := ctx.Session.Get(middleware.SESS_KEY_OAUTH_STATE).(string)
	queryState := ctx.Query("state")
	if savedState != queryState {
		ctx.Handle(500, "login.OAuthLogin(state mismatch)", nil)
		return
	}

	// handle call back
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: setting.OAuthService.OAuthInfos[name].TlsSkipVerify,
		},
	}
	oauthClient := &http.Client{
		Transport: tr,
	}

	if setting.OAuthService.OAuthInfos[name].TlsClientCert != "" || setting.OAuthService.OAuthInfos[name].TlsClientKey != "" {
		cert, err := tls.LoadX509KeyPair(setting.OAuthService.OAuthInfos[name].TlsClientCert, setting.OAuthService.OAuthInfos[name].TlsClientKey)
		if err != nil {
			log.Fatal(err)
		}

		tr.TLSClientConfig.Certificates = append(tr.TLSClientConfig.Certificates, cert)
	}

	if setting.OAuthService.OAuthInfos[name].TlsClientCa != "" {
		caCert, err := ioutil.ReadFile(setting.OAuthService.OAuthInfos[name].TlsClientCa)
		if err != nil {
			log.Fatal(err)
		}
		caCertPool := x509.NewCertPool()
		caCertPool.AppendCertsFromPEM(caCert)

		tr.TLSClientConfig.RootCAs = caCertPool
	}

	oauthCtx := context.WithValue(context.Background(), oauth2.HTTPClient, oauthClient)

	// get token from provider
	token, err := connect.Exchange(oauthCtx, code)
	if err != nil {
		ctx.Handle(500, "login.OAuthLogin(NewTransportWithCode)", err)
		return
	}
	// token.TokenType was defaulting to "bearer", which is out of spec, so we explicitly set to "Bearer"
	token.TokenType = "Bearer"

	ctx.Logger.Debug("OAuthLogin Got token")

	// set up oauth2 client
	client := connect.Client(oauthCtx, token)

	// get user info
	userInfo, err := connect.UserInfo(client)
	if err != nil {
		if sErr, ok := err.(*social.Error); ok {
			redirectWithError(ctx, sErr)
		} else {
			ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err)
		}
		return
	}

	ctx.Logger.Debug("OAuthLogin got user info", "userInfo", userInfo)

	// validate that we got at least an email address
	if userInfo.Email == "" {
		redirectWithError(ctx, ErrNoEmail)
		return
	}

	// validate that the email is allowed to login to grafana
	if !connect.IsEmailAllowed(userInfo.Email) {
		redirectWithError(ctx, ErrEmailNotAllowed)
		return
	}

	userQuery := m.GetUserByEmailQuery{Email: userInfo.Email}
	err = bus.Dispatch(&userQuery)

	// create account if missing
	if err == m.ErrUserNotFound {
		if !connect.IsSignupAllowed() {
			redirectWithError(ctx, ErrSignUpNotAllowed)
			return
		}
		limitReached, err := middleware.QuotaReached(ctx, "user")
		if err != nil {
			ctx.Handle(500, "Failed to get user quota", err)
			return
		}
		if limitReached {
			redirectWithError(ctx, ErrUsersQuotaReached)
			return
		}
		cmd := m.CreateUserCommand{
			Login:          userInfo.Login,
			Email:          userInfo.Email,
			Name:           userInfo.Name,
			Company:        userInfo.Company,
			DefaultOrgRole: userInfo.Role,
		}

		if err = bus.Dispatch(&cmd); err != nil {
			ctx.Handle(500, "Failed to create account", err)
			return
		}

		userQuery.Result = &cmd.Result
	} else if err != nil {
		ctx.Handle(500, "Unexpected error", err)
	}

	// login
	loginUserWithUser(userQuery.Result, ctx)

	metrics.M_Api_Login_OAuth.Inc()

	if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 {
		ctx.SetCookie("redirect_to", "", -1, setting.AppSubUrl+"/")
		ctx.Redirect(redirectTo)
		return
	}

	ctx.Redirect(setting.AppSubUrl + "/")
}

func redirectWithError(ctx *middleware.Context, err error, v ...interface{}) {
	ctx.Logger.Info(err.Error(), v...)
	// TODO: we can use the flash storage here once it's implemented
	ctx.Session.Set("loginError", err.Error())
	ctx.Redirect(setting.AppSubUrl + "/login")
}
<commit_msg>oauth: provide more logging for failed oauth requests<commit_after>package api

import (
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"
	"encoding/base64"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"

	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/log"
	"github.com/grafana/grafana/pkg/metrics"
	"github.com/grafana/grafana/pkg/middleware"
	m "github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/setting"
	"github.com/grafana/grafana/pkg/social"
)

var (
	ErrProviderDeniedRequest = errors.New("Login provider denied login request")
	ErrEmailNotAllowed       = errors.New("Required email domain not fulfilled")
	ErrSignUpNotAllowed      = errors.New("Signup is not allowed for this adapter")
	ErrUsersQuotaReached     = errors.New("Users quota reached")
	ErrNoEmail               = errors.New("Login provider didn't return an email address")
	oauthLogger              = log.New("oauth.login")
)

func GenStateString() string {
	rnd := make([]byte, 32)
	rand.Read(rnd)
	return base64.StdEncoding.EncodeToString(rnd)
}

func OAuthLogin(ctx *middleware.Context) {
	if setting.OAuthService == nil {
		ctx.Handle(404, "login.OAuthLogin(oauth service not enabled)", nil)
		return
	}

	name := ctx.Params(":name")
	connect, ok := social.SocialMap[name]
	if !ok {
		ctx.Handle(404, "login.OAuthLogin(social login not enabled)", errors.New(name))
		return
	}

	errorParam := ctx.Query("error")
	if errorParam != "" {
		errorDesc := ctx.Query("error_description")
		oauthLogger.Error("failed to login ", "error", errorParam, "errorDesc", errorDesc)
		redirectWithError(ctx, ErrProviderDeniedRequest, "error", errorParam, "errorDesc", errorDesc)
		return
	}

	code := ctx.Query("code")
	if code == "" {
		state := GenStateString()
		ctx.Session.Set(middleware.SESS_KEY_OAUTH_STATE, state)
		if setting.OAuthService.OAuthInfos[name].HostedDomain == "" {
			ctx.Redirect(connect.AuthCodeURL(state, oauth2.AccessTypeOnline))
		} else {
			ctx.Redirect(connect.AuthCodeURL(state, oauth2.SetAuthURLParam("hd", setting.OAuthService.OAuthInfos[name].HostedDomain), oauth2.AccessTypeOnline))
		}
		return
	}

	// verify state string
	savedState := ctx.Session.Get(middleware.SESS_KEY_OAUTH_STATE).(string)
	queryState := ctx.Query("state")
	if savedState != queryState {
		ctx.Handle(500, "login.OAuthLogin(state mismatch)", nil)
		return
	}

	// handle call back
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: setting.OAuthService.OAuthInfos[name].TlsSkipVerify,
		},
	}
	oauthClient := &http.Client{
		Transport: tr,
	}

	if setting.OAuthService.OAuthInfos[name].TlsClientCert != "" || setting.OAuthService.OAuthInfos[name].TlsClientKey != "" {
		cert, err := tls.LoadX509KeyPair(setting.OAuthService.OAuthInfos[name].TlsClientCert, setting.OAuthService.OAuthInfos[name].TlsClientKey)
		if err != nil {
			log.Fatal(1, "Failed to setup TlsClientCert", "oauth provider", name, "error", err)
		}

		tr.TLSClientConfig.Certificates = append(tr.TLSClientConfig.Certificates, cert)
	}

	if setting.OAuthService.OAuthInfos[name].TlsClientCa != "" {
		caCert, err := ioutil.ReadFile(setting.OAuthService.OAuthInfos[name].TlsClientCa)
		if err != nil {
			log.Fatal(1, "Failed to setup TlsClientCa", "oauth provider", name, "error", err)
		}
		caCertPool := x509.NewCertPool()
		caCertPool.AppendCertsFromPEM(caCert)

		tr.TLSClientConfig.RootCAs = caCertPool
	}

	oauthCtx := context.WithValue(context.Background(), oauth2.HTTPClient, oauthClient)

	// get token from provider
	token, err := connect.Exchange(oauthCtx, code)
	if err != nil {
		ctx.Handle(500, "login.OAuthLogin(NewTransportWithCode)", err)
		return
	}
	// token.TokenType was defaulting to "bearer", which is out of spec, so we explicitly set to "Bearer"
	token.TokenType = "Bearer"

	ctx.Logger.Debug("OAuthLogin Got token")

	// set up oauth2 client
	client := connect.Client(oauthCtx, token)

	// get user info
	userInfo, err := connect.UserInfo(client)
	if err != nil {
		if sErr, ok := err.(*social.Error); ok {
			redirectWithError(ctx, sErr)
		} else {
			ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err)
		}
		return
	}

	ctx.Logger.Debug("OAuthLogin got user info", "userInfo", userInfo)

	// validate that we got at least an email address
	if userInfo.Email == "" {
		redirectWithError(ctx, ErrNoEmail)
		return
	}

	// validate that the email is allowed to login to grafana
	if !connect.IsEmailAllowed(userInfo.Email) {
		redirectWithError(ctx, ErrEmailNotAllowed)
		return
	}

	userQuery := m.GetUserByEmailQuery{Email: userInfo.Email}
	err = bus.Dispatch(&userQuery)

	// create account if missing
	if err == m.ErrUserNotFound {
		if !connect.IsSignupAllowed() {
			redirectWithError(ctx, ErrSignUpNotAllowed)
			return
		}
		limitReached, err := middleware.QuotaReached(ctx, "user")
		if err != nil {
			ctx.Handle(500, "Failed to get user quota", err)
			return
		}
		if limitReached {
			redirectWithError(ctx, ErrUsersQuotaReached)
			return
		}
		cmd := m.CreateUserCommand{
			Login:          userInfo.Login,
			Email:          userInfo.Email,
			Name:           userInfo.Name,
			Company:        userInfo.Company,
			DefaultOrgRole: userInfo.Role,
		}

		if err = bus.Dispatch(&cmd); err != nil {
			ctx.Handle(500, "Failed to create account", err)
			return
		}

		userQuery.Result = &cmd.Result
	} else if err != nil {
		ctx.Handle(500, "Unexpected error", err)
	}

	// login
	loginUserWithUser(userQuery.Result, ctx)

	metrics.M_Api_Login_OAuth.Inc()

	if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 {
		ctx.SetCookie("redirect_to", "", -1, setting.AppSubUrl+"/")
		ctx.Redirect(redirectTo)
		return
	}

	ctx.Redirect(setting.AppSubUrl + "/")
}

func redirectWithError(ctx *middleware.Context, err error, v ...interface{}) {
	ctx.Logger.Info(err.Error(), v...)
	// TODO: we can use the flash storage here once it's implemented
	ctx.Session.Set("loginError", err.Error())
	ctx.Redirect(setting.AppSubUrl + "/login")
}
<|endoftext|>


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

package v1

import (
	"k8s.io/client-go/pkg/runtime"
	"k8s.io/client-go/pkg/util"
	"k8s.io/client-go/pkg/util/intstr"
	"k8s.io/client-go/pkg/util/parsers"
)

func addDefaultingFuncs(scheme *runtime.Scheme) error {
	RegisterDefaults(scheme)
	return scheme.AddDefaultingFuncs(
		SetDefaults_PodExecOptions,
		SetDefaults_PodAttachOptions,
		SetDefaults_ReplicationController,
		SetDefaults_Volume,
		SetDefaults_ContainerPort,
		SetDefaults_Container,
		SetDefaults_ServiceSpec,
		SetDefaults_Pod,
		SetDefaults_PodSpec,
		SetDefaults_Probe,
		SetDefaults_SecretVolumeSource,
		SetDefaults_ConfigMapVolumeSource,
		SetDefaults_DownwardAPIVolumeSource,
		SetDefaults_Secret,
		SetDefaults_PersistentVolume,
		SetDefaults_PersistentVolumeClaim,
		SetDefaults_ISCSIVolumeSource,
		SetDefaults_Endpoints,
		SetDefaults_HTTPGetAction,
		SetDefaults_NamespaceStatus,
		SetDefaults_Node,
		SetDefaults_NodeStatus,
		SetDefaults_ObjectFieldSelector,
		SetDefaults_LimitRangeItem,
		SetDefaults_ConfigMap,
		SetDefaults_RBDVolumeSource,
		SetDefaults_ResourceList,
	)
}

func SetDefaults_ResourceList(obj *ResourceList) {
	for key, val := range *obj {
		// TODO(#18538): We round up resource values to milli scale to maintain API compatibility.
		// In the future, we should instead reject values that need rounding.
		const milliScale = -3
		val.RoundUp(milliScale)

		(*obj)[ResourceName(key)] = val
	}
}

func SetDefaults_PodExecOptions(obj *PodExecOptions) {
	obj.Stdout = true
	obj.Stderr = true
}
func SetDefaults_PodAttachOptions(obj *PodAttachOptions) {
	obj.Stdout = true
	obj.Stderr = true
}
func SetDefaults_ReplicationController(obj *ReplicationController) {
	var labels map[string]string
	if obj.Spec.Template != nil {
		labels = obj.Spec.Template.Labels
	}
	// TODO: support templates defined elsewhere when we support them in the API
	if labels != nil {
		if len(obj.Spec.Selector) == 0 {
			obj.Spec.Selector = labels
		}
		if len(obj.Labels) == 0 {
			obj.Labels = labels
		}
	}
	if obj.Spec.Replicas == nil {
		obj.Spec.Replicas = new(int32)
		*obj.Spec.Replicas = 1
	}
}
func SetDefaults_Volume(obj *Volume) {
	if util.AllPtrFieldsNil(&obj.VolumeSource) {
		obj.VolumeSource = VolumeSource{
			EmptyDir: &EmptyDirVolumeSource{},
		}
	}
}
func SetDefaults_ContainerPort(obj *ContainerPort) {
	if obj.Protocol == "" {
		obj.Protocol = ProtocolTCP
	}
}
func SetDefaults_Container(obj *Container) {
	if obj.ImagePullPolicy == "" {
		// Ignore error and assume it has been validated elsewhere
		_, tag, _, _ := parsers.ParseImageName(obj.Image)

		// Check image tag

		if tag == "latest" {
			obj.ImagePullPolicy = PullAlways
		} else {
			obj.ImagePullPolicy = PullIfNotPresent
		}
	}
	if obj.TerminationMessagePath == "" {
		obj.TerminationMessagePath = TerminationMessagePathDefault
	}
}
func SetDefaults_ServiceSpec(obj *ServiceSpec) {
	if obj.SessionAffinity == "" {
		obj.SessionAffinity = ServiceAffinityNone
	}
	if obj.Type == "" {
		obj.Type = ServiceTypeClusterIP
	}
	for i := range obj.Ports {
		sp := &obj.Ports[i]
		if sp.Protocol == "" {
			sp.Protocol = ProtocolTCP
		}
		if sp.TargetPort == intstr.FromInt(0) || sp.TargetPort == intstr.FromString("") {
			sp.TargetPort = intstr.FromInt(int(sp.Port))
		}
	}
}
func SetDefaults_Pod(obj *Pod) {
	// If limits are specified, but requests are not, default requests to limits
	// This is done here rather than a more specific defaulting pass on ResourceRequirements
	// because we only want this defaulting semantic to take place on a Pod and not a PodTemplate
	for i := range obj.Spec.Containers {
		// set requests to limits if requests are not specified, but limits are
		if obj.Spec.Containers[i].Resources.Limits != nil {
			if obj.Spec.Containers[i].Resources.Requests == nil {
				obj.Spec.Containers[i].Resources.Requests = make(ResourceList)
			}
			for key, value := range obj.Spec.Containers[i].Resources.Limits {
				if _, exists := obj.Spec.Containers[i].Resources.Requests[key]; !exists {
					obj.Spec.Containers[i].Resources.Requests[key] = *(value.Copy())
				}
			}
		}
	}
}
func SetDefaults_PodSpec(obj *PodSpec) {
	if obj.DNSPolicy == "" {
		obj.DNSPolicy = DNSClusterFirst
	}
	if obj.RestartPolicy == "" {
		obj.RestartPolicy = RestartPolicyAlways
	}
	if obj.HostNetwork {
		defaultHostNetworkPorts(&obj.Containers)
	}
	if obj.SecurityContext == nil {
		obj.SecurityContext = &PodSecurityContext{}
	}
	if obj.TerminationGracePeriodSeconds == nil {
		period := int64(DefaultTerminationGracePeriodSeconds)
		obj.TerminationGracePeriodSeconds = &period
	}
	if obj.Affinity == nil {
		obj.Affinity = &Affinity{}
	}
}
func SetDefaults_Probe(obj *Probe) {
	if obj.TimeoutSeconds == 0 {
		obj.TimeoutSeconds = 1
	}
	if obj.PeriodSeconds == 0 {
		obj.PeriodSeconds = 10
	}
	if obj.SuccessThreshold == 0 {
		obj.SuccessThreshold = 1
	}
	if obj.FailureThreshold == 0 {
		obj.FailureThreshold = 3
	}
}
func SetDefaults_SecretVolumeSource(obj *SecretVolumeSource) {
	if obj.DefaultMode == nil {
		perm := int32(SecretVolumeSourceDefaultMode)
		obj.DefaultMode = &perm
	}
}
func SetDefaults_ConfigMapVolumeSource(obj *ConfigMapVolumeSource) {
	if obj.DefaultMode == nil {
		perm := int32(ConfigMapVolumeSourceDefaultMode)
		obj.DefaultMode = &perm
	}
}
func SetDefaults_DownwardAPIVolumeSource(obj *DownwardAPIVolumeSource) {
	if obj.DefaultMode == nil {
		perm := int32(DownwardAPIVolumeSourceDefaultMode)
		obj.DefaultMode = &perm
	}
}
func SetDefaults_Secret(obj *Secret) {
	if obj.Type == "" {
		obj.Type = SecretTypeOpaque
	}
}
func SetDefaults_PersistentVolume(obj *PersistentVolume) {
	if obj.Status.Phase == "" {
		obj.Status.Phase = VolumePending
	}
	if obj.Spec.PersistentVolumeReclaimPolicy == "" {
		obj.Spec.PersistentVolumeReclaimPolicy = PersistentVolumeReclaimRetain
	}
}
func SetDefaults_PersistentVolumeClaim(obj *PersistentVolumeClaim) {
	if obj.Status.Phase == "" {
		obj.Status.Phase = ClaimPending
	}
}
func SetDefaults_ISCSIVolumeSource(obj *ISCSIVolumeSource) {
	if obj.ISCSIInterface == "" {
		obj.ISCSIInterface = "default"
	}
}
func SetDefaults_AzureDiskVolumeSource(obj *AzureDiskVolumeSource) {
	if obj.CachingMode == nil {
		obj.CachingMode = new(AzureDataDiskCachingMode)
		*obj.CachingMode = AzureDataDiskCachingNone
	}
	if obj.FSType == nil {
		obj.FSType = new(string)
		*obj.FSType = "ext4"
	}
	if obj.ReadOnly == nil {
		obj.ReadOnly = new(bool)
		*obj.ReadOnly = false
	}
}
func SetDefaults_Endpoints(obj *Endpoints) {
	for i := range obj.Subsets {
		ss := &obj.Subsets[i]
		for i := range ss.Ports {
			ep := &ss.Ports[i]
			if ep.Protocol == "" {
				ep.Protocol = ProtocolTCP
			}
		}
	}
}
func SetDefaults_HTTPGetAction(obj *HTTPGetAction) {
	if obj.Path == "" {
		obj.Path = "/"
	}
	if obj.Scheme == "" {
		obj.Scheme = URISchemeHTTP
	}
}
func SetDefaults_NamespaceStatus(obj *NamespaceStatus) {
	if obj.Phase == "" {
		obj.Phase = NamespaceActive
	}
}
func SetDefaults_Node(obj *Node) {
	if obj.Spec.ExternalID == "" {
		obj.Spec.ExternalID = obj.Name
	}
}
func SetDefaults_NodeStatus(obj *NodeStatus) {
	if obj.Allocatable == nil && obj.Capacity != nil {
		obj.Allocatable = make(ResourceList, len(obj.Capacity))
		for key, value := range obj.Capacity {
			obj.Allocatable[key] = *(value.Copy())
		}
		obj.Allocatable = obj.Capacity
	}
}
func SetDefaults_ObjectFieldSelector(obj *ObjectFieldSelector) {
	if obj.APIVersion == "" {
		obj.APIVersion = "v1"
	}
}
func SetDefaults_LimitRangeItem(obj *LimitRangeItem) {
	// for container limits, we apply default values
	if obj.Type == LimitTypeContainer {

		if obj.Default == nil {
			obj.Default = make(ResourceList)
		}
		if obj.DefaultRequest == nil {
			obj.DefaultRequest = make(ResourceList)
		}

		// If a default limit is unspecified, but the max is specified, default the limit to the max
		for key, value := range obj.Max {
			if _, exists := obj.Default[key]; !exists {
				obj.Default[key] = *(value.Copy())
			}
		}
		// If a default limit is specified, but the default request is not, default request to limit
		for key, value := range obj.Default {
			if _, exists := obj.DefaultRequest[key]; !exists {
				obj.DefaultRequest[key] = *(value.Copy())
			}
		}
		// If a default request is not specified, but the min is provided, default request to the min
		for key, value := range obj.Min {
			if _, exists := obj.DefaultRequest[key]; !exists {
				obj.DefaultRequest[key] = *(value.Copy())
			}
		}
	}
}
func SetDefaults_ConfigMap(obj *ConfigMap) {
	if obj.Data == nil {
		obj.Data = make(map[string]string)
	}
}

// With host networking default all container ports to host ports.
func defaultHostNetworkPorts(containers *[]Container) {
	for i := range *containers {
		for j := range (*containers)[i].Ports {
			if (*containers)[i].Ports[j].HostPort == 0 {
				(*containers)[i].Ports[j].HostPort = (*containers)[i].Ports[j].ContainerPort
			}
		}
	}
}

func SetDefaults_RBDVolumeSource(obj *RBDVolumeSource) {
	if obj.RBDPool == "" {
		obj.RBDPool = "rbd"
	}
	if obj.RadosUser == "" {
		obj.RadosUser = "admin"
	}
	if obj.Keyring == "" {
		obj.Keyring = "/etc/ceph/keyring"
	}
}
<commit_msg>published by bot (https://github.com/kubernetes/contrib/tree/master/mungegithub)<commit_after>/*
Copyright 2015 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.
*/

package v1

import (
	"k8s.io/client-go/pkg/runtime"
	"k8s.io/client-go/pkg/util"
	"k8s.io/client-go/pkg/util/intstr"
	"k8s.io/client-go/pkg/util/parsers"
)

func addDefaultingFuncs(scheme *runtime.Scheme) error {
	RegisterDefaults(scheme)
	return scheme.AddDefaultingFuncs(
		SetDefaults_PodExecOptions,
		SetDefaults_PodAttachOptions,
		SetDefaults_ReplicationController,
		SetDefaults_Volume,
		SetDefaults_ContainerPort,
		SetDefaults_Container,
		SetDefaults_ServiceSpec,
		SetDefaults_Pod,
		SetDefaults_PodSpec,
		SetDefaults_Probe,
		SetDefaults_SecretVolumeSource,
		SetDefaults_ConfigMapVolumeSource,
		SetDefaults_DownwardAPIVolumeSource,
		SetDefaults_Secret,
		SetDefaults_PersistentVolume,
		SetDefaults_PersistentVolumeClaim,
		SetDefaults_ISCSIVolumeSource,
		SetDefaults_Endpoints,
		SetDefaults_HTTPGetAction,
		SetDefaults_NamespaceStatus,
		SetDefaults_Node,
		SetDefaults_NodeStatus,
		SetDefaults_ObjectFieldSelector,
		SetDefaults_LimitRangeItem,
		SetDefaults_ConfigMap,
		SetDefaults_RBDVolumeSource,
		SetDefaults_ResourceList,
	)
}

func SetDefaults_ResourceList(obj *ResourceList) {
	for key, val := range *obj {
		// TODO(#18538): We round up resource values to milli scale to maintain API compatibility.
		// In the future, we should instead reject values that need rounding.
		const milliScale = -3
		val.RoundUp(milliScale)

		(*obj)[ResourceName(key)] = val
	}
}

func SetDefaults_PodExecOptions(obj *PodExecOptions) {
	obj.Stdout = true
	obj.Stderr = true
}
func SetDefaults_PodAttachOptions(obj *PodAttachOptions) {
	obj.Stdout = true
	obj.Stderr = true
}
func SetDefaults_ReplicationController(obj *ReplicationController) {
	var labels map[string]string
	if obj.Spec.Template != nil {
		labels = obj.Spec.Template.Labels
	}
	// TODO: support templates defined elsewhere when we support them in the API
	if labels != nil {
		if len(obj.Spec.Selector) == 0 {
			obj.Spec.Selector = labels
		}
		if len(obj.Labels) == 0 {
			obj.Labels = labels
		}
	}
	if obj.Spec.Replicas == nil {
		obj.Spec.Replicas = new(int32)
		*obj.Spec.Replicas = 1
	}
}
func SetDefaults_Volume(obj *Volume) {
	if util.AllPtrFieldsNil(&obj.VolumeSource) {
		obj.VolumeSource = VolumeSource{
			EmptyDir: &EmptyDirVolumeSource{},
		}
	}
}
func SetDefaults_ContainerPort(obj *ContainerPort) {
	if obj.Protocol == "" {
		obj.Protocol = ProtocolTCP
	}
}
func SetDefaults_Container(obj *Container) {
	if obj.ImagePullPolicy == "" {
		// Ignore error and assume it has been validated elsewhere
		_, tag, _, _ := parsers.ParseImageName(obj.Image)

		// Check image tag

		if tag == "latest" {
			obj.ImagePullPolicy = PullAlways
		} else {
			obj.ImagePullPolicy = PullIfNotPresent
		}
	}
	if obj.TerminationMessagePath == "" {
		obj.TerminationMessagePath = TerminationMessagePathDefault
	}
}
func SetDefaults_ServiceSpec(obj *ServiceSpec) {
	if obj.SessionAffinity == "" {
		obj.SessionAffinity = ServiceAffinityNone
	}
	if obj.Type == "" {
		obj.Type = ServiceTypeClusterIP
	}
	for i := range obj.Ports {
		sp := &obj.Ports[i]
		if sp.Protocol == "" {
			sp.Protocol = ProtocolTCP
		}
		if sp.TargetPort == intstr.FromInt(0) || sp.TargetPort == intstr.FromString("") {
			sp.TargetPort = intstr.FromInt(int(sp.Port))
		}
	}
}
func SetDefaults_Pod(obj *Pod) {
	// If limits are specified, but requests are not, default requests to limits
	// This is done here rather than a more specific defaulting pass on ResourceRequirements
	// because we only want this defaulting semantic to take place on a Pod and not a PodTemplate
	for i := range obj.Spec.Containers {
		// set requests to limits if requests are not specified, but limits are
		if obj.Spec.Containers[i].Resources.Limits != nil {
			if obj.Spec.Containers[i].Resources.Requests == nil {
				obj.Spec.Containers[i].Resources.Requests = make(ResourceList)
			}
			for key, value := range obj.Spec.Containers[i].Resources.Limits {
				if _, exists := obj.Spec.Containers[i].Resources.Requests[key]; !exists {
					obj.Spec.Containers[i].Resources.Requests[key] = *(value.Copy())
				}
			}
		}
	}
}
func SetDefaults_PodSpec(obj *PodSpec) {
	if obj.DNSPolicy == "" {
		obj.DNSPolicy = DNSClusterFirst
	}
	if obj.RestartPolicy == "" {
		obj.RestartPolicy = RestartPolicyAlways
	}
	if obj.HostNetwork {
		defaultHostNetworkPorts(&obj.Containers)
	}
	if obj.SecurityContext == nil {
		obj.SecurityContext = &PodSecurityContext{}
	}
	if obj.TerminationGracePeriodSeconds == nil {
		period := int64(DefaultTerminationGracePeriodSeconds)
		obj.TerminationGracePeriodSeconds = &period
	}
}
func SetDefaults_Probe(obj *Probe) {
	if obj.TimeoutSeconds == 0 {
		obj.TimeoutSeconds = 1
	}
	if obj.PeriodSeconds == 0 {
		obj.PeriodSeconds = 10
	}
	if obj.SuccessThreshold == 0 {
		obj.SuccessThreshold = 1
	}
	if obj.FailureThreshold == 0 {
		obj.FailureThreshold = 3
	}
}
func SetDefaults_SecretVolumeSource(obj *SecretVolumeSource) {
	if obj.DefaultMode == nil {
		perm := int32(SecretVolumeSourceDefaultMode)
		obj.DefaultMode = &perm
	}
}
func SetDefaults_ConfigMapVolumeSource(obj *ConfigMapVolumeSource) {
	if obj.DefaultMode == nil {
		perm := int32(ConfigMapVolumeSourceDefaultMode)
		obj.DefaultMode = &perm
	}
}
func SetDefaults_DownwardAPIVolumeSource(obj *DownwardAPIVolumeSource) {
	if obj.DefaultMode == nil {
		perm := int32(DownwardAPIVolumeSourceDefaultMode)
		obj.DefaultMode = &perm
	}
}
func SetDefaults_Secret(obj *Secret) {
	if obj.Type == "" {
		obj.Type = SecretTypeOpaque
	}
}
func SetDefaults_PersistentVolume(obj *PersistentVolume) {
	if obj.Status.Phase == "" {
		obj.Status.Phase = VolumePending
	}
	if obj.Spec.PersistentVolumeReclaimPolicy == "" {
		obj.Spec.PersistentVolumeReclaimPolicy = PersistentVolumeReclaimRetain
	}
}
func SetDefaults_PersistentVolumeClaim(obj *PersistentVolumeClaim) {
	if obj.Status.Phase == "" {
		obj.Status.Phase = ClaimPending
	}
}
func SetDefaults_ISCSIVolumeSource(obj *ISCSIVolumeSource) {
	if obj.ISCSIInterface == "" {
		obj.ISCSIInterface = "default"
	}
}
func SetDefaults_AzureDiskVolumeSource(obj *AzureDiskVolumeSource) {
	if obj.CachingMode == nil {
		obj.CachingMode = new(AzureDataDiskCachingMode)
		*obj.CachingMode = AzureDataDiskCachingNone
	}
	if obj.FSType == nil {
		obj.FSType = new(string)
		*obj.FSType = "ext4"
	}
	if obj.ReadOnly == nil {
		obj.ReadOnly = new(bool)
		*obj.ReadOnly = false
	}
}
func SetDefaults_Endpoints(obj *Endpoints) {
	for i := range obj.Subsets {
		ss := &obj.Subsets[i]
		for i := range ss.Ports {
			ep := &ss.Ports[i]
			if ep.Protocol == "" {
				ep.Protocol = ProtocolTCP
			}
		}
	}
}
func SetDefaults_HTTPGetAction(obj *HTTPGetAction) {
	if obj.Path == "" {
		obj.Path = "/"
	}
	if obj.Scheme == "" {
		obj.Scheme = URISchemeHTTP
	}
}
func SetDefaults_NamespaceStatus(obj *NamespaceStatus) {
	if obj.Phase == "" {
		obj.Phase = NamespaceActive
	}
}
func SetDefaults_Node(obj *Node) {
	if obj.Spec.ExternalID == "" {
		obj.Spec.ExternalID = obj.Name
	}
}
func SetDefaults_NodeStatus(obj *NodeStatus) {
	if obj.Allocatable == nil && obj.Capacity != nil {
		obj.Allocatable = make(ResourceList, len(obj.Capacity))
		for key, value := range obj.Capacity {
			obj.Allocatable[key] = *(value.Copy())
		}
		obj.Allocatable = obj.Capacity
	}
}
func SetDefaults_ObjectFieldSelector(obj *ObjectFieldSelector) {
	if obj.APIVersion == "" {
		obj.APIVersion = "v1"
	}
}
func SetDefaults_LimitRangeItem(obj *LimitRangeItem) {
	// for container limits, we apply default values
	if obj.Type == LimitTypeContainer {

		if obj.Default == nil {
			obj.Default = make(ResourceList)
		}
		if obj.DefaultRequest == nil {
			obj.DefaultRequest = make(ResourceList)
		}

		// If a default limit is unspecified, but the max is specified, default the limit to the max
		for key, value := range obj.Max {
			if _, exists := obj.Default[key]; !exists {
				obj.Default[key] = *(value.Copy())
			}
		}
		// If a default limit is specified, but the default request is not, default request to limit
		for key, value := range obj.Default {
			if _, exists := obj.DefaultRequest[key]; !exists {
				obj.DefaultRequest[key] = *(value.Copy())
			}
		}
		// If a default request is not specified, but the min is provided, default request to the min
		for key, value := range obj.Min {
			if _, exists := obj.DefaultRequest[key]; !exists {
				obj.DefaultRequest[key] = *(value.Copy())
			}
		}
	}
}
func SetDefaults_ConfigMap(obj *ConfigMap) {
	if obj.Data == nil {
		obj.Data = make(map[string]string)
	}
}

// With host networking default all container ports to host ports.
func defaultHostNetworkPorts(containers *[]Container) {
	for i := range *containers {
		for j := range (*containers)[i].Ports {
			if (*containers)[i].Ports[j].HostPort == 0 {
				(*containers)[i].Ports[j].HostPort = (*containers)[i].Ports[j].ContainerPort
			}
		}
	}
}

func SetDefaults_RBDVolumeSource(obj *RBDVolumeSource) {
	if obj.RBDPool == "" {
		obj.RBDPool = "rbd"
	}
	if obj.RadosUser == "" {
		obj.RadosUser = "admin"
	}
	if obj.Keyring == "" {
		obj.Keyring = "/etc/ceph/keyring"
	}
}
<|endoftext|>