<commit_before>package providercache

import (
	"context"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"

	getter "github.com/hashicorp/go-getter"

	"github.com/hashicorp/terraform/internal/copy"
	"github.com/hashicorp/terraform/internal/getproviders"
	"github.com/hashicorp/terraform/internal/httpclient"
)

// We borrow the "unpack a zip file into a target directory" logic from
// go-getter, even though we're not otherwise using go-getter here.
// (We don't need the same flexibility as we have for modules, because
// providers _always_ come from provider registries, which have a very
// specific protocol and set of expectations.)
var unzip = getter.ZipDecompressor{}

func installFromHTTPURL(ctx context.Context, meta getproviders.PackageMeta, targetDir string, allowedHashes []getproviders.Hash) (*getproviders.PackageAuthenticationResult, error) {
	url := meta.Location.String()

	// When we're installing from an HTTP URL we expect the URL to refer to
	// a zip file. We'll fetch that into a temporary file here and then
	// delegate to installFromLocalArchive below to actually extract it.
	// (We're not using go-getter here because its HTTP getter has a bunch
	// of extraneous functionality we don't need or want, like indirection
	// through X-Terraform-Get header, attempting partial fetches for
	// files that already exist, etc.)

	httpClient := httpclient.New()
	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("invalid provider download request: %s", err)
	}
	resp, err := httpClient.Do(req)
	if err != nil {
		if ctx.Err() == context.Canceled {
			// "context canceled" is not a user-friendly error message,
			// so we'll return a more appropriate one here.
			return nil, fmt.Errorf("provider download was interrupted")
		}
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("unsuccessful request to %s: %s", url, resp.Status)
	}

	f, err := ioutil.TempFile("", "terraform-provider")
	if err != nil {
		return nil, fmt.Errorf("failed to open temporary file to download from %s", url)
	}
	defer f.Close()
	defer os.Remove(f.Name())

	// We'll borrow go-getter's "cancelable copy" implementation here so that
	// the download can potentially be interrupted partway through.
	n, err := getter.Copy(ctx, f, resp.Body)
	if err == nil && n < resp.ContentLength {
		err = fmt.Errorf("incorrect response size: expected %d bytes, but got %d bytes", resp.ContentLength, n)
	}
	if err != nil {
		return nil, err
	}

	archiveFilename := f.Name()
	localLocation := getproviders.PackageLocalArchive(archiveFilename)

	var authResult *getproviders.PackageAuthenticationResult
	if meta.Authentication != nil {
		if authResult, err = meta.Authentication.AuthenticatePackage(localLocation); err != nil {
			return authResult, err
		}
	}

	// We can now delegate to installFromLocalArchive for extraction. To do so,
	// we construct a new package meta description using the local archive
	// path as the location, and skipping authentication. installFromLocalMeta
	// is responsible for verifying that the archive matches the allowedHashes,
	// though.
	localMeta := getproviders.PackageMeta{
		Provider:         meta.Provider,
		Version:          meta.Version,
		ProtocolVersions: meta.ProtocolVersions,
		TargetPlatform:   meta.TargetPlatform,
		Filename:         meta.Filename,
		Location:         localLocation,
		Authentication:   nil,
	}
	if _, err := installFromLocalArchive(ctx, localMeta, targetDir, allowedHashes); err != nil {
		return nil, err
	}
	return authResult, nil
}

func installFromLocalArchive(ctx context.Context, meta getproviders.PackageMeta, targetDir string, allowedHashes []getproviders.Hash) (*getproviders.PackageAuthenticationResult, error) {
	var authResult *getproviders.PackageAuthenticationResult
	if meta.Authentication != nil {
		var err error
		if authResult, err = meta.Authentication.AuthenticatePackage(meta.Location); err != nil {
			return nil, err
		}
	}

	if len(allowedHashes) > 0 {
		if matches, err := meta.MatchesAnyHash(allowedHashes); err != nil {
			return authResult, fmt.Errorf(
				"failed to calculate checksum for %s %s package at %s: %s",
				meta.Provider, meta.Version, meta.Location, err,
			)
		} else if !matches {
			return authResult, fmt.Errorf(
				"the current package for %s %s doesn't match any of the checksums previously recorded in the dependency lock file; for more information: https://www.terraform.io/language/provider-checksum-verification",
				meta.Provider, meta.Version,
			)
		}
	}

	filename := meta.Location.String()

	err := unzip.Decompress(targetDir, filename, true, 0000)
	if err != nil {
		return authResult, err
	}

	return authResult, nil
}

// installFromLocalDir is the implementation of both installing a package from
// a local directory source _and_ of linking a package from another cache
// in LinkFromOtherCache, because they both do fundamentally the same
// operation: symlink if possible, or deep-copy otherwise.
func installFromLocalDir(ctx context.Context, meta getproviders.PackageMeta, targetDir string, allowedHashes []getproviders.Hash) (*getproviders.PackageAuthenticationResult, error) {
	sourceDir := meta.Location.String()

	absNew, err := filepath.Abs(targetDir)
	if err != nil {
		return nil, fmt.Errorf("failed to make target path %s absolute: %s", targetDir, err)
	}
	absCurrent, err := filepath.Abs(sourceDir)
	if err != nil {
		return nil, fmt.Errorf("failed to make source path %s absolute: %s", sourceDir, err)
	}

	// Before we do anything else, we'll do a quick check to make sure that
	// these two paths are not pointing at the same physical directory on
	// disk. This compares the files by their OS-level device and directory
	// entry identifiers, not by their virtual filesystem paths.
	if same, err := copy.SameFile(absNew, absCurrent); same {
		return nil, fmt.Errorf("cannot install existing provider directory %s to itself", targetDir)
	} else if err != nil {
		return nil, fmt.Errorf("failed to determine if %s and %s are the same: %s", sourceDir, targetDir, err)
	}

	var authResult *getproviders.PackageAuthenticationResult
	if meta.Authentication != nil {
		// (we have this here for completeness but note that local filesystem
		// mirrors typically don't include enough information for package
		// authentication and so we'll rarely get in here in practice.)
		var err error
		if authResult, err = meta.Authentication.AuthenticatePackage(meta.Location); err != nil {
			return nil, err
		}
	}

	// If the caller provided at least one hash in allowedHashes then at
	// least one of those hashes ought to match. However, for local directories
	// in particular we can't actually verify the legacy "zh:" hash scheme
	// because it requires access to the original .zip archive, and so as a
	// measure of pragmatism we'll treat a set of hashes where all are "zh:"
	// the same as no hashes at all, and let anything pass. This is definitely
	// non-ideal but accepted for two reasons:
	// - Packages we find on local disk can be considered a little more trusted
	//   than packages coming from over the network, because we assume that
	//   they were either placed intentionally by an operator or they were
	//   automatically installed by a previous network operation that would've
	//   itself verified the hashes.
	// - Our installer makes a concerted effort to record at least one new-style
	//   hash for each lock entry, so we should very rarely end up in this
	//   situation anyway.
	suitableHashCount := 0
	for _, hash := range allowedHashes {
		if !hash.HasScheme(getproviders.HashSchemeZip) {
			suitableHashCount++
		}
	}
	if suitableHashCount > 0 {
		if matches, err := meta.MatchesAnyHash(allowedHashes); err != nil {
			return authResult, fmt.Errorf(
				"failed to calculate checksum for %s %s package at %s: %s",
				meta.Provider, meta.Version, meta.Location, err,
			)
		} else if !matches {
			return authResult, fmt.Errorf(
				"the local package for %s %s doesn't match any of the checksums previously recorded in the dependency lock file (this might be because the available checksums are for packages targeting different platforms); for more information: https://www.terraform.io/language/provider-checksum-verification",
				meta.Provider, meta.Version,
			)
		}
	}

	// Delete anything that's already present at this path first.
	err = os.RemoveAll(targetDir)
	if err != nil && !os.IsNotExist(err) {
		return nil, fmt.Errorf("failed to remove existing %s before linking it to %s: %s", sourceDir, targetDir, err)
	}

	// We'll prefer to create a symlink if possible, but we'll fall back to
	// a recursive copy if symlink creation fails. It could fail for a number
	// of reasons, including being on Windows 8 without administrator
	// privileges or being on a legacy filesystem like FAT that has no way
	// to represent a symlink. (Generalized symlink support for Windows was
	// introduced in a Windows 10 minor update.)
	//
	// We use an absolute path for the symlink to reduce the risk of it being
	// broken by moving things around later, since the source directory is
	// likely to be a shared directory independent on any particular target
	// and thus we can't assume that they will move around together.
	linkTarget := absCurrent

	parentDir := filepath.Dir(absNew)
	err = os.MkdirAll(parentDir, 0755)
	if err != nil {
		return nil, fmt.Errorf("failed to create parent directories leading to %s: %s", targetDir, err)
	}

	err = os.Symlink(linkTarget, absNew)
	if err == nil {
		// Success, then!
		return nil, nil
	}

	// If we get down here then symlinking failed and we need a deep copy
	// instead. To make a copy, we first need to create the target directory,
	// which would otherwise be a symlink.
	err = os.Mkdir(absNew, 0755)
	if err != nil && os.IsExist(err) {
		return nil, fmt.Errorf("failed to create directory %s: %s", absNew, err)
	}
	err = copy.CopyDir(absNew, absCurrent)
	if err != nil {
		return nil, fmt.Errorf("failed to either symlink or copy %s to %s: %s", absCurrent, absNew, err)
	}

	// If we got here then apparently our copy succeeded, so we're done.
	return nil, nil
}
<commit_msg>providercache: include host in provider installation error (#31524)<commit_after>package providercache

import (
	"context"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"

	getter "github.com/hashicorp/go-getter"

	"github.com/hashicorp/terraform/internal/copy"
	"github.com/hashicorp/terraform/internal/getproviders"
	"github.com/hashicorp/terraform/internal/httpclient"
)

// We borrow the "unpack a zip file into a target directory" logic from
// go-getter, even though we're not otherwise using go-getter here.
// (We don't need the same flexibility as we have for modules, because
// providers _always_ come from provider registries, which have a very
// specific protocol and set of expectations.)
var unzip = getter.ZipDecompressor{}

func installFromHTTPURL(ctx context.Context, meta getproviders.PackageMeta, targetDir string, allowedHashes []getproviders.Hash) (*getproviders.PackageAuthenticationResult, error) {
	url := meta.Location.String()

	// When we're installing from an HTTP URL we expect the URL to refer to
	// a zip file. We'll fetch that into a temporary file here and then
	// delegate to installFromLocalArchive below to actually extract it.
	// (We're not using go-getter here because its HTTP getter has a bunch
	// of extraneous functionality we don't need or want, like indirection
	// through X-Terraform-Get header, attempting partial fetches for
	// files that already exist, etc.)

	httpClient := httpclient.New()
	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("invalid provider download request: %s", err)
	}
	resp, err := httpClient.Do(req)
	if err != nil {
		if ctx.Err() == context.Canceled {
			// "context canceled" is not a user-friendly error message,
			// so we'll return a more appropriate one here.
			return nil, fmt.Errorf("provider download was interrupted")
		}
		return nil, fmt.Errorf("%s: %w", getproviders.HostFromRequest(req), err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("unsuccessful request to %s: %s", url, resp.Status)
	}

	f, err := ioutil.TempFile("", "terraform-provider")
	if err != nil {
		return nil, fmt.Errorf("failed to open temporary file to download from %s", url)
	}
	defer f.Close()
	defer os.Remove(f.Name())

	// We'll borrow go-getter's "cancelable copy" implementation here so that
	// the download can potentially be interrupted partway through.
	n, err := getter.Copy(ctx, f, resp.Body)
	if err == nil && n < resp.ContentLength {
		err = fmt.Errorf("incorrect response size: expected %d bytes, but got %d bytes", resp.ContentLength, n)
	}
	if err != nil {
		return nil, err
	}

	archiveFilename := f.Name()
	localLocation := getproviders.PackageLocalArchive(archiveFilename)

	var authResult *getproviders.PackageAuthenticationResult
	if meta.Authentication != nil {
		if authResult, err = meta.Authentication.AuthenticatePackage(localLocation); err != nil {
			return authResult, err
		}
	}

	// We can now delegate to installFromLocalArchive for extraction. To do so,
	// we construct a new package meta description using the local archive
	// path as the location, and skipping authentication. installFromLocalMeta
	// is responsible for verifying that the archive matches the allowedHashes,
	// though.
	localMeta := getproviders.PackageMeta{
		Provider:         meta.Provider,
		Version:          meta.Version,
		ProtocolVersions: meta.ProtocolVersions,
		TargetPlatform:   meta.TargetPlatform,
		Filename:         meta.Filename,
		Location:         localLocation,
		Authentication:   nil,
	}
	if _, err := installFromLocalArchive(ctx, localMeta, targetDir, allowedHashes); err != nil {
		return nil, err
	}
	return authResult, nil
}

func installFromLocalArchive(ctx context.Context, meta getproviders.PackageMeta, targetDir string, allowedHashes []getproviders.Hash) (*getproviders.PackageAuthenticationResult, error) {
	var authResult *getproviders.PackageAuthenticationResult
	if meta.Authentication != nil {
		var err error
		if authResult, err = meta.Authentication.AuthenticatePackage(meta.Location); err != nil {
			return nil, err
		}
	}

	if len(allowedHashes) > 0 {
		if matches, err := meta.MatchesAnyHash(allowedHashes); err != nil {
			return authResult, fmt.Errorf(
				"failed to calculate checksum for %s %s package at %s: %s",
				meta.Provider, meta.Version, meta.Location, err,
			)
		} else if !matches {
			return authResult, fmt.Errorf(
				"the current package for %s %s doesn't match any of the checksums previously recorded in the dependency lock file; for more information: https://www.terraform.io/language/provider-checksum-verification",
				meta.Provider, meta.Version,
			)
		}
	}

	filename := meta.Location.String()

	err := unzip.Decompress(targetDir, filename, true, 0000)
	if err != nil {
		return authResult, err
	}

	return authResult, nil
}

// installFromLocalDir is the implementation of both installing a package from
// a local directory source _and_ of linking a package from another cache
// in LinkFromOtherCache, because they both do fundamentally the same
// operation: symlink if possible, or deep-copy otherwise.
func installFromLocalDir(ctx context.Context, meta getproviders.PackageMeta, targetDir string, allowedHashes []getproviders.Hash) (*getproviders.PackageAuthenticationResult, error) {
	sourceDir := meta.Location.String()

	absNew, err := filepath.Abs(targetDir)
	if err != nil {
		return nil, fmt.Errorf("failed to make target path %s absolute: %s", targetDir, err)
	}
	absCurrent, err := filepath.Abs(sourceDir)
	if err != nil {
		return nil, fmt.Errorf("failed to make source path %s absolute: %s", sourceDir, err)
	}

	// Before we do anything else, we'll do a quick check to make sure that
	// these two paths are not pointing at the same physical directory on
	// disk. This compares the files by their OS-level device and directory
	// entry identifiers, not by their virtual filesystem paths.
	if same, err := copy.SameFile(absNew, absCurrent); same {
		return nil, fmt.Errorf("cannot install existing provider directory %s to itself", targetDir)
	} else if err != nil {
		return nil, fmt.Errorf("failed to determine if %s and %s are the same: %s", sourceDir, targetDir, err)
	}

	var authResult *getproviders.PackageAuthenticationResult
	if meta.Authentication != nil {
		// (we have this here for completeness but note that local filesystem
		// mirrors typically don't include enough information for package
		// authentication and so we'll rarely get in here in practice.)
		var err error
		if authResult, err = meta.Authentication.AuthenticatePackage(meta.Location); err != nil {
			return nil, err
		}
	}

	// If the caller provided at least one hash in allowedHashes then at
	// least one of those hashes ought to match. However, for local directories
	// in particular we can't actually verify the legacy "zh:" hash scheme
	// because it requires access to the original .zip archive, and so as a
	// measure of pragmatism we'll treat a set of hashes where all are "zh:"
	// the same as no hashes at all, and let anything pass. This is definitely
	// non-ideal but accepted for two reasons:
	// - Packages we find on local disk can be considered a little more trusted
	//   than packages coming from over the network, because we assume that
	//   they were either placed intentionally by an operator or they were
	//   automatically installed by a previous network operation that would've
	//   itself verified the hashes.
	// - Our installer makes a concerted effort to record at least one new-style
	//   hash for each lock entry, so we should very rarely end up in this
	//   situation anyway.
	suitableHashCount := 0
	for _, hash := range allowedHashes {
		if !hash.HasScheme(getproviders.HashSchemeZip) {
			suitableHashCount++
		}
	}
	if suitableHashCount > 0 {
		if matches, err := meta.MatchesAnyHash(allowedHashes); err != nil {
			return authResult, fmt.Errorf(
				"failed to calculate checksum for %s %s package at %s: %s",
				meta.Provider, meta.Version, meta.Location, err,
			)
		} else if !matches {
			return authResult, fmt.Errorf(
				"the local package for %s %s doesn't match any of the checksums previously recorded in the dependency lock file (this might be because the available checksums are for packages targeting different platforms); for more information: https://www.terraform.io/language/provider-checksum-verification",
				meta.Provider, meta.Version,
			)
		}
	}

	// Delete anything that's already present at this path first.
	err = os.RemoveAll(targetDir)
	if err != nil && !os.IsNotExist(err) {
		return nil, fmt.Errorf("failed to remove existing %s before linking it to %s: %s", sourceDir, targetDir, err)
	}

	// We'll prefer to create a symlink if possible, but we'll fall back to
	// a recursive copy if symlink creation fails. It could fail for a number
	// of reasons, including being on Windows 8 without administrator
	// privileges or being on a legacy filesystem like FAT that has no way
	// to represent a symlink. (Generalized symlink support for Windows was
	// introduced in a Windows 10 minor update.)
	//
	// We use an absolute path for the symlink to reduce the risk of it being
	// broken by moving things around later, since the source directory is
	// likely to be a shared directory independent on any particular target
	// and thus we can't assume that they will move around together.
	linkTarget := absCurrent

	parentDir := filepath.Dir(absNew)
	err = os.MkdirAll(parentDir, 0755)
	if err != nil {
		return nil, fmt.Errorf("failed to create parent directories leading to %s: %s", targetDir, err)
	}

	err = os.Symlink(linkTarget, absNew)
	if err == nil {
		// Success, then!
		return nil, nil
	}

	// If we get down here then symlinking failed and we need a deep copy
	// instead. To make a copy, we first need to create the target directory,
	// which would otherwise be a symlink.
	err = os.Mkdir(absNew, 0755)
	if err != nil && os.IsExist(err) {
		return nil, fmt.Errorf("failed to create directory %s: %s", absNew, err)
	}
	err = copy.CopyDir(absNew, absCurrent)
	if err != nil {
		return nil, fmt.Errorf("failed to either symlink or copy %s to %s: %s", absCurrent, absNew, err)
	}

	// If we got here then apparently our copy succeeded, so we're done.
	return nil, nil
}
<|endoftext|>


<commit_before>package trackermanager

import (
	"context"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"time"

	"github.com/cenkalti/rain/internal/blocklist"
	"github.com/cenkalti/rain/internal/tracker"
	"github.com/cenkalti/rain/internal/tracker/httptracker"
	"github.com/cenkalti/rain/internal/tracker/udptracker"
)

type TrackerManager struct {
	httpTransport *http.Transport
	udpTransport  *udptracker.Transport
}

func New(bl *blocklist.Blocklist) *TrackerManager {
	m := &TrackerManager{
		httpTransport: new(http.Transport),
		udpTransport:  udptracker.NewTransport(bl),
	}
	m.httpTransport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
		ip, port, err := tracker.ResolveHost(ctx, addr, bl)
		if err != nil {
			return nil, err
		}
		var d net.Dialer
		taddr := &net.TCPAddr{IP: ip, Port: port}
		return d.DialContext(ctx, network, taddr.String())
	}
	return m
}

func (m *TrackerManager) Get(s string, httpTimeout time.Duration, httpUserAgent string) (tracker.Tracker, error) {
	u, err := url.Parse(s)
	if err != nil {
		return nil, err
	}
	switch u.Scheme {
	case "http", "https":
		tr := httptracker.New(s, u, httpTimeout, m.httpTransport, httpUserAgent)
		return tr, nil
	case "udp":
		tr := udptracker.New(s, u, m.udpTransport)
		return tr, nil
	default:
		return nil, fmt.Errorf("unsupported tracker scheme: %s", u.Scheme)
	}
}
<commit_msg>disable http/2 in tracker client<commit_after>package trackermanager

import (
	"context"
	"crypto/tls"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"time"

	"github.com/cenkalti/rain/internal/blocklist"
	"github.com/cenkalti/rain/internal/tracker"
	"github.com/cenkalti/rain/internal/tracker/httptracker"
	"github.com/cenkalti/rain/internal/tracker/udptracker"
)

type TrackerManager struct {
	httpTransport *http.Transport
	udpTransport  *udptracker.Transport
}

func New(bl *blocklist.Blocklist) *TrackerManager {
	m := &TrackerManager{
		httpTransport: &http.Transport{
			// Setting TLSNextProto to non-nil map disables HTTP/2 support.
			TLSNextProto: make(map[string]func(string, *tls.Conn) http.RoundTripper),
		},
		udpTransport: udptracker.NewTransport(bl),
	}
	m.httpTransport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
		ip, port, err := tracker.ResolveHost(ctx, addr, bl)
		if err != nil {
			return nil, err
		}
		var d net.Dialer
		taddr := &net.TCPAddr{IP: ip, Port: port}
		return d.DialContext(ctx, network, taddr.String())
	}
	return m
}

func (m *TrackerManager) Get(s string, httpTimeout time.Duration, httpUserAgent string) (tracker.Tracker, error) {
	u, err := url.Parse(s)
	if err != nil {
		return nil, err
	}
	switch u.Scheme {
	case "http", "https":
		tr := httptracker.New(s, u, httpTimeout, m.httpTransport, httpUserAgent)
		return tr, nil
	case "udp":
		tr := udptracker.New(s, u, m.udpTransport)
		return tr, nil
	default:
		return nil, fmt.Errorf("unsupported tracker scheme: %s", u.Scheme)
	}
}
<|endoftext|>


<commit_before>/*
 Copyright 2016 - 2018 Crunchy Data Solutions, Inc.
 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 main

import (
	"bytes"
	"log"
	"net/http"
	"os"
	"os/exec"
)

const REPORT = "/report/index.html"

func init() {
	log.SetOutput(os.Stdout)
	log.Println("BadgerServer starting..")
}

func main() {
	http.HandleFunc("/api/badgergenerate", BadgerGenerate)
	http.Handle("/static/", http.StripPrefix("/static", http.FileServer(http.Dir("/report"))))
	log.Fatal(http.ListenAndServe(":10000", nil))
}

// BadgerGenerate perform a pgbadger to create the HTML output file
func BadgerGenerate(w http.ResponseWriter, r *http.Request) {
	log.Println("Generating report..")

	var cmd *exec.Cmd
	cmd = exec.Command("badger-generate.sh")
	var out bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &stderr
	err := cmd.Run()
	if err != nil {
		log.Fatalf("Error running badger-generate: %s", err)
		return
	}

	log.Println("Report generated.  Redirecting..")
	http.Redirect(w, r, "/static", 301)
}
<commit_msg>Add handler for / in pgbadger http server<commit_after>/*
 Copyright 2016 - 2018 Crunchy Data Solutions, Inc.
 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 main

import (
	"bytes"
	"log"
	"net/http"
	"os"
	"os/exec"
)

const REPORT = "/report/index.html"

func init() {
	log.SetOutput(os.Stdout)
	log.Println("BadgerServer starting..")
}

func main() {
	http.HandleFunc("/api/badgergenerate", BadgerGenerate)
	http.Handle("/static/", http.StripPrefix("/static", http.FileServer(http.Dir("/report"))))
	http.HandleFunc("/", RootPathRedirect)
	log.Fatal(http.ListenAndServe(":10000", nil))
}

// BadgerGenerate perform a pgbadger to create the HTML output file
func BadgerGenerate(w http.ResponseWriter, r *http.Request) {
	log.Println("Generating report..")

	var cmd *exec.Cmd
	cmd = exec.Command("badger-generate.sh")
	var out bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &stderr
	err := cmd.Run()
	if err != nil {
		log.Fatalf("Error running badger-generate: %s", err)
		return
	}

	log.Println("Report generated.  Redirecting..")
	http.Redirect(w, r, "/static", 301)
}

func RootPathRedirect(w http.ResponseWriter, r *http.Request) {
	redirect_url := "/static/"
	if _, err := os.Stat(REPORT); os.IsNotExist(err) {
		redirect_url = "/api/badgergenerate"
	}
	http.Redirect(w, r, redirect_url, 302)
}
<|endoftext|>


<commit_before>package lifecycle

import (
	"github.com/lxc/lxd/lxd/operations"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/version"
)

// Internal copy of the instance interface.
type instance interface {
	Name() string
	Project() string
	Operation() *operations.Operation
}

// InstanceAction represents a lifecycle event action for instances.
type InstanceAction string

// All supported lifecycle events for instances.
const (
	InstanceCreated          = InstanceAction(api.EventLifecycleInstanceCreated)
	InstanceStarted          = InstanceAction(api.EventLifecycleInstanceStarted)
	InstanceStopped          = InstanceAction(api.EventLifecycleInstanceStopped)
	InstanceShutdown         = InstanceAction(api.EventLifecycleInstanceShutdown)
	InstanceRestarted        = InstanceAction(api.EventLifecycleInstanceRestarted)
	InstancePaused           = InstanceAction(api.EventLifecycleInstancePaused)
	InstanceResumed          = InstanceAction(api.EventLifecycleInstanceResumed)
	InstanceRestored         = InstanceAction(api.EventLifecycleInstanceRestored)
	InstanceDeleted          = InstanceAction(api.EventLifecycleInstanceDeleted)
	InstanceRenamed          = InstanceAction(api.EventLifecycleInstanceRenamed)
	InstanceUpdated          = InstanceAction(api.EventLifecycleInstanceUpdated)
	InstanceExec             = InstanceAction(api.EventLifecycleInstanceExec)
	InstanceConsole          = InstanceAction(api.EventLifecycleInstanceConsole)
	InstanceConsoleRetrieved = InstanceAction(api.EventLifecycleInstanceConsoleRetrieved)
	InstanceConsoleReset     = InstanceAction(api.EventLifecycleInstanceConsoleReset)
	InstanceFileRetrieved    = InstanceAction(api.EventLifecycleInstanceFileRetrieved)
	InstanceFilePushed       = InstanceAction(api.EventLifecycleInstanceFilePushed)
	InstanceFileDeleted      = InstanceAction(api.EventLifecycleInstanceFileDeleted)
)

// Event creates the lifecycle event for an action on an instance.
func (a InstanceAction) Event(inst instance, ctx map[string]any) api.EventLifecycle {
	url := api.NewURL().Path(version.APIVersion, "instances", inst.Name()).Project(inst.Project())

	var requestor *api.EventLifecycleRequestor
	if inst.Operation() != nil {
		requestor = inst.Operation().Requestor()
	}

	return api.EventLifecycle{
		Action:    string(a),
		Source:    url.String(),
		Context:   ctx,
		Requestor: requestor,
	}
}
<commit_msg>lxd/lifecycle: Add InstanceReady lifecycle event<commit_after>package lifecycle

import (
	"github.com/lxc/lxd/lxd/operations"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/version"
)

// Internal copy of the instance interface.
type instance interface {
	Name() string
	Project() string
	Operation() *operations.Operation
}

// InstanceAction represents a lifecycle event action for instances.
type InstanceAction string

// All supported lifecycle events for instances.
const (
	InstanceCreated          = InstanceAction(api.EventLifecycleInstanceCreated)
	InstanceStarted          = InstanceAction(api.EventLifecycleInstanceStarted)
	InstanceStopped          = InstanceAction(api.EventLifecycleInstanceStopped)
	InstanceShutdown         = InstanceAction(api.EventLifecycleInstanceShutdown)
	InstanceRestarted        = InstanceAction(api.EventLifecycleInstanceRestarted)
	InstancePaused           = InstanceAction(api.EventLifecycleInstancePaused)
	InstanceReady            = InstanceAction(api.EventLifecycleInstanceReady)
	InstanceResumed          = InstanceAction(api.EventLifecycleInstanceResumed)
	InstanceRestored         = InstanceAction(api.EventLifecycleInstanceRestored)
	InstanceDeleted          = InstanceAction(api.EventLifecycleInstanceDeleted)
	InstanceRenamed          = InstanceAction(api.EventLifecycleInstanceRenamed)
	InstanceUpdated          = InstanceAction(api.EventLifecycleInstanceUpdated)
	InstanceExec             = InstanceAction(api.EventLifecycleInstanceExec)
	InstanceConsole          = InstanceAction(api.EventLifecycleInstanceConsole)
	InstanceConsoleRetrieved = InstanceAction(api.EventLifecycleInstanceConsoleRetrieved)
	InstanceConsoleReset     = InstanceAction(api.EventLifecycleInstanceConsoleReset)
	InstanceFileRetrieved    = InstanceAction(api.EventLifecycleInstanceFileRetrieved)
	InstanceFilePushed       = InstanceAction(api.EventLifecycleInstanceFilePushed)
	InstanceFileDeleted      = InstanceAction(api.EventLifecycleInstanceFileDeleted)
)

// Event creates the lifecycle event for an action on an instance.
func (a InstanceAction) Event(inst instance, ctx map[string]any) api.EventLifecycle {
	url := api.NewURL().Path(version.APIVersion, "instances", inst.Name()).Project(inst.Project())

	var requestor *api.EventLifecycleRequestor
	if inst.Operation() != nil {
		requestor = inst.Operation().Requestor()
	}

	return api.EventLifecycle{
		Action:    string(a),
		Source:    url.String(),
		Context:   ctx,
		Requestor: requestor,
	}
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package validators

import (
	"math"
	"testing"

	"github.com/ava-labs/gecko/ids"
)

func TestSamplerSample(t *testing.T) {
	vdr0 := GenerateRandomValidator(1)
	vdr1 := GenerateRandomValidator(math.MaxInt64 - 1)

	s := NewSet()
	s.Add(vdr0)

	if sampled := s.Sample(1); len(sampled) != 1 {
		t.Fatalf("Should have sampled 1 validator")
	} else if !sampled[0].ID().Equals(vdr0.ID()) {
		t.Fatalf("Should have sampled vdr0")
	} else if s.Len() != 1 {
		t.Fatalf("Wrong size")
	}

	s.Add(vdr1)

	if sampled := s.Sample(1); len(sampled) != 1 {
		t.Fatalf("Should have sampled 1 validator")
	} else if !sampled[0].ID().Equals(vdr1.ID()) {
		t.Fatalf("Should have sampled vdr1")
	} else if s.Len() != 2 {
		t.Fatalf("Wrong size")
	}

	if sampled := s.Sample(2); len(sampled) != 2 {
		t.Fatalf("Should have sampled 2 validators")
	} else if !sampled[1].ID().Equals(vdr0.ID()) {
		t.Fatalf("Should have sampled vdr0")
	} else if !sampled[0].ID().Equals(vdr1.ID()) {
		t.Fatalf("Should have sampled vdr1")
	}

	if sampled := s.Sample(3); len(sampled) != 2 {
		t.Fatalf("Should have sampled 2 validators")
	} else if !sampled[1].ID().Equals(vdr0.ID()) {
		t.Fatalf("Should have sampled vdr0")
	} else if !sampled[0].ID().Equals(vdr1.ID()) {
		t.Fatalf("Should have sampled vdr1")
	}

	if list := s.List(); len(list) != 2 {
		t.Fatalf("Should have returned 2 validators")
	} else if !list[0].ID().Equals(vdr0.ID()) {
		t.Fatalf("Should have returned vdr0")
	} else if !list[1].ID().Equals(vdr1.ID()) {
		t.Fatalf("Should have returned vdr1")
	}
}

func TestSamplerDuplicate(t *testing.T) {
	vdr0 := GenerateRandomValidator(1)
	vdr1_0 := GenerateRandomValidator(math.MaxInt64 - 1)
	vdr1_1 := NewValidator(vdr1_0.ID(), 0)

	s := NewSet()
	s.Add(vdr0)
	s.Add(vdr1_0)

	if sampled := s.Sample(1); len(sampled) != 1 {
		t.Fatalf("Should have sampled 1 validator")
	} else if !sampled[0].ID().Equals(vdr1_0.ID()) {
		t.Fatalf("Should have sampled vdr1")
	}

	s.Add(vdr1_1)

	if sampled := s.Sample(1); len(sampled) != 1 {
		t.Fatalf("Should have sampled 1 validator")
	} else if !sampled[0].ID().Equals(vdr0.ID()) {
		t.Fatalf("Should have sampled vdr0")
	}

	if sampled := s.Sample(2); len(sampled) != 1 {
		t.Fatalf("Should have only sampled 1 validator")
	} else if !sampled[0].ID().Equals(vdr0.ID()) {
		t.Fatalf("Should have sampled vdr0")
	}

	s.Remove(vdr1_1.ID())

	if sampled := s.Sample(2); len(sampled) != 1 {
		t.Fatalf("Should have only sampled 1 validator")
	} else if !sampled[0].ID().Equals(vdr0.ID()) {
		t.Fatalf("Should have sampled vdr0")
	}
}

func TestSamplerSimple(t *testing.T) {
	vdr := GenerateRandomValidator(1)

	s := NewSet()
	s.Add(vdr)

	if sampled := s.Sample(1); len(sampled) != 1 {
		t.Fatalf("Should have sampled 1 validator")
	}
}

func TestSamplerContains(t *testing.T) {
	vdr := GenerateRandomValidator(1)

	s := NewSet()
	s.Add(vdr)

	if !s.Contains(vdr.ID()) {
		t.Fatalf("Should have contained validator")
	}

	s.Remove(vdr.ID())

	if s.Contains(vdr.ID()) {
		t.Fatalf("Shouldn't have contained validator")
	}
}

func TestSamplerString(t *testing.T) {
	vdr0 := NewValidator(ids.ShortEmpty, 1)
	vdr1 := NewValidator(
		ids.NewShortID([20]byte{
			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		}),
		math.MaxInt64-1,
	)

	s := NewSet()
	s.Add(vdr0)
	s.Add(vdr1)

	expected := "Validator Set: (Size = 2)\n" +
		"    Validator[0]:        111111111111111111116DBWJs, 1\n" +
		"    Validator[1]: QLbz7JHiBTspS962RLKV8GndWFwdYhk6V, 9223372036854775806"
	if str := s.String(); str != expected {
		t.Fatalf("Got:\n%s\nExpected:\n%s", str, expected)
	}
}
<commit_msg>snow: Add test for validators.Set.Set<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package validators

import (
	"math"
	"testing"

	"github.com/ava-labs/gecko/ids"
)

func TestSetSet(t *testing.T) {
	vdr0 := NewValidator(ids.ShortEmpty, 1)
	vdr1_0 := NewValidator(ids.NewShortID([20]byte{0xFF}), 1)
	// Should replace vdr1_0, because later additions replace earlier ones
	vdr1_1 := NewValidator(ids.NewShortID([20]byte{0xFF}), math.MaxInt64-1)
	// Should be discarded, because it has a weight of 0
	vdr2 := NewValidator(ids.NewShortID([20]byte{0xAA}), 0)

	s := NewSet()
	s.Set([]Validator{vdr0, vdr1_0, vdr1_1, vdr2})

	if !s.Contains(vdr0.ID()) {
		t.Fatal("Should have contained vdr0", vdr0.ID())
	}
	if !s.Contains(vdr1_0.ID()) {
		t.Fatal("Should have contained vdr1", vdr1_0.ID())
	}
	if sampled := s.Sample(1); !sampled[0].ID().Equals(vdr1_0.ID()) {
		t.Fatal("Should have sampled vdr1")
	}
	if len := s.Len(); len != 2 {
		t.Fatalf("Got size %d, expected 2", len)
	}
}

func TestSamplerSample(t *testing.T) {
	vdr0 := GenerateRandomValidator(1)
	vdr1 := GenerateRandomValidator(math.MaxInt64 - 1)

	s := NewSet()
	s.Add(vdr0)

	if sampled := s.Sample(1); len(sampled) != 1 {
		t.Fatalf("Should have sampled 1 validator")
	} else if !sampled[0].ID().Equals(vdr0.ID()) {
		t.Fatalf("Should have sampled vdr0")
	} else if s.Len() != 1 {
		t.Fatalf("Wrong size")
	}

	s.Add(vdr1)

	if sampled := s.Sample(1); len(sampled) != 1 {
		t.Fatalf("Should have sampled 1 validator")
	} else if !sampled[0].ID().Equals(vdr1.ID()) {
		t.Fatalf("Should have sampled vdr1")
	} else if s.Len() != 2 {
		t.Fatalf("Wrong size")
	}

	if sampled := s.Sample(2); len(sampled) != 2 {
		t.Fatalf("Should have sampled 2 validators")
	} else if !sampled[1].ID().Equals(vdr0.ID()) {
		t.Fatalf("Should have sampled vdr0")
	} else if !sampled[0].ID().Equals(vdr1.ID()) {
		t.Fatalf("Should have sampled vdr1")
	}

	if sampled := s.Sample(3); len(sampled) != 2 {
		t.Fatalf("Should have sampled 2 validators")
	} else if !sampled[1].ID().Equals(vdr0.ID()) {
		t.Fatalf("Should have sampled vdr0")
	} else if !sampled[0].ID().Equals(vdr1.ID()) {
		t.Fatalf("Should have sampled vdr1")
	}

	if list := s.List(); len(list) != 2 {
		t.Fatalf("Should have returned 2 validators")
	} else if !list[0].ID().Equals(vdr0.ID()) {
		t.Fatalf("Should have returned vdr0")
	} else if !list[1].ID().Equals(vdr1.ID()) {
		t.Fatalf("Should have returned vdr1")
	}
}

func TestSamplerDuplicate(t *testing.T) {
	vdr0 := GenerateRandomValidator(1)
	vdr1_0 := GenerateRandomValidator(math.MaxInt64 - 1)
	vdr1_1 := NewValidator(vdr1_0.ID(), 0)

	s := NewSet()
	s.Add(vdr0)
	s.Add(vdr1_0)

	if sampled := s.Sample(1); len(sampled) != 1 {
		t.Fatalf("Should have sampled 1 validator")
	} else if !sampled[0].ID().Equals(vdr1_0.ID()) {
		t.Fatalf("Should have sampled vdr1")
	}

	s.Add(vdr1_1)

	if sampled := s.Sample(1); len(sampled) != 1 {
		t.Fatalf("Should have sampled 1 validator")
	} else if !sampled[0].ID().Equals(vdr0.ID()) {
		t.Fatalf("Should have sampled vdr0")
	}

	if sampled := s.Sample(2); len(sampled) != 1 {
		t.Fatalf("Should have only sampled 1 validator")
	} else if !sampled[0].ID().Equals(vdr0.ID()) {
		t.Fatalf("Should have sampled vdr0")
	}

	s.Remove(vdr1_1.ID())

	if sampled := s.Sample(2); len(sampled) != 1 {
		t.Fatalf("Should have only sampled 1 validator")
	} else if !sampled[0].ID().Equals(vdr0.ID()) {
		t.Fatalf("Should have sampled vdr0")
	}
}

func TestSamplerSimple(t *testing.T) {
	vdr := GenerateRandomValidator(1)

	s := NewSet()
	s.Add(vdr)

	if sampled := s.Sample(1); len(sampled) != 1 {
		t.Fatalf("Should have sampled 1 validator")
	}
}

func TestSamplerContains(t *testing.T) {
	vdr := GenerateRandomValidator(1)

	s := NewSet()
	s.Add(vdr)

	if !s.Contains(vdr.ID()) {
		t.Fatalf("Should have contained validator")
	}

	s.Remove(vdr.ID())

	if s.Contains(vdr.ID()) {
		t.Fatalf("Shouldn't have contained validator")
	}
}

func TestSamplerString(t *testing.T) {
	vdr0 := NewValidator(ids.ShortEmpty, 1)
	vdr1 := NewValidator(
		ids.NewShortID([20]byte{
			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		}),
		math.MaxInt64-1,
	)

	s := NewSet()
	s.Add(vdr0)
	s.Add(vdr1)

	expected := "Validator Set: (Size = 2)\n" +
		"    Validator[0]:        111111111111111111116DBWJs, 1\n" +
		"    Validator[1]: QLbz7JHiBTspS962RLKV8GndWFwdYhk6V, 9223372036854775806"
	if str := s.String(); str != expected {
		t.Fatalf("Got:\n%s\nExpected:\n%s", str, expected)
	}
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "time"
import "bitbucket.org/davidwallace/go-opc/colorutils"
import "github.com/davecheney/profile"

func main() {

	defer profile.Start(profile.CPUProfile).Stop()

	const N_PIXELS = 1000
	var array = make([]byte, N_PIXELS*3)

	var pct, r, g, b, t float64
	var last_print = float64(time.Now().UnixNano()) / 1.0e9
	var frames = 0
	var start_time = last_print
	t = start_time
	for t < start_time+5 {
		t = float64(time.Now().UnixNano()) / 1.0e9
		frames += 1
		if t > last_print+1 {
			last_print = t
			fmt.Printf("%f ms (%d fps)\n", 1000.0/float64(frames), frames)
			frames = 0
		}
		for ii := 0; ii < N_PIXELS; ii++ {
			pct = float64(ii) / N_PIXELS

			r = pct
			g = pct
			b = pct

			array[ii*3+0] = colorutils.FloatToByte(r)
			array[ii*3+1] = colorutils.FloatToByte(g)
			array[ii*3+2] = colorutils.FloatToByte(b)
		}

		//for ii, v := range array {
		//    fmt.Printf("array[%d] = %d\n", ii, v)
		//}
	}

}
<commit_msg>Read from layout json file<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"
	"github.com/davecheney/profile"
	"bitbucket.org/davidwallace/go-opc/colorutils"
)

// read locations from JSON file into a slice of floats
func readLocations(fn string) []float64 {
	locations := make([]float64, 0)
	var file *os.File
	var err error
	if file, err = os.Open(fn); err != nil {
		panic(fmt.Sprintf("could not open layout file: %s", fn))
	}
	defer file.Close()
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		if len(line) == 0 || line[0] == '[' || line[0] == ']' {
			continue
		}
		line = strings.Split(line, "[")[1]
		line = strings.Split(line, "]")[0]
		coordStrings := strings.Split(line, ", ")
		var x, y, z float64
		x, err = strconv.ParseFloat(coordStrings[0], 64)
		y, err = strconv.ParseFloat(coordStrings[1], 64)
		z, err = strconv.ParseFloat(coordStrings[2], 64)
		locations = append(locations, x, y, z)
	}
	fmt.Printf("Read %v pixel locations from %s\n", len(locations), fn)
	return locations
}

func main() {
	defer profile.Start(profile.CPUProfile).Stop()

	path := "circle.json"

	LOCATIONS := readLocations(path)
	N_PIXELS := len(LOCATIONS) / 3
	VALUES := make([]byte, N_PIXELS*3)

	// fill in values over and over
	var pct, r, g, b, t float64
	var last_print = float64(time.Now().UnixNano()) / 1.0e9
	var frames = 0
	var start_time = last_print
	t = start_time
	for t < start_time+5 {
		t = float64(time.Now().UnixNano()) / 1.0e9
		frames += 1
		if t > last_print+1 {
			last_print = t
			fmt.Printf("%f ms (%d fps)\n", 1000.0/float64(frames), frames)
			frames = 0
		}
		for ii := 0; ii < N_PIXELS; ii++ {
			pct = float64(ii) / float64(N_PIXELS)

			r = pct
			g = pct
			b = pct

			VALUES[ii*3+0] = colorutils.FloatToByte(r)
			VALUES[ii*3+1] = colorutils.FloatToByte(g)
			VALUES[ii*3+2] = colorutils.FloatToByte(b)
		}

		//for ii, v := range VALUES {
		//    fmt.Printf("VALUES[%d] = %d\n", ii, v)
		//}
	}

}
<|endoftext|>


<commit_before>package main

type Ops struct {
	Config  string
	Root    string
	Type    string
	Delay   int
	Verbose bool
	Version bool
}
<commit_msg>update Opt struct<commit_after>package main

// Ops structure
type Ops struct {
	Config   string
	Root     string
	Type     string
	Addr     string
	Delay    int
	Loglevel string
	Version  bool
}
<|endoftext|>


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

package cmd

import (
	"bufio"
	"bytes"
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"code.gitea.io/git"
	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/private"
	"code.gitea.io/gitea/modules/setting"

	"github.com/urfave/cli"
)

var (
	// CmdHook represents the available hooks sub-command.
	CmdHook = cli.Command{
		Name:        "hook",
		Usage:       "Delegate commands to corresponding Git hooks",
		Description: "This should only be called by Git",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "config, c",
				Value: "custom/conf/app.ini",
				Usage: "Custom configuration file path",
			},
		},
		Subcommands: []cli.Command{
			subcmdHookPreReceive,
			subcmdHookUpdate,
			subcmdHookPostReceive,
		},
	}

	subcmdHookPreReceive = cli.Command{
		Name:        "pre-receive",
		Usage:       "Delegate pre-receive Git hook",
		Description: "This command should only be called by Git",
		Action:      runHookPreReceive,
	}
	subcmdHookUpdate = cli.Command{
		Name:        "update",
		Usage:       "Delegate update Git hook",
		Description: "This command should only be called by Git",
		Action:      runHookUpdate,
	}
	subcmdHookPostReceive = cli.Command{
		Name:        "post-receive",
		Usage:       "Delegate post-receive Git hook",
		Description: "This command should only be called by Git",
		Action:      runHookPostReceive,
	}
)

func hookSetup(logPath string) {
	setting.NewContext()
	log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
	models.LoadConfigs()
}

func runHookPreReceive(c *cli.Context) error {
	if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
		return nil
	}

	if c.IsSet("config") {
		setting.CustomConf = c.String("config")
	} else if c.GlobalIsSet("config") {
		setting.CustomConf = c.GlobalString("config")
	}

	hookSetup("hooks/pre-receive.log")

	// the environment setted on serv command
	repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64)
	isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
	username := os.Getenv(models.EnvRepoUsername)
	reponame := os.Getenv(models.EnvRepoName)
	userIDStr := os.Getenv(models.EnvPusherID)
	repoPath := models.RepoPath(username, reponame)

	buf := bytes.NewBuffer(nil)
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		buf.Write(scanner.Bytes())
		buf.WriteByte('\n')

		// TODO: support news feeds for wiki
		if isWiki {
			continue
		}

		fields := bytes.Fields(scanner.Bytes())
		if len(fields) != 3 {
			continue
		}

		oldCommitID := string(fields[0])
		newCommitID := string(fields[1])
		refFullName := string(fields[2])

		branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
		protectBranch, err := private.GetProtectedBranchBy(repoID, branchName)
		if err != nil {
			log.GitLogger.Fatal(2, "retrieve protected branches information failed")
		}

		if protectBranch != nil && protectBranch.IsProtected() {
			// detect force push
			if git.EmptySHA != oldCommitID {
				output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDir(repoPath)
				if err != nil {
					fail("Internal error", "Fail to detect force push: %v", err)
				} else if len(output) > 0 {
					fail(fmt.Sprintf("branch %s is protected from force push", branchName), "")
				}
			}

			// check and deletion
			if newCommitID == git.EmptySHA {
				fail(fmt.Sprintf("branch %s is protected from deletion", branchName), "")
			} else {
				userID, _ := strconv.ParseInt(userIDStr, 10, 64)
				canPush, err := private.CanUserPush(protectBranch.ID, userID)
				if err != nil {
					fail("Internal error", "Fail to detect user can push: %v", err)
				} else if !canPush {
					fail(fmt.Sprintf("protected branch %s can not be pushed to", branchName), "")
				}
			}
		}
	}

	return nil
}

func runHookUpdate(c *cli.Context) error {
	if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
		return nil
	}

	if c.IsSet("config") {
		setting.CustomConf = c.String("config")
	} else if c.GlobalIsSet("config") {
		setting.CustomConf = c.GlobalString("config")
	}

	hookSetup("hooks/update.log")

	return nil
}

func runHookPostReceive(c *cli.Context) error {
	if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
		return nil
	}

	if c.IsSet("config") {
		setting.CustomConf = c.String("config")
	} else if c.GlobalIsSet("config") {
		setting.CustomConf = c.GlobalString("config")
	}

	hookSetup("hooks/post-receive.log")

	// the environment setted on serv command
	repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64)
	repoUser := os.Getenv(models.EnvRepoUsername)
	isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
	repoName := os.Getenv(models.EnvRepoName)
	pusherID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
	pusherName := os.Getenv(models.EnvPusherName)

	buf := bytes.NewBuffer(nil)
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		buf.Write(scanner.Bytes())
		buf.WriteByte('\n')

		// TODO: support news feeds for wiki
		if isWiki {
			continue
		}

		fields := bytes.Fields(scanner.Bytes())
		if len(fields) != 3 {
			continue
		}

		oldCommitID := string(fields[0])
		newCommitID := string(fields[1])
		refFullName := string(fields[2])

		if err := private.PushUpdate(models.PushUpdateOptions{
			RefFullName:  refFullName,
			OldCommitID:  oldCommitID,
			NewCommitID:  newCommitID,
			PusherID:     pusherID,
			PusherName:   pusherName,
			RepoUserName: repoUser,
			RepoName:     repoName,
		}); err != nil {
			log.GitLogger.Error(2, "Update: %v", err)
		}

		if strings.HasPrefix(refFullName, git.BranchPrefix) {
			branch := strings.TrimPrefix(refFullName, git.BranchPrefix)
			repo, pullRequestAllowed, err := private.GetRepository(repoID)
			if err != nil {
				log.GitLogger.Error(2, "get repo: %v", err)
				break
			}
			if !pullRequestAllowed {
				break
			}

			baseRepo := repo
			if repo.IsFork {
				baseRepo = repo.BaseRepo
			}

			if !repo.IsFork && branch == baseRepo.DefaultBranch {
				break
			}

			pr, err := private.ActivePullRequest(baseRepo.ID, repo.ID, baseRepo.DefaultBranch, branch)
			if err != nil {
				log.GitLogger.Error(2, "get active pr: %v", err)
				break
			}

			fmt.Fprintln(os.Stderr, "")
			if pr == nil {
				if repo.IsFork {
					branch = fmt.Sprintf("%s:%s", repo.OwnerName, branch)
				}
				fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", branch)
				fmt.Fprintf(os.Stderr, "  %s/compare/%s...%s\n", baseRepo.HTMLURL(), url.QueryEscape(baseRepo.DefaultBranch), url.QueryEscape(branch))
			} else {
				fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
				fmt.Fprintf(os.Stderr, "  %s/pulls/%d\n", baseRepo.HTMLURL(), pr.Index)
			}
			fmt.Fprintln(os.Stderr, "")
		}

	}

	return nil
}
<commit_msg>fix showing pull request link when delete a branch (#5166)<commit_after>// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package cmd

import (
	"bufio"
	"bytes"
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"code.gitea.io/git"
	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/private"
	"code.gitea.io/gitea/modules/setting"

	"github.com/urfave/cli"
)

var (
	// CmdHook represents the available hooks sub-command.
	CmdHook = cli.Command{
		Name:        "hook",
		Usage:       "Delegate commands to corresponding Git hooks",
		Description: "This should only be called by Git",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "config, c",
				Value: "custom/conf/app.ini",
				Usage: "Custom configuration file path",
			},
		},
		Subcommands: []cli.Command{
			subcmdHookPreReceive,
			subcmdHookUpdate,
			subcmdHookPostReceive,
		},
	}

	subcmdHookPreReceive = cli.Command{
		Name:        "pre-receive",
		Usage:       "Delegate pre-receive Git hook",
		Description: "This command should only be called by Git",
		Action:      runHookPreReceive,
	}
	subcmdHookUpdate = cli.Command{
		Name:        "update",
		Usage:       "Delegate update Git hook",
		Description: "This command should only be called by Git",
		Action:      runHookUpdate,
	}
	subcmdHookPostReceive = cli.Command{
		Name:        "post-receive",
		Usage:       "Delegate post-receive Git hook",
		Description: "This command should only be called by Git",
		Action:      runHookPostReceive,
	}
)

func hookSetup(logPath string) {
	setting.NewContext()
	log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
	models.LoadConfigs()
}

func runHookPreReceive(c *cli.Context) error {
	if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
		return nil
	}

	if c.IsSet("config") {
		setting.CustomConf = c.String("config")
	} else if c.GlobalIsSet("config") {
		setting.CustomConf = c.GlobalString("config")
	}

	hookSetup("hooks/pre-receive.log")

	// the environment setted on serv command
	repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64)
	isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
	username := os.Getenv(models.EnvRepoUsername)
	reponame := os.Getenv(models.EnvRepoName)
	userIDStr := os.Getenv(models.EnvPusherID)
	repoPath := models.RepoPath(username, reponame)

	buf := bytes.NewBuffer(nil)
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		buf.Write(scanner.Bytes())
		buf.WriteByte('\n')

		// TODO: support news feeds for wiki
		if isWiki {
			continue
		}

		fields := bytes.Fields(scanner.Bytes())
		if len(fields) != 3 {
			continue
		}

		oldCommitID := string(fields[0])
		newCommitID := string(fields[1])
		refFullName := string(fields[2])

		branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
		protectBranch, err := private.GetProtectedBranchBy(repoID, branchName)
		if err != nil {
			log.GitLogger.Fatal(2, "retrieve protected branches information failed")
		}

		if protectBranch != nil && protectBranch.IsProtected() {
			// detect force push
			if git.EmptySHA != oldCommitID {
				output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDir(repoPath)
				if err != nil {
					fail("Internal error", "Fail to detect force push: %v", err)
				} else if len(output) > 0 {
					fail(fmt.Sprintf("branch %s is protected from force push", branchName), "")
				}
			}

			// check and deletion
			if newCommitID == git.EmptySHA {
				fail(fmt.Sprintf("branch %s is protected from deletion", branchName), "")
			} else {
				userID, _ := strconv.ParseInt(userIDStr, 10, 64)
				canPush, err := private.CanUserPush(protectBranch.ID, userID)
				if err != nil {
					fail("Internal error", "Fail to detect user can push: %v", err)
				} else if !canPush {
					fail(fmt.Sprintf("protected branch %s can not be pushed to", branchName), "")
				}
			}
		}
	}

	return nil
}

func runHookUpdate(c *cli.Context) error {
	if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
		return nil
	}

	if c.IsSet("config") {
		setting.CustomConf = c.String("config")
	} else if c.GlobalIsSet("config") {
		setting.CustomConf = c.GlobalString("config")
	}

	hookSetup("hooks/update.log")

	return nil
}

func runHookPostReceive(c *cli.Context) error {
	if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
		return nil
	}

	if c.IsSet("config") {
		setting.CustomConf = c.String("config")
	} else if c.GlobalIsSet("config") {
		setting.CustomConf = c.GlobalString("config")
	}

	hookSetup("hooks/post-receive.log")

	// the environment setted on serv command
	repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64)
	repoUser := os.Getenv(models.EnvRepoUsername)
	isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
	repoName := os.Getenv(models.EnvRepoName)
	pusherID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
	pusherName := os.Getenv(models.EnvPusherName)

	buf := bytes.NewBuffer(nil)
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		buf.Write(scanner.Bytes())
		buf.WriteByte('\n')

		// TODO: support news feeds for wiki
		if isWiki {
			continue
		}

		fields := bytes.Fields(scanner.Bytes())
		if len(fields) != 3 {
			continue
		}

		oldCommitID := string(fields[0])
		newCommitID := string(fields[1])
		refFullName := string(fields[2])

		if err := private.PushUpdate(models.PushUpdateOptions{
			RefFullName:  refFullName,
			OldCommitID:  oldCommitID,
			NewCommitID:  newCommitID,
			PusherID:     pusherID,
			PusherName:   pusherName,
			RepoUserName: repoUser,
			RepoName:     repoName,
		}); err != nil {
			log.GitLogger.Error(2, "Update: %v", err)
		}

		if newCommitID != git.EmptySHA && strings.HasPrefix(refFullName, git.BranchPrefix) {
			branch := strings.TrimPrefix(refFullName, git.BranchPrefix)
			repo, pullRequestAllowed, err := private.GetRepository(repoID)
			if err != nil {
				log.GitLogger.Error(2, "get repo: %v", err)
				break
			}
			if !pullRequestAllowed {
				break
			}

			baseRepo := repo
			if repo.IsFork {
				baseRepo = repo.BaseRepo
			}

			if !repo.IsFork && branch == baseRepo.DefaultBranch {
				break
			}

			pr, err := private.ActivePullRequest(baseRepo.ID, repo.ID, baseRepo.DefaultBranch, branch)
			if err != nil {
				log.GitLogger.Error(2, "get active pr: %v", err)
				break
			}

			fmt.Fprintln(os.Stderr, "")
			if pr == nil {
				if repo.IsFork {
					branch = fmt.Sprintf("%s:%s", repo.OwnerName, branch)
				}
				fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", branch)
				fmt.Fprintf(os.Stderr, "  %s/compare/%s...%s\n", baseRepo.HTMLURL(), url.QueryEscape(baseRepo.DefaultBranch), url.QueryEscape(branch))
			} else {
				fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
				fmt.Fprintf(os.Stderr, "  %s/pulls/%d\n", baseRepo.HTMLURL(), pr.Index)
			}
			fmt.Fprintln(os.Stderr, "")
		}

	}

	return nil
}
<|endoftext|>


<commit_before>package manifest

import (
	"code.cloudfoundry.org/cli/plugin/models"
	"github.com/cloudfoundry-incubator/candiedyaml"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Manifest", func() {

	Context("For a manifest with no applications section", func() {

		input := map[string]interface{}{
			"host": "bob",
			"routes": []interface{}{
				map[interface{}]interface{}{"route": "example.com"},
				map[interface{}]interface{}{"route": "www.example.com/foo"},
				map[interface{}]interface{}{"route": "tcp-example.com:1234"},
			},
		}
		m := &Manifest{}

		Context("the getAppMaps function", func() {
			appMaps, err := m.getAppMaps(input)
			It("does not error", func() {
				Expect(err).To(BeNil())
			})

			It("should return one entry", func() {
				Expect(len(appMaps)).To(Equal(1))
			})

			It("should return global properties", func() {
				Expect(appMaps).To(Equal([]map[string]interface{}{input}))
			})
		})

		Context("the parseRoutes function", func() {
			errs := []error{}
			routeStuff := parseRoutes(input, &errs)

			It("does not error", func() {
				Expect(len(errs)).To(Equal(0))
			})

			It("should return three routes", func() {
				Expect(len(routeStuff)).To(Equal(3))
			})

			It("should return global properties", func() {
				// We're only testing for domain because of limitations in the route struct
				Expect(routeStuff[0].Domain.Name).To(Equal("example.com"))
			})
		})
	})

	Context("For a manifest with an applications section", func() {
		applicationsContents := []interface{}{map[string]string{
			"fred": "hello",
		}}
		input := map[string]interface{}{
			"applications": applicationsContents,
			"host":         "bob",
		}

		m := &Manifest{}
		appMaps, err := m.getAppMaps(input)

		Context("the AppMaps function", func() {
			It("does not error", func() {
				Expect(err).To(BeNil())
			})

			It("should not alter what gets passed in", func() {

				Expect(input["applications"]).To(Equal(applicationsContents))
				// Make sure this doesn't change what's passed in
				Expect(input["applications"]).To(Equal(applicationsContents))

			})

			It("should return one entry", func() {
				Expect(len(appMaps)).To(Equal(1))
			})

			It("should merge global properties with application-level properties", func() {

				Expect(appMaps[0]["host"]).To(Equal("bob"))
				Expect(appMaps[0]["fred"]).To(Equal("hello"))

			})
		})
	})

	Context("For a manifest with two applications in the applications section", func() {
		applicationsContents := []interface{}{map[string]string{
			"fred": "hello",
		},
			map[string]string{
				"george": "goodbye",
			}}
		input := map[string]interface{}{
			"applications": applicationsContents,
			"host":         "bob",
		}

		m := &Manifest{}
		appMaps, err := m.getAppMaps(input)

		Context("the AppMaps function", func() {
			It("does not error", func() {
				Expect(err).To(BeNil())
			})

			It("should not alter what gets passed in", func() {

				Expect(input["applications"]).To(Equal(applicationsContents))
				// Make sure this doesn't change what's passed in
				Expect(input["applications"]).To(Equal(applicationsContents))

			})

			It("should return two entry", func() {
				Expect(len(appMaps)).To(Equal(2))
			})

			It("should merge global properties with application-level properties", func() {

				Expect(appMaps[0]["host"]).To(Equal("bob"))
				Expect(appMaps[0]["fred"]).To(Equal("hello"))
				Expect(appMaps[0]["george"]).To(BeNil())

				Expect(appMaps[1]["host"]).To(Equal("bob"))
				Expect(appMaps[1]["george"]).To(Equal("goodbye"))
				Expect(appMaps[1]["fred"]).To(BeNil())

			})
		})
	})

})

var _ = Describe("CloneWithExclude", func() {

	Context("When the map contains some values and excludeKey exists", func() {

		input := map[string]interface{}{
			"one":   1,
			"two":   2138,
			"three": 1908,
		}

		excludeKey := "two"

		actual := cloneWithExclude(input, excludeKey)

		It("should return a new map without the excludeKey", func() {

			expected := map[string]interface{}{
				"one":   1,
				"three": 1908,
			}

			Expect(actual).To(Equal(expected))
		})

		It("should not alter the original map", func() {
			Expect(input["two"]).To(Equal(2138))
		})
	})

	Context("When the map contains some values and excludeKey does not exist", func() {
		It("should return a new map with the same contents as the original", func() {
			input := map[string]interface{}{
				"one":   1,
				"two":   2138,
				"three": 1908,
			}

			excludeKey := "four"

			actual := cloneWithExclude(input, excludeKey)

			Expect(actual).To(Equal(input))
		})
	})

	Context("When the map contains a key that includes the excludeKey", func() {
		It("should return a new map with the same contents as the original", func() {
			input := map[string]interface{}{
				"one":       1,
				"two":       2138,
				"threefour": 1908,
			}

			excludeKey := "four"

			actual := cloneWithExclude(input, excludeKey)

			Expect(actual).To(Equal(input))
		})
	})

	Context("When the map is empty", func() {
		It("should return a new empty map", func() {
			input := map[string]interface{}{}

			excludeKey := "one"

			actual := cloneWithExclude(input, excludeKey)

			Expect(actual).To(Equal(input))
		})
	})

	Context("when the manifest contains a different app name", func() {
		manifest := manifestFromYamlString(`---
	      name: bar
	      host: foo`)

		It("Returns nil", func() {
			Expect(manifest.GetAppParams("appname", "domain")).To(BeNil())
		})

		Context("when the manifest contain a host but no app name", func() {
			manifest := manifestFromYamlString(`---
host: foo`)

			It("Returns params that contain the host", func() {

				var hostNames []string

				for _, route := range manifest.GetAppParams("foo", "something.com").Routes {
					hostNames = append(hostNames, route.Host)
				}

				Expect(hostNames).To(ContainElement("foo"))
			})
		})

		Describe("Route Lister", func() {
			It("returns a list of Routes from the manifest", func() {
				manifest := manifestFromYamlString(`---
name: foo
hosts:
 - host1
 - host2
domains:
 - example.com
 - example.net`)

				params := manifest.GetAppParams("foo", "example.com")

				Expect(params).ToNot(BeNil())
				Expect(params.Routes).ToNot(BeNil())

				routes := params.Routes
				Expect(routes).To(ConsistOf(
					plugin_models.GetApp_RouteSummary{Host: "host1", Domain: plugin_models.GetApp_DomainFields{Name: "example.com"}},
					plugin_models.GetApp_RouteSummary{Host: "host1", Domain: plugin_models.GetApp_DomainFields{Name: "example.net"}},
					plugin_models.GetApp_RouteSummary{Host: "host2", Domain: plugin_models.GetApp_DomainFields{Name: "example.com"}},
					plugin_models.GetApp_RouteSummary{Host: "host2", Domain: plugin_models.GetApp_DomainFields{Name: "example.net"}},
				))
			})

			Context("when app has just hosts, no domains", func() {
				It("returns Application", func() {
					manifest := manifestFromYamlString(`---
name: foo
hosts:
 - host1
 - host2`)

					params := manifest.GetAppParams("foo", "example.com")
					Expect(params).ToNot(BeNil())
					Expect(params.Routes).ToNot(BeNil())

					routes := params.Routes
					Expect(routes).To(ConsistOf(
						plugin_models.GetApp_RouteSummary{Host: "host1", Domain: plugin_models.GetApp_DomainFields{Name: "example.com"}},
						plugin_models.GetApp_RouteSummary{Host: "host2", Domain: plugin_models.GetApp_DomainFields{Name: "example.com"}},
					))
				})
			})

			PContext("when app has just routes, no hosts or domains", func() {
				It("returns those routes", func() {
					manifest := manifestFromYamlString(`---
name: foo
routes:
 - route1.domain1
 - route2.domain2`)

					params := manifest.GetAppParams("foo", "example.com")

					Expect(params).To(ConsistOf(
						plugin_models.GetApp_RouteSummary{Host: "route1", Domain: plugin_models.GetApp_DomainFields{Name: "domain1"}},
						plugin_models.GetApp_RouteSummary{Host: "route2", Domain: plugin_models.GetApp_DomainFields{Name: "domain2"}},
					))
				})
			})

			Context("when no matching application", func() {
				It("returns nil", func() {
					manifest := manifestFromYamlString(``)

					Expect(manifest.GetAppParams("foo", "example.com")).To(BeNil())
				})
			})
		})

	})

	Context("when the manifest contains multiple apps with 1 matching", func() {
		manifest := manifestFromYamlString(`---
applications:
 - name: bar
   host: barhost
 - name: foo
   hosts:
    - host1
    - host2
   domains:
    - example1.com
    - example2.com`)
		It("Returns the correct app", func() {

			var hostNames []string
			var domainNames []string

			appParams := manifest.GetAppParams("foo", "")
			Expect(appParams).ToNot(BeNil())

			routes := appParams.Routes
			Expect(routes).ToNot(BeNil())
			for _, route := range routes {
				hostNames = append(hostNames, route.Host)
				domainNames = append(domainNames, route.Domain.Name)
			}

			hostNames = deDuplicate(hostNames)
			domainNames = deDuplicate(domainNames)

			Expect(manifest.GetAppParams("foo", "").Name).To(Equal("foo"))
			Expect(hostNames).To(ConsistOf("host1", "host2"))
			Expect(domainNames).To(ConsistOf("example1.com", "example2.com"))
		})
	})
})

func deDuplicate(ary []string) []string {
	if ary == nil {
		return nil
	}

	m := make(map[string]bool)
	for _, v := range ary {
		m[v] = true
	}

	newAry := []string{}
	for _, val := range ary {
		if m[val] {
			newAry = append(newAry, val)
			m[val] = false
		}
	}
	return newAry
}

func manifestFromYamlString(yamlString string) *Manifest {
	yamlMap := make(map[string]interface{})
	candiedyaml.Unmarshal([]byte(yamlString), &yamlMap)
	return &Manifest{Data: yamlMap}
}
<commit_msg>shorter and stronger test for host with no app name<commit_after>package manifest

import (
	"code.cloudfoundry.org/cli/plugin/models"
	"github.com/cloudfoundry-incubator/candiedyaml"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Manifest", func() {

	Context("For a manifest with no applications section", func() {

		input := map[string]interface{}{
			"host": "bob",
			"routes": []interface{}{
				map[interface{}]interface{}{"route": "example.com"},
				map[interface{}]interface{}{"route": "www.example.com/foo"},
				map[interface{}]interface{}{"route": "tcp-example.com:1234"},
			},
		}
		m := &Manifest{}

		Context("the getAppMaps function", func() {
			appMaps, err := m.getAppMaps(input)
			It("does not error", func() {
				Expect(err).To(BeNil())
			})

			It("should return one entry", func() {
				Expect(len(appMaps)).To(Equal(1))
			})

			It("should return global properties", func() {
				Expect(appMaps).To(Equal([]map[string]interface{}{input}))
			})
		})

		Context("the parseRoutes function", func() {
			errs := []error{}
			routeStuff := parseRoutes(input, &errs)

			It("does not error", func() {
				Expect(len(errs)).To(Equal(0))
			})

			It("should return three routes", func() {
				Expect(len(routeStuff)).To(Equal(3))
			})

			It("should return global properties", func() {
				// We're only testing for domain because of limitations in the route struct
				Expect(routeStuff[0].Domain.Name).To(Equal("example.com"))
			})
		})
	})

	Context("For a manifest with an applications section", func() {
		applicationsContents := []interface{}{map[string]string{
			"fred": "hello",
		}}
		input := map[string]interface{}{
			"applications": applicationsContents,
			"host":         "bob",
		}

		m := &Manifest{}
		appMaps, err := m.getAppMaps(input)

		Context("the AppMaps function", func() {
			It("does not error", func() {
				Expect(err).To(BeNil())
			})

			It("should not alter what gets passed in", func() {

				Expect(input["applications"]).To(Equal(applicationsContents))
				// Make sure this doesn't change what's passed in
				Expect(input["applications"]).To(Equal(applicationsContents))

			})

			It("should return one entry", func() {
				Expect(len(appMaps)).To(Equal(1))
			})

			It("should merge global properties with application-level properties", func() {

				Expect(appMaps[0]["host"]).To(Equal("bob"))
				Expect(appMaps[0]["fred"]).To(Equal("hello"))

			})
		})
	})

	Context("For a manifest with two applications in the applications section", func() {
		applicationsContents := []interface{}{map[string]string{
			"fred": "hello",
		},
			map[string]string{
				"george": "goodbye",
			}}
		input := map[string]interface{}{
			"applications": applicationsContents,
			"host":         "bob",
		}

		m := &Manifest{}
		appMaps, err := m.getAppMaps(input)

		Context("the AppMaps function", func() {
			It("does not error", func() {
				Expect(err).To(BeNil())
			})

			It("should not alter what gets passed in", func() {

				Expect(input["applications"]).To(Equal(applicationsContents))
				// Make sure this doesn't change what's passed in
				Expect(input["applications"]).To(Equal(applicationsContents))

			})

			It("should return two entry", func() {
				Expect(len(appMaps)).To(Equal(2))
			})

			It("should merge global properties with application-level properties", func() {

				Expect(appMaps[0]["host"]).To(Equal("bob"))
				Expect(appMaps[0]["fred"]).To(Equal("hello"))
				Expect(appMaps[0]["george"]).To(BeNil())

				Expect(appMaps[1]["host"]).To(Equal("bob"))
				Expect(appMaps[1]["george"]).To(Equal("goodbye"))
				Expect(appMaps[1]["fred"]).To(BeNil())

			})
		})
	})

})

var _ = Describe("CloneWithExclude", func() {

	Context("When the map contains some values and excludeKey exists", func() {

		input := map[string]interface{}{
			"one":   1,
			"two":   2138,
			"three": 1908,
		}

		excludeKey := "two"

		actual := cloneWithExclude(input, excludeKey)

		It("should return a new map without the excludeKey", func() {

			expected := map[string]interface{}{
				"one":   1,
				"three": 1908,
			}

			Expect(actual).To(Equal(expected))
		})

		It("should not alter the original map", func() {
			Expect(input["two"]).To(Equal(2138))
		})
	})

	Context("When the map contains some values and excludeKey does not exist", func() {
		It("should return a new map with the same contents as the original", func() {
			input := map[string]interface{}{
				"one":   1,
				"two":   2138,
				"three": 1908,
			}

			excludeKey := "four"

			actual := cloneWithExclude(input, excludeKey)

			Expect(actual).To(Equal(input))
		})
	})

	Context("When the map contains a key that includes the excludeKey", func() {
		It("should return a new map with the same contents as the original", func() {
			input := map[string]interface{}{
				"one":       1,
				"two":       2138,
				"threefour": 1908,
			}

			excludeKey := "four"

			actual := cloneWithExclude(input, excludeKey)

			Expect(actual).To(Equal(input))
		})
	})

	Context("When the map is empty", func() {
		It("should return a new empty map", func() {
			input := map[string]interface{}{}

			excludeKey := "one"

			actual := cloneWithExclude(input, excludeKey)

			Expect(actual).To(Equal(input))
		})
	})

	Context("when the manifest contains a different app name", func() {
		manifest := manifestFromYamlString(`---
	      name: bar
	      host: foo`)

		It("Returns nil", func() {
			Expect(manifest.GetAppParams("appname", "domain")).To(BeNil())
		})

		Context("when the manifest contain a host but no app name", func() {
			manifest := manifestFromYamlString(`---
host: foo`)

			It("Returns params that contain the host", func() {

				routes := manifest.GetAppParams("foo", "something.com").Routes
				Expect(routes).To(ConsistOf(
					plugin_models.GetApp_RouteSummary{Host: "foo", Domain: plugin_models.GetApp_DomainFields{Name: "something.com"}},
				))
			})
		})

		Describe("Route Lister", func() {
			It("returns a list of Routes from the manifest", func() {
				manifest := manifestFromYamlString(`---
name: foo
hosts:
 - host1
 - host2
domains:
 - example.com
 - example.net`)

				params := manifest.GetAppParams("foo", "example.com")

				Expect(params).ToNot(BeNil())
				Expect(params.Routes).ToNot(BeNil())

				routes := params.Routes
				Expect(routes).To(ConsistOf(
					plugin_models.GetApp_RouteSummary{Host: "host1", Domain: plugin_models.GetApp_DomainFields{Name: "example.com"}},
					plugin_models.GetApp_RouteSummary{Host: "host1", Domain: plugin_models.GetApp_DomainFields{Name: "example.net"}},
					plugin_models.GetApp_RouteSummary{Host: "host2", Domain: plugin_models.GetApp_DomainFields{Name: "example.com"}},
					plugin_models.GetApp_RouteSummary{Host: "host2", Domain: plugin_models.GetApp_DomainFields{Name: "example.net"}},
				))
			})

			Context("when app has just hosts, no domains", func() {
				It("returns Application", func() {
					manifest := manifestFromYamlString(`---
name: foo
hosts:
 - host1
 - host2`)

					params := manifest.GetAppParams("foo", "example.com")
					Expect(params).ToNot(BeNil())
					Expect(params.Routes).ToNot(BeNil())

					routes := params.Routes
					Expect(routes).To(ConsistOf(
						plugin_models.GetApp_RouteSummary{Host: "host1", Domain: plugin_models.GetApp_DomainFields{Name: "example.com"}},
						plugin_models.GetApp_RouteSummary{Host: "host2", Domain: plugin_models.GetApp_DomainFields{Name: "example.com"}},
					))
				})
			})

			PContext("when app has just routes, no hosts or domains", func() {
				It("returns those routes", func() {
					manifest := manifestFromYamlString(`---
name: foo
routes:
 - route1.domain1
 - route2.domain2`)

					params := manifest.GetAppParams("foo", "example.com")

					Expect(params).To(ConsistOf(
						plugin_models.GetApp_RouteSummary{Host: "route1", Domain: plugin_models.GetApp_DomainFields{Name: "domain1"}},
						plugin_models.GetApp_RouteSummary{Host: "route2", Domain: plugin_models.GetApp_DomainFields{Name: "domain2"}},
					))
				})
			})

			Context("when no matching application", func() {
				It("returns nil", func() {
					manifest := manifestFromYamlString(``)

					Expect(manifest.GetAppParams("foo", "example.com")).To(BeNil())
				})
			})
		})

	})

	Context("when the manifest contains multiple apps with 1 matching", func() {
		manifest := manifestFromYamlString(`---
applications:
 - name: bar
   host: barhost
 - name: foo
   hosts:
    - host1
    - host2
   domains:
    - example1.com
    - example2.com`)
		It("Returns the correct app", func() {

			var hostNames []string
			var domainNames []string

			appParams := manifest.GetAppParams("foo", "")
			Expect(appParams).ToNot(BeNil())

			routes := appParams.Routes
			Expect(routes).ToNot(BeNil())
			for _, route := range routes {
				hostNames = append(hostNames, route.Host)
				domainNames = append(domainNames, route.Domain.Name)
			}

			hostNames = deDuplicate(hostNames)
			domainNames = deDuplicate(domainNames)

			Expect(manifest.GetAppParams("foo", "").Name).To(Equal("foo"))
			Expect(hostNames).To(ConsistOf("host1", "host2"))
			Expect(domainNames).To(ConsistOf("example1.com", "example2.com"))
		})
	})
})

func deDuplicate(ary []string) []string {
	if ary == nil {
		return nil
	}

	m := make(map[string]bool)
	for _, v := range ary {
		m[v] = true
	}

	newAry := []string{}
	for _, val := range ary {
		if m[val] {
			newAry = append(newAry, val)
			m[val] = false
		}
	}
	return newAry
}

func manifestFromYamlString(yamlString string) *Manifest {
	yamlMap := make(map[string]interface{})
	candiedyaml.Unmarshal([]byte(yamlString), &yamlMap)
	return &Manifest{Data: yamlMap}
}
<|endoftext|>


<commit_before>package cluster

import (
	"fmt"

	"github.com/zalando/postgres-operator/pkg/spec"
	"github.com/zalando/postgres-operator/pkg/util"
	v1 "k8s.io/api/core/v1"
)

// VersionMap Map of version numbers
var VersionMap = map[string]int{
	"9.5": 90500,
	"9.6": 90600,
	"10":  100000,
	"11":  110000,
	"12":  120000,
	"13":  130000,
	"14":  140000,
}

// IsBiggerPostgresVersion Compare two Postgres version numbers
func IsBiggerPostgresVersion(old string, new string) bool {
	oldN := VersionMap[old]
	newN := VersionMap[new]
	return newN > oldN
}

// GetDesiredMajorVersionAsInt Convert string to comparable integer of PG version
func (c *Cluster) GetDesiredMajorVersionAsInt() int {
	return VersionMap[c.GetDesiredMajorVersion()]
}

// GetDesiredMajorVersion returns major version to use, incl. potential auto upgrade
func (c *Cluster) GetDesiredMajorVersion() string {

	if c.Config.OpConfig.MajorVersionUpgradeMode == "full" {
		// e.g. current is 9.6, minimal is 11 allowing 11 to 14 clusters, everything below is upgraded
		if IsBiggerPostgresVersion(c.Spec.PgVersion, c.Config.OpConfig.MinimalMajorVersion) {
			c.logger.Infof("overwriting configured major version %s to %s", c.Spec.PgVersion, c.Config.OpConfig.TargetMajorVersion)
			return c.Config.OpConfig.TargetMajorVersion
		}
	}

	return c.Spec.PgVersion
}

func (c *Cluster) isUpgradeAllowedForTeam(owningTeam string) bool {
	allowedTeams := c.OpConfig.MajorVersionUpgradeTeamAllowList

	if len(allowedTeams) == 0 {
		return false
	}

	return util.SliceContains(allowedTeams, owningTeam)
}

/*
  Execute upgrade when mode is set to manual or full or when the owning team is allowed for upgrade (and mode is "off").

  Manual upgrade means, it is triggered by the user via manifest version change
  Full upgrade means, operator also determines the minimal version used accross all clusters and upgrades violators.
*/
func (c *Cluster) majorVersionUpgrade() error {

	if c.OpConfig.MajorVersionUpgradeMode == "off" && !c.isUpgradeAllowedForTeam(c.Spec.TeamID) {
		return nil
	}

	desiredVersion := c.GetDesiredMajorVersionAsInt()

	if c.currentMajorVersion >= desiredVersion {
		c.logger.Infof("cluster version up to date. current: %d, min desired: %d", c.currentMajorVersion, desiredVersion)
		return nil
	}

	pods, err := c.listPods()
	if err != nil {
		return err
	}

	allRunning := true

	var masterPod *v1.Pod

	for _, pod := range pods {
		ps, _ := c.patroni.GetMemberData(&pod)

		if ps.State != "running" {
			allRunning = false
			c.logger.Infof("identified non running pod, potentially skipping major version upgrade")
		}

		if ps.Role == "master" {
			masterPod = &pod
			c.currentMajorVersion = ps.ServerVersion
		}
	}

	numberOfPods := len(pods)
	if allRunning && masterPod != nil {
		c.logger.Infof("healthy cluster ready to upgrade, current: %d desired: %d", c.currentMajorVersion, desiredVersion)
		if c.currentMajorVersion < desiredVersion {
			podName := &spec.NamespacedName{Namespace: masterPod.Namespace, Name: masterPod.Name}
			c.logger.Infof("triggering major version upgrade on pod %s of %d pods", masterPod.Name, numberOfPods)
			c.eventRecorder.Eventf(c.GetReference(), v1.EventTypeNormal, "Major Version Upgrade", "Starting major version upgrade on pod %s of %d pods", masterPod.Name, numberOfPods)
			upgradeCommand := fmt.Sprintf("/usr/bin/python3 /scripts/inplace_upgrade.py %d 2>&1 | tee last_upgrade.log", numberOfPods)

			result, err := c.ExecCommand(podName, "/bin/su", "postgres", "-c", upgradeCommand)
			if err != nil {
				c.eventRecorder.Eventf(c.GetReference(), v1.EventTypeNormal, "Major Version Upgrade", "Upgrade from %d to %d FAILED: %v", c.currentMajorVersion, desiredVersion, err)
				return err
			}

			c.logger.Infof("upgrade action triggered and command completed: %s", result[:50])
			c.eventRecorder.Eventf(c.GetReference(), v1.EventTypeNormal, "Major Version Upgrade", "Upgrade from %d to %d finished", c.currentMajorVersion, desiredVersion)
		}
	}

	return nil
}
<commit_msg>make sure upgrade script runs on the master (#1715)<commit_after>package cluster

import (
	"fmt"

	"github.com/zalando/postgres-operator/pkg/spec"
	"github.com/zalando/postgres-operator/pkg/util"
	v1 "k8s.io/api/core/v1"
)

// VersionMap Map of version numbers
var VersionMap = map[string]int{
	"9.5": 90500,
	"9.6": 90600,
	"10":  100000,
	"11":  110000,
	"12":  120000,
	"13":  130000,
	"14":  140000,
}

// IsBiggerPostgresVersion Compare two Postgres version numbers
func IsBiggerPostgresVersion(old string, new string) bool {
	oldN := VersionMap[old]
	newN := VersionMap[new]
	return newN > oldN
}

// GetDesiredMajorVersionAsInt Convert string to comparable integer of PG version
func (c *Cluster) GetDesiredMajorVersionAsInt() int {
	return VersionMap[c.GetDesiredMajorVersion()]
}

// GetDesiredMajorVersion returns major version to use, incl. potential auto upgrade
func (c *Cluster) GetDesiredMajorVersion() string {

	if c.Config.OpConfig.MajorVersionUpgradeMode == "full" {
		// e.g. current is 9.6, minimal is 11 allowing 11 to 14 clusters, everything below is upgraded
		if IsBiggerPostgresVersion(c.Spec.PgVersion, c.Config.OpConfig.MinimalMajorVersion) {
			c.logger.Infof("overwriting configured major version %s to %s", c.Spec.PgVersion, c.Config.OpConfig.TargetMajorVersion)
			return c.Config.OpConfig.TargetMajorVersion
		}
	}

	return c.Spec.PgVersion
}

func (c *Cluster) isUpgradeAllowedForTeam(owningTeam string) bool {
	allowedTeams := c.OpConfig.MajorVersionUpgradeTeamAllowList

	if len(allowedTeams) == 0 {
		return false
	}

	return util.SliceContains(allowedTeams, owningTeam)
}

/*
  Execute upgrade when mode is set to manual or full or when the owning team is allowed for upgrade (and mode is "off").

  Manual upgrade means, it is triggered by the user via manifest version change
  Full upgrade means, operator also determines the minimal version used accross all clusters and upgrades violators.
*/
func (c *Cluster) majorVersionUpgrade() error {

	if c.OpConfig.MajorVersionUpgradeMode == "off" && !c.isUpgradeAllowedForTeam(c.Spec.TeamID) {
		return nil
	}

	desiredVersion := c.GetDesiredMajorVersionAsInt()

	if c.currentMajorVersion >= desiredVersion {
		c.logger.Infof("cluster version up to date. current: %d, min desired: %d", c.currentMajorVersion, desiredVersion)
		return nil
	}

	pods, err := c.listPods()
	if err != nil {
		return err
	}

	allRunning := true

	var masterPod *v1.Pod

	for i, pod := range pods {
		ps, _ := c.patroni.GetMemberData(&pod)

		if ps.State != "running" {
			allRunning = false
			c.logger.Infof("identified non running pod, potentially skipping major version upgrade")
		}

		if ps.Role == "master" {
			masterPod = &pods[i]
			c.currentMajorVersion = ps.ServerVersion
		}
	}

	numberOfPods := len(pods)
	if allRunning && masterPod != nil {
		c.logger.Infof("healthy cluster ready to upgrade, current: %d desired: %d", c.currentMajorVersion, desiredVersion)
		if c.currentMajorVersion < desiredVersion {
			podName := &spec.NamespacedName{Namespace: masterPod.Namespace, Name: masterPod.Name}
			c.logger.Infof("triggering major version upgrade on pod %s of %d pods", masterPod.Name, numberOfPods)
			c.eventRecorder.Eventf(c.GetReference(), v1.EventTypeNormal, "Major Version Upgrade", "Starting major version upgrade on pod %s of %d pods", masterPod.Name, numberOfPods)
			upgradeCommand := fmt.Sprintf("/usr/bin/python3 /scripts/inplace_upgrade.py %d 2>&1 | tee last_upgrade.log", numberOfPods)

			result, err := c.ExecCommand(podName, "/bin/su", "postgres", "-c", upgradeCommand)
			if err != nil {
				c.eventRecorder.Eventf(c.GetReference(), v1.EventTypeNormal, "Major Version Upgrade", "Upgrade from %d to %d FAILED: %v", c.currentMajorVersion, desiredVersion, err)
				return err
			}

			c.logger.Infof("upgrade action triggered and command completed: %s", result[:100])
			c.eventRecorder.Eventf(c.GetReference(), v1.EventTypeNormal, "Major Version Upgrade", "Upgrade from %d to %d finished", c.currentMajorVersion, desiredVersion)
		}
	}

	return nil
}
<|endoftext|>