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

package tar_test

import (
	"archive/tar"
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
)

func Example() {
	// Create a buffer to write our archive to.
	buf := new(bytes.Buffer)

	// Create a new tar archive.
	tw := tar.NewWriter(buf)

	// Add some files to the archive.
	var files = []struct {
		Name, Body string
	}{
		{"readme.txt", "This archive contains some text files."},
		{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
		{"todo.txt", "Get animal handling licence."},
	}
	for _, file := range files {
		hdr := &tar.Header{
			Name: file.Name,
			Mode: 0600,
			Size: int64(len(file.Body)),
		}
		if err := tw.WriteHeader(hdr); err != nil {
			log.Fatalln(err)
		}
		if _, err := tw.Write([]byte(file.Body)); err != nil {
			log.Fatalln(err)
		}
	}
	// Make sure to check the error on Close.
	if err := tw.Close(); err != nil {
		log.Fatalln(err)
	}

	// Open the tar archive for reading.
	r := bytes.NewReader(buf.Bytes())
	tr := tar.NewReader(r)

	// Iterate through the files in the archive.
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			// end of tar archive
			break
		}
		if err != nil {
			log.Fatalln(err)
		}
		fmt.Printf("Contents of %s:\n", hdr.Name)
		if _, err := io.Copy(os.Stdout, tr); err != nil {
			log.Fatalln(err)
		}
		fmt.Println()
	}

	// Output:
	// Contents of readme.txt:
	// This archive contains some text files.
	// Contents of gopher.txt:
	// Gopher names:
	// George
	// Geoffrey
	// Gonzo
	// Contents of todo.txt:
	// Get animal handling licence.
}
<commit_msg>archive/tar: spell license correctly in example<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tar_test

import (
	"archive/tar"
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
)

func Example() {
	// Create a buffer to write our archive to.
	buf := new(bytes.Buffer)

	// Create a new tar archive.
	tw := tar.NewWriter(buf)

	// Add some files to the archive.
	var files = []struct {
		Name, Body string
	}{
		{"readme.txt", "This archive contains some text files."},
		{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
		{"todo.txt", "Get animal handling license."},
	}
	for _, file := range files {
		hdr := &tar.Header{
			Name: file.Name,
			Mode: 0600,
			Size: int64(len(file.Body)),
		}
		if err := tw.WriteHeader(hdr); err != nil {
			log.Fatalln(err)
		}
		if _, err := tw.Write([]byte(file.Body)); err != nil {
			log.Fatalln(err)
		}
	}
	// Make sure to check the error on Close.
	if err := tw.Close(); err != nil {
		log.Fatalln(err)
	}

	// Open the tar archive for reading.
	r := bytes.NewReader(buf.Bytes())
	tr := tar.NewReader(r)

	// Iterate through the files in the archive.
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			// end of tar archive
			break
		}
		if err != nil {
			log.Fatalln(err)
		}
		fmt.Printf("Contents of %s:\n", hdr.Name)
		if _, err := io.Copy(os.Stdout, tr); err != nil {
			log.Fatalln(err)
		}
		fmt.Println()
	}

	// Output:
	// Contents of readme.txt:
	// This archive contains some text files.
	// Contents of gopher.txt:
	// Gopher names:
	// George
	// Geoffrey
	// Gonzo
	// Contents of todo.txt:
	// Get animal handling license.
}
<|endoftext|>


<commit_before>package libpod

import (
	"fmt"

	"github.com/containers/storage"
	"github.com/containers/storage/pkg/idtools"
	"github.com/pkg/errors"
)

var (
	ctrNotImplemented = func(c *Container) error {
		return fmt.Errorf("NOT IMPLEMENTED")
	}
)

const (
	// IPCNamespace represents the IPC namespace
	IPCNamespace = "ipc"
	// MountNamespace represents the mount namespace
	MountNamespace = "mount"
	// NetNamespace represents the network namespace
	NetNamespace = "net"
	// PIDNamespace represents the PID namespace
	PIDNamespace = "pid"
	// UserNamespace represents the user namespace
	UserNamespace = "user"
	// UTSNamespace represents the UTS namespace
	UTSNamespace = "uts"
)

// Runtime Creation Options

// WithStorageConfig uses the given configuration to set up container storage
// If this is not specified, the system default configuration will be used
// instead
func WithStorageConfig(config storage.StoreOptions) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.StorageConfig.RunRoot = config.RunRoot
		rt.config.StorageConfig.GraphRoot = config.GraphRoot
		rt.config.StorageConfig.GraphDriverName = config.GraphDriverName

		rt.config.StorageConfig.GraphDriverOptions = make([]string, len(config.GraphDriverOptions))
		copy(rt.config.StorageConfig.GraphDriverOptions, config.GraphDriverOptions)

		rt.config.StorageConfig.UIDMap = make([]idtools.IDMap, len(config.UIDMap))
		copy(rt.config.StorageConfig.UIDMap, config.UIDMap)

		rt.config.StorageConfig.GIDMap = make([]idtools.IDMap, len(config.UIDMap))
		copy(rt.config.StorageConfig.GIDMap, config.GIDMap)

		return nil
	}
}

// WithImageConfig uses the given configuration to set up image handling
// If this is not specified, the system default configuration will be used
// instead
func WithImageConfig(defaultTransport string, insecureRegistries, registries []string) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.ImageDefaultTransport = defaultTransport

		rt.config.InsecureRegistries = make([]string, len(insecureRegistries))
		copy(rt.config.InsecureRegistries, insecureRegistries)

		rt.config.Registries = make([]string, len(registries))
		copy(rt.config.Registries, registries)

		return nil
	}
}

// WithSignaturePolicy specifies the path of a file which decides how trust is
// managed for images we've pulled.
// If this is not specified, the system default configuration will be used
// instead
func WithSignaturePolicy(path string) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.SignaturePolicyPath = path

		return nil
	}
}

// WithOCIRuntime specifies an OCI runtime to use for running containers
func WithOCIRuntime(runtimePath string) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.RuntimePath = runtimePath

		return nil
	}
}

// WithConmonPath specifies the path to the conmon binary which manages the
// runtime
func WithConmonPath(path string) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.ConmonPath = path

		return nil
	}
}

// WithConmonEnv specifies the environment variable list for the conmon process
func WithConmonEnv(environment []string) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.ConmonEnvVars = make([]string, len(environment))
		copy(rt.config.ConmonEnvVars, environment)

		return nil
	}
}

// WithCgroupManager specifies the manager implementation name which is used to
// handle cgroups for containers
func WithCgroupManager(manager string) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.CgroupManager = manager

		return nil
	}
}

// WithSELinux enables SELinux on the container server
func WithSELinux() RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.SelinuxEnabled = true

		return nil
	}
}

// WithPidsLimit specifies the maximum number of processes each container is
// restricted to
func WithPidsLimit(limit int64) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.PidsLimit = limit

		return nil
	}
}

// Container Creation Options

// WithRootFSFromPath uses the given path as a container's root filesystem
// No further setup is performed on this path
func WithRootFSFromPath(path string) CtrCreateOption {
	return ctrNotImplemented
}

// WithRootFSFromImage sets up a fresh root filesystem using the given image
// If useImageConfig is specified, image volumes, environment variables, and
// other configuration from the image will be added to the config
func WithRootFSFromImage(image string, useImageConfig bool) CtrCreateOption {
	return ctrNotImplemented
}

// WithSharedNamespaces sets a container to share namespaces with another
// container. If the from container belongs to a pod, the new container will
// be added to the pod.
// By default no namespaces are shared. To share a namespace, add the Namespace
// string constant to the map as a key
func WithSharedNamespaces(from *Container, namespaces map[string]string) CtrCreateOption {
	return ctrNotImplemented
}

// WithPod adds the container to a pod
func (r *Runtime) WithPod(pod *Pod) CtrCreateOption {
	return func(ctr *Container) error {
		if !ctr.valid {
			return ErrCtrFinalized
		}

		if ctr.pod != nil {
			return fmt.Errorf("container has already been added to a pod")
		}

		exists, err := r.state.HasPod(pod.ID())
		if err != nil {
			return errors.Wrapf(err, "error searching state for pod %s", pod.ID())
		} else if !exists {
			return errors.Wrapf(ErrNoSuchPod, "pod %s cannot be found in state", pod.ID())
		}

		if err := pod.addContainer(ctr); err != nil {
			return errors.Wrapf(err, "error adding container to pod")
		}

		ctr.pod = pod

		return nil
	}
}

// WithLabels adds labels to the container
func WithLabels(labels map[string]string) CtrCreateOption {
	return ctrNotImplemented
}

// WithAnnotations adds annotations to the container
func WithAnnotations(annotations map[string]string) CtrCreateOption {
	return ctrNotImplemented
}

// WithName sets the container's name
func WithName(name string) CtrCreateOption {
	return func(ctr *Container) error {
		if !ctr.valid {
			return ErrCtrFinalized
		}

		ctr.name = name

		return nil
	}
}

// WithStopSignal sets the signal that will be sent to stop the container
func WithStopSignal(signal uint) CtrCreateOption {
	return ctrNotImplemented
}

// Pod Creation Options

// WithPodName sets the name of the pod
func WithPodName(name string) PodCreateOption {
	return func(pod *Pod) error {
		if pod.valid {
			return ErrPodFinalized
		}

		pod.name = name

		return nil
	}
}
<commit_msg>Fix a copy/paste error in libpod initializers<commit_after>package libpod

import (
	"fmt"

	"github.com/containers/storage"
	"github.com/containers/storage/pkg/idtools"
	"github.com/pkg/errors"
)

var (
	ctrNotImplemented = func(c *Container) error {
		return fmt.Errorf("NOT IMPLEMENTED")
	}
)

const (
	// IPCNamespace represents the IPC namespace
	IPCNamespace = "ipc"
	// MountNamespace represents the mount namespace
	MountNamespace = "mount"
	// NetNamespace represents the network namespace
	NetNamespace = "net"
	// PIDNamespace represents the PID namespace
	PIDNamespace = "pid"
	// UserNamespace represents the user namespace
	UserNamespace = "user"
	// UTSNamespace represents the UTS namespace
	UTSNamespace = "uts"
)

// Runtime Creation Options

// WithStorageConfig uses the given configuration to set up container storage
// If this is not specified, the system default configuration will be used
// instead
func WithStorageConfig(config storage.StoreOptions) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.StorageConfig.RunRoot = config.RunRoot
		rt.config.StorageConfig.GraphRoot = config.GraphRoot
		rt.config.StorageConfig.GraphDriverName = config.GraphDriverName

		rt.config.StorageConfig.GraphDriverOptions = make([]string, len(config.GraphDriverOptions))
		copy(rt.config.StorageConfig.GraphDriverOptions, config.GraphDriverOptions)

		rt.config.StorageConfig.UIDMap = make([]idtools.IDMap, len(config.UIDMap))
		copy(rt.config.StorageConfig.UIDMap, config.UIDMap)

		rt.config.StorageConfig.GIDMap = make([]idtools.IDMap, len(config.GIDMap))
		copy(rt.config.StorageConfig.GIDMap, config.GIDMap)

		return nil
	}
}

// WithImageConfig uses the given configuration to set up image handling
// If this is not specified, the system default configuration will be used
// instead
func WithImageConfig(defaultTransport string, insecureRegistries, registries []string) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.ImageDefaultTransport = defaultTransport

		rt.config.InsecureRegistries = make([]string, len(insecureRegistries))
		copy(rt.config.InsecureRegistries, insecureRegistries)

		rt.config.Registries = make([]string, len(registries))
		copy(rt.config.Registries, registries)

		return nil
	}
}

// WithSignaturePolicy specifies the path of a file which decides how trust is
// managed for images we've pulled.
// If this is not specified, the system default configuration will be used
// instead
func WithSignaturePolicy(path string) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.SignaturePolicyPath = path

		return nil
	}
}

// WithOCIRuntime specifies an OCI runtime to use for running containers
func WithOCIRuntime(runtimePath string) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.RuntimePath = runtimePath

		return nil
	}
}

// WithConmonPath specifies the path to the conmon binary which manages the
// runtime
func WithConmonPath(path string) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.ConmonPath = path

		return nil
	}
}

// WithConmonEnv specifies the environment variable list for the conmon process
func WithConmonEnv(environment []string) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.ConmonEnvVars = make([]string, len(environment))
		copy(rt.config.ConmonEnvVars, environment)

		return nil
	}
}

// WithCgroupManager specifies the manager implementation name which is used to
// handle cgroups for containers
func WithCgroupManager(manager string) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.CgroupManager = manager

		return nil
	}
}

// WithSELinux enables SELinux on the container server
func WithSELinux() RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.SelinuxEnabled = true

		return nil
	}
}

// WithPidsLimit specifies the maximum number of processes each container is
// restricted to
func WithPidsLimit(limit int64) RuntimeOption {
	return func(rt *Runtime) error {
		if rt.valid {
			return ErrRuntimeFinalized
		}

		rt.config.PidsLimit = limit

		return nil
	}
}

// Container Creation Options

// WithRootFSFromPath uses the given path as a container's root filesystem
// No further setup is performed on this path
func WithRootFSFromPath(path string) CtrCreateOption {
	return ctrNotImplemented
}

// WithRootFSFromImage sets up a fresh root filesystem using the given image
// If useImageConfig is specified, image volumes, environment variables, and
// other configuration from the image will be added to the config
func WithRootFSFromImage(image string, useImageConfig bool) CtrCreateOption {
	return ctrNotImplemented
}

// WithSharedNamespaces sets a container to share namespaces with another
// container. If the from container belongs to a pod, the new container will
// be added to the pod.
// By default no namespaces are shared. To share a namespace, add the Namespace
// string constant to the map as a key
func WithSharedNamespaces(from *Container, namespaces map[string]string) CtrCreateOption {
	return ctrNotImplemented
}

// WithPod adds the container to a pod
func (r *Runtime) WithPod(pod *Pod) CtrCreateOption {
	return func(ctr *Container) error {
		if !ctr.valid {
			return ErrCtrFinalized
		}

		if ctr.pod != nil {
			return fmt.Errorf("container has already been added to a pod")
		}

		exists, err := r.state.HasPod(pod.ID())
		if err != nil {
			return errors.Wrapf(err, "error searching state for pod %s", pod.ID())
		} else if !exists {
			return errors.Wrapf(ErrNoSuchPod, "pod %s cannot be found in state", pod.ID())
		}

		if err := pod.addContainer(ctr); err != nil {
			return errors.Wrapf(err, "error adding container to pod")
		}

		ctr.pod = pod

		return nil
	}
}

// WithLabels adds labels to the container
func WithLabels(labels map[string]string) CtrCreateOption {
	return ctrNotImplemented
}

// WithAnnotations adds annotations to the container
func WithAnnotations(annotations map[string]string) CtrCreateOption {
	return ctrNotImplemented
}

// WithName sets the container's name
func WithName(name string) CtrCreateOption {
	return func(ctr *Container) error {
		if !ctr.valid {
			return ErrCtrFinalized
		}

		ctr.name = name

		return nil
	}
}

// WithStopSignal sets the signal that will be sent to stop the container
func WithStopSignal(signal uint) CtrCreateOption {
	return ctrNotImplemented
}

// Pod Creation Options

// WithPodName sets the name of the pod
func WithPodName(name string) PodCreateOption {
	return func(pod *Pod) error {
		if pod.valid {
			return ErrPodFinalized
		}

		pod.name = name

		return nil
	}
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      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 hydra contains helpers for using hydra
package hydra

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"

	"github.com/golang/glog" /* copybara-comment */
	"google.golang.org/grpc/codes" /* copybara-comment */
	"google.golang.org/grpc/status" /* copybara-comment */
	"github.com/GoogleCloudPlatform/healthcare-federated-access-services/apis/hydraapi" /* copybara-comment: hydraapi */
	"github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/errutil" /* copybara-comment: errutil */
	"github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/httputils" /* copybara-comment: httputils */
)

// GetLoginRequest fetches information on a login request.
func GetLoginRequest(client *http.Client, hydraAdminURL, challenge string) (*hydraapi.LoginRequest, error) {
	u := getURL(hydraAdminURL, "login", url.QueryEscape(challenge))
	resp := &hydraapi.LoginRequest{}
	err := httpGet(client, u, resp)
	return resp, err
}

// AcceptLogin tells hydra to accept a login request.
func AcceptLogin(client *http.Client, hydraAdminURL, challenge string, r *hydraapi.HandledLoginRequest) (*hydraapi.RequestHandlerResponse, error) {
	u := putURL(hydraAdminURL, "login", "accept", url.QueryEscape(challenge))
	resp := &hydraapi.RequestHandlerResponse{}
	err := httpPut(client, u, r, resp)
	return resp, err
}

// RejectLogin tells hydra to reject a login request.
func RejectLogin(client *http.Client, hydraAdminURL, challenge string, r *hydraapi.RequestDeniedError) (*hydraapi.RequestHandlerResponse, error) {
	u := putURL(hydraAdminURL, "login", "reject", url.QueryEscape(challenge))
	resp := &hydraapi.RequestHandlerResponse{}
	err := httpPut(client, u, r, resp)
	return resp, err
}

// GetConsentRequest fetches information on a consent request.
func GetConsentRequest(client *http.Client, hydraAdminURL, challenge string) (*hydraapi.ConsentRequest, error) {
	u := getURL(hydraAdminURL, "consent", url.QueryEscape(challenge))
	resp := &hydraapi.ConsentRequest{}
	err := httpGet(client, u, resp)
	return resp, err
}

// AcceptConsent tells hydra to accept a consent request.
func AcceptConsent(client *http.Client, hydraAdminURL, challenge string, r *hydraapi.HandledConsentRequest) (*hydraapi.RequestHandlerResponse, error) {
	u := putURL(hydraAdminURL, "consent", "accept", url.QueryEscape(challenge))
	resp := &hydraapi.RequestHandlerResponse{}
	err := httpPut(client, u, r, resp)
	return resp, err
}

// RejectConsent tells hydra to rejects a consent request.
func RejectConsent(client *http.Client, hydraAdminURL, challenge string, r *hydraapi.RequestDeniedError) (*hydraapi.RequestHandlerResponse, error) {
	u := putURL(hydraAdminURL, "consent", "reject", url.QueryEscape(challenge))
	resp := &hydraapi.RequestHandlerResponse{}
	err := httpPut(client, u, r, resp)
	return resp, err
}

// ListClients list all OAuth clients in hydra.
func ListClients(client *http.Client, hydraAdminURL string) ([]*hydraapi.Client, error) {
	u := hydraAdminURL + "/clients"
	resp := []*hydraapi.Client{}
	err := httpGet(client, u, &resp)
	return resp, err
}

// CreateClient creates OAuth client in hydra.
func CreateClient(client *http.Client, hydraAdminURL string, oauthClient *hydraapi.Client) (*hydraapi.Client, error) {
	u := hydraAdminURL + "/clients"
	resp := &hydraapi.Client{}
	err := httpPostJSON(client, u, oauthClient, resp)
	return resp, err
}

// GetClient gets an OAUth 2.0 client by its ID.
func GetClient(client *http.Client, hydraAdminURL, id string) (*hydraapi.Client, error) {
	u := hydraAdminURL + "/clients/" + id
	resp := &hydraapi.Client{}
	err := httpGet(client, u, resp)
	return resp, err
}

// UpdateClient updates an existing OAuth 2.0 Client.
func UpdateClient(client *http.Client, hydraAdminURL, id string, oauthClient *hydraapi.Client) (*hydraapi.Client, error) {
	u := hydraAdminURL + "/clients/" + id
	resp := &hydraapi.Client{}
	err := httpPut(client, u, oauthClient, resp)
	return resp, err
}

// DeleteClient delete an existing OAuth 2.0 Client by its ID.
func DeleteClient(client *http.Client, hydraAdminURL, id string) error {
	u := hydraAdminURL + "/clients/" + id
	err := httpDelete(client, u)
	return err
}

// Introspect token, validate the given token and return token claims.
func Introspect(client *http.Client, hydraAdminURL, token string) (*hydraapi.Introspection, error) {
	u := hydraAdminURL + "/oauth2/introspect"

	data := url.Values{}
	data.Set("token", url.QueryEscape(token))

	response := &hydraapi.Introspection{}

	req, err := http.NewRequest(http.MethodPost, u, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, status.Errorf(codes.Internal, "http.NewRequest for Introspect failed to initialize: %v", err)
	}

	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Accept", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return nil, status.Errorf(codes.Unavailable, "Introspect to hydra failed: %v", err)
	}
	defer resp.Body.Close()

	if err := httpResponse(resp, response); err != nil {
		return nil, err
	}
	return response, nil
}

// ListConsents lists all consents of user (subject).
func ListConsents(client *http.Client, hydraAdminURL, subject string) ([]*hydraapi.PreviousConsentSession, error) {
	// TODO: consider support page param.
	u := hydraAdminURL + "/oauth2/auth/sessions/consent?subject=" + subject

	resp := []*hydraapi.PreviousConsentSession{}
	if err := httpGet(client, u, &resp); err != nil {
		return nil, err
	}

	return resp, nil
}

// RevokeConsents revokes all consents of user for a client. clientID is optional, will revoke all consent of user if no clientID.
func RevokeConsents(client *http.Client, hydraAdminURL, subject, clientID string) error {
	u, err := url.Parse(hydraAdminURL + "/oauth2/auth/sessions/consent")
	if err != nil {
		return err
	}

	q := url.Values{}
	q.Add("subject", subject)
	if len(clientID) != 0 {
		q.Add("client", clientID)
	}

	u.RawQuery = q.Encode()

	return httpDelete(client, u.String())
}

// RevokeToken revokes the given token, token maybe refresh token or access token.
func RevokeToken(client *http.Client, hydraAdminURL, token string) error {
	u, err := url.Parse(hydraAdminURL + "/oauth2/revoke")
	if err != nil {
		return status.Errorf(codes.Internal, "invalid hydraAdminURL: %v", err)
	}

	q := url.Values{}
	q.Add("token", token)

	req, err := http.NewRequest(http.MethodPost, u.String(), bytes.NewBufferString(q.Encode()))
	if err != nil {
		return status.Errorf(codes.Internal, "http.NewRequest for RevokeToken failed to initialize: %v", err)
	}

	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Accept", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return status.Errorf(codes.Unavailable, "RevokeToken to hydra failed: %v", err)
	}
	defer resp.Body.Close()

	// Doc shows API may return empty body for success response.
	// https://www.ory.sh/docs/next/hydra/sdk/api#revoke-oauth2-tokens
	if httputils.IsHTTPSuccess(resp.StatusCode) {
		return nil
	}

	return httpResponse(resp, nil)
}

func getURL(hydraAdminURL, flow, challenge string) string {
	const getURLPattern = "%s/oauth2/auth/requests/%s?%s_challenge=%s"
	return fmt.Sprintf(getURLPattern, hydraAdminURL, flow, flow, url.QueryEscape(challenge))
}

func putURL(hydraAdminURL, flow, action, challenge string) string {
	const putURLPattern = "%s/oauth2/auth/requests/%s/%s?%s_challenge=%s"
	return fmt.Sprintf(putURLPattern, hydraAdminURL, flow, action, flow, url.QueryEscape(challenge))
}

func httpResponse(resp *http.Response, response interface{}) error {
	if httputils.IsHTTPError(resp.StatusCode) {
		gErr := &hydraapi.GenericError{}
		if err := httputils.DecodeJSON(resp.Body, gErr); err != nil {
			return status.Errorf(codes.Internal, "DecodeJSON() failed: %v", err)
		}
		// TODO: figure out what error from hydra should handle.
		log.Errorf("error from hydra: %v, debug info: %s", gErr, gErr.Debug)
		return toStatusErr(gErr)
	}

	return httputils.DecodeJSON(resp.Body, response)
}

func toStatusErr(err *hydraapi.GenericError) error {
	reason := ""
	if err.Name != nil {
		reason = *err.Name
	}
	return errutil.WithErrorReason(
		reason,
		status.Errorf(httputils.RPCCode(int(err.Code)), err.Description),
	)
}

func httpPut(client *http.Client, url string, request interface{}, response interface{}) error {
	body, err := json.Marshal(request)
	if err != nil {
		return err
	}

	req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(body))
	if err != nil {
		return status.Errorf(codes.Internal, "http.NewRequest for httpPut failed to initialize: %v", err)
	}

	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return status.Errorf(codes.Unavailable, "httpPut to hydra failed: %v", err)
	}
	defer resp.Body.Close()

	return httpResponse(resp, response)
}

func httpPostJSON(client *http.Client, url string, request interface{}, response interface{}) error {
	body, err := json.Marshal(request)
	if err != nil {
		return err
	}

	req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(body))
	if err != nil {
		return status.Errorf(codes.Internal, "http.NewRequest for httpPostJSON failed to initialize: %v", err)
	}

	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return status.Errorf(codes.Unavailable, "httpPostJSON to hydra failed: %v", err)
	}
	defer resp.Body.Close()

	return httpResponse(resp, response)
}

func httpDelete(client *http.Client, url string) error {
	req, err := http.NewRequest(http.MethodDelete, url, nil)
	if err != nil {
		return status.Errorf(codes.Internal, "http.NewRequest for httpDelete failed to initialize: %v", err)
	}

	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return status.Errorf(codes.Unavailable, "httpDelete to hydra failed: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusNoContent {
		return nil
	}
	return httpResponse(resp, nil)
}

func httpGet(client *http.Client, url string, response interface{}) error {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return status.Errorf(codes.Internal, "http.NewRequest for httpGet failed to initialize: %v", err)
	}

	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return status.Errorf(codes.Unavailable, "httpGet to hydra failed: %v", err)
	}
	defer resp.Body.Close()

	return httpResponse(resp, response)
}
<commit_msg>fix package name<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      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 hydra contains helpers for using hydra
package hydra

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"

	"google.golang.org/grpc/codes" /* copybara-comment */
	"google.golang.org/grpc/status" /* copybara-comment */
	"github.com/GoogleCloudPlatform/healthcare-federated-access-services/apis/hydraapi" /* copybara-comment: hydraapi */
	"github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/errutil" /* copybara-comment: errutil */
	"github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/httputils" /* copybara-comment: httputils */

	glog "github.com/golang/glog" /* copybara-comment */
)

// GetLoginRequest fetches information on a login request.
func GetLoginRequest(client *http.Client, hydraAdminURL, challenge string) (*hydraapi.LoginRequest, error) {
	u := getURL(hydraAdminURL, "login", url.QueryEscape(challenge))
	resp := &hydraapi.LoginRequest{}
	err := httpGet(client, u, resp)
	return resp, err
}

// AcceptLogin tells hydra to accept a login request.
func AcceptLogin(client *http.Client, hydraAdminURL, challenge string, r *hydraapi.HandledLoginRequest) (*hydraapi.RequestHandlerResponse, error) {
	u := putURL(hydraAdminURL, "login", "accept", url.QueryEscape(challenge))
	resp := &hydraapi.RequestHandlerResponse{}
	err := httpPut(client, u, r, resp)
	return resp, err
}

// RejectLogin tells hydra to reject a login request.
func RejectLogin(client *http.Client, hydraAdminURL, challenge string, r *hydraapi.RequestDeniedError) (*hydraapi.RequestHandlerResponse, error) {
	u := putURL(hydraAdminURL, "login", "reject", url.QueryEscape(challenge))
	resp := &hydraapi.RequestHandlerResponse{}
	err := httpPut(client, u, r, resp)
	return resp, err
}

// GetConsentRequest fetches information on a consent request.
func GetConsentRequest(client *http.Client, hydraAdminURL, challenge string) (*hydraapi.ConsentRequest, error) {
	u := getURL(hydraAdminURL, "consent", url.QueryEscape(challenge))
	resp := &hydraapi.ConsentRequest{}
	err := httpGet(client, u, resp)
	return resp, err
}

// AcceptConsent tells hydra to accept a consent request.
func AcceptConsent(client *http.Client, hydraAdminURL, challenge string, r *hydraapi.HandledConsentRequest) (*hydraapi.RequestHandlerResponse, error) {
	u := putURL(hydraAdminURL, "consent", "accept", url.QueryEscape(challenge))
	resp := &hydraapi.RequestHandlerResponse{}
	err := httpPut(client, u, r, resp)
	return resp, err
}

// RejectConsent tells hydra to rejects a consent request.
func RejectConsent(client *http.Client, hydraAdminURL, challenge string, r *hydraapi.RequestDeniedError) (*hydraapi.RequestHandlerResponse, error) {
	u := putURL(hydraAdminURL, "consent", "reject", url.QueryEscape(challenge))
	resp := &hydraapi.RequestHandlerResponse{}
	err := httpPut(client, u, r, resp)
	return resp, err
}

// ListClients list all OAuth clients in hydra.
func ListClients(client *http.Client, hydraAdminURL string) ([]*hydraapi.Client, error) {
	u := hydraAdminURL + "/clients"
	resp := []*hydraapi.Client{}
	err := httpGet(client, u, &resp)
	return resp, err
}

// CreateClient creates OAuth client in hydra.
func CreateClient(client *http.Client, hydraAdminURL string, oauthClient *hydraapi.Client) (*hydraapi.Client, error) {
	u := hydraAdminURL + "/clients"
	resp := &hydraapi.Client{}
	err := httpPostJSON(client, u, oauthClient, resp)
	return resp, err
}

// GetClient gets an OAUth 2.0 client by its ID.
func GetClient(client *http.Client, hydraAdminURL, id string) (*hydraapi.Client, error) {
	u := hydraAdminURL + "/clients/" + id
	resp := &hydraapi.Client{}
	err := httpGet(client, u, resp)
	return resp, err
}

// UpdateClient updates an existing OAuth 2.0 Client.
func UpdateClient(client *http.Client, hydraAdminURL, id string, oauthClient *hydraapi.Client) (*hydraapi.Client, error) {
	u := hydraAdminURL + "/clients/" + id
	resp := &hydraapi.Client{}
	err := httpPut(client, u, oauthClient, resp)
	return resp, err
}

// DeleteClient delete an existing OAuth 2.0 Client by its ID.
func DeleteClient(client *http.Client, hydraAdminURL, id string) error {
	u := hydraAdminURL + "/clients/" + id
	err := httpDelete(client, u)
	return err
}

// Introspect token, validate the given token and return token claims.
func Introspect(client *http.Client, hydraAdminURL, token string) (*hydraapi.Introspection, error) {
	u := hydraAdminURL + "/oauth2/introspect"

	data := url.Values{}
	data.Set("token", url.QueryEscape(token))

	response := &hydraapi.Introspection{}

	req, err := http.NewRequest(http.MethodPost, u, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, status.Errorf(codes.Internal, "http.NewRequest for Introspect failed to initialize: %v", err)
	}

	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Accept", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return nil, status.Errorf(codes.Unavailable, "Introspect to hydra failed: %v", err)
	}
	defer resp.Body.Close()

	if err := httpResponse(resp, response); err != nil {
		return nil, err
	}
	return response, nil
}

// ListConsents lists all consents of user (subject).
func ListConsents(client *http.Client, hydraAdminURL, subject string) ([]*hydraapi.PreviousConsentSession, error) {
	// TODO: consider support page param.
	u := hydraAdminURL + "/oauth2/auth/sessions/consent?subject=" + subject

	resp := []*hydraapi.PreviousConsentSession{}
	if err := httpGet(client, u, &resp); err != nil {
		return nil, err
	}

	return resp, nil
}

// RevokeConsents revokes all consents of user for a client. clientID is optional, will revoke all consent of user if no clientID.
func RevokeConsents(client *http.Client, hydraAdminURL, subject, clientID string) error {
	u, err := url.Parse(hydraAdminURL + "/oauth2/auth/sessions/consent")
	if err != nil {
		return err
	}

	q := url.Values{}
	q.Add("subject", subject)
	if len(clientID) != 0 {
		q.Add("client", clientID)
	}

	u.RawQuery = q.Encode()

	return httpDelete(client, u.String())
}

// RevokeToken revokes the given token, token maybe refresh token or access token.
func RevokeToken(client *http.Client, hydraAdminURL, token string) error {
	u, err := url.Parse(hydraAdminURL + "/oauth2/revoke")
	if err != nil {
		return status.Errorf(codes.Internal, "invalid hydraAdminURL: %v", err)
	}

	q := url.Values{}
	q.Add("token", token)

	req, err := http.NewRequest(http.MethodPost, u.String(), bytes.NewBufferString(q.Encode()))
	if err != nil {
		return status.Errorf(codes.Internal, "http.NewRequest for RevokeToken failed to initialize: %v", err)
	}

	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Accept", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return status.Errorf(codes.Unavailable, "RevokeToken to hydra failed: %v", err)
	}
	defer resp.Body.Close()

	// Doc shows API may return empty body for success response.
	// https://www.ory.sh/docs/next/hydra/sdk/api#revoke-oauth2-tokens
	if httputils.IsHTTPSuccess(resp.StatusCode) {
		return nil
	}

	return httpResponse(resp, nil)
}

func getURL(hydraAdminURL, flow, challenge string) string {
	const getURLPattern = "%s/oauth2/auth/requests/%s?%s_challenge=%s"
	return fmt.Sprintf(getURLPattern, hydraAdminURL, flow, flow, url.QueryEscape(challenge))
}

func putURL(hydraAdminURL, flow, action, challenge string) string {
	const putURLPattern = "%s/oauth2/auth/requests/%s/%s?%s_challenge=%s"
	return fmt.Sprintf(putURLPattern, hydraAdminURL, flow, action, flow, url.QueryEscape(challenge))
}

func httpResponse(resp *http.Response, response interface{}) error {
	if httputils.IsHTTPError(resp.StatusCode) {
		gErr := &hydraapi.GenericError{}
		if err := httputils.DecodeJSON(resp.Body, gErr); err != nil {
			return status.Errorf(codes.Internal, "DecodeJSON() failed: %v", err)
		}
		// TODO: figure out what error from hydra should handle.
		glog.Errorf("error from hydra: %v, debug info: %s", gErr, gErr.Debug)
		return toStatusErr(gErr)
	}

	return httputils.DecodeJSON(resp.Body, response)
}

func toStatusErr(err *hydraapi.GenericError) error {
	reason := ""
	if err.Name != nil {
		reason = *err.Name
	}
	return errutil.WithErrorReason(
		reason,
		status.Errorf(httputils.RPCCode(int(err.Code)), err.Description),
	)
}

func httpPut(client *http.Client, url string, request interface{}, response interface{}) error {
	body, err := json.Marshal(request)
	if err != nil {
		return err
	}

	req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(body))
	if err != nil {
		return status.Errorf(codes.Internal, "http.NewRequest for httpPut failed to initialize: %v", err)
	}

	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return status.Errorf(codes.Unavailable, "httpPut to hydra failed: %v", err)
	}
	defer resp.Body.Close()

	return httpResponse(resp, response)
}

func httpPostJSON(client *http.Client, url string, request interface{}, response interface{}) error {
	body, err := json.Marshal(request)
	if err != nil {
		return err
	}

	req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(body))
	if err != nil {
		return status.Errorf(codes.Internal, "http.NewRequest for httpPostJSON failed to initialize: %v", err)
	}

	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return status.Errorf(codes.Unavailable, "httpPostJSON to hydra failed: %v", err)
	}
	defer resp.Body.Close()

	return httpResponse(resp, response)
}

func httpDelete(client *http.Client, url string) error {
	req, err := http.NewRequest(http.MethodDelete, url, nil)
	if err != nil {
		return status.Errorf(codes.Internal, "http.NewRequest for httpDelete failed to initialize: %v", err)
	}

	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return status.Errorf(codes.Unavailable, "httpDelete to hydra failed: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusNoContent {
		return nil
	}
	return httpResponse(resp, nil)
}

func httpGet(client *http.Client, url string, response interface{}) error {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return status.Errorf(codes.Internal, "http.NewRequest for httpGet failed to initialize: %v", err)
	}

	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return status.Errorf(codes.Unavailable, "httpGet to hydra failed: %v", err)
	}
	defer resp.Body.Close()

	return httpResponse(resp, response)
}
<|endoftext|>


<commit_before>// +build integration

package integration

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"testing"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/client-go/pkg/api"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"

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

	// For client auth plugins
	_ "k8s.io/client-go/plugin/pkg/client/auth"

	// For apimachinery serialisation magic
	_ "k8s.io/client-go/pkg/api/install"
)

var kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
var kubecfgBin = flag.String("kubecfg-bin", "kubecfg", "path to kubecfg executable under test")

func init() {
	if missingVersions := api.Registry.ValidateEnvRequestedVersions(); len(missingVersions) != 0 {
		panic(fmt.Sprintf("KUBE_API_VERSIONS contains versions that are not installed: %q.", missingVersions))
	}
}

func clusterConfigOrDie() *rest.Config {
	var config *rest.Config
	var err error

	if *kubeconfig != "" {
		config, err = clientcmd.BuildConfigFromFlags("", *kubeconfig)
	} else {
		config, err = rest.InClusterConfig()
	}
	if err != nil {
		panic(err.Error())
	}

	return config
}

func createNsOrDie(c corev1.CoreV1Interface, ns string) string {
	result, err := c.Namespaces().Create(
		&v1.Namespace{
			ObjectMeta: metav1.ObjectMeta{
				GenerateName: ns,
			},
		})
	if err != nil {
		panic(err.Error())
	}
	name := result.GetName()
	fmt.Fprintf(GinkgoWriter, "Created namespace %s\n", name)
	return name
}

func deleteNsOrDie(c corev1.CoreV1Interface, ns string) {
	err := c.Namespaces().Delete(ns, &metav1.DeleteOptions{})
	if err != nil {
		panic(err.Error())
	}
}

func runKubecfgWith(flags []string, input []runtime.Object) error {
	tmpdir, err := ioutil.TempDir("", "kubecfg-testdata")
	if err != nil {
		return err
	}
	defer os.RemoveAll(tmpdir)

	fname := filepath.Join(tmpdir, "input.yaml")

	f, err := os.Create(fname)
	if err != nil {
		return err
	}
	enc := api.Codecs.LegacyCodec(v1.SchemeGroupVersion)
	for _, o := range input {
		buf, err := runtime.Encode(enc, o)
		if err != nil {
			return err
		}
		fmt.Fprintf(f, "---\n")
		_, err = f.Write(buf)
		if err != nil {
			return err
		}
	}
	if err := f.Close(); err != nil {
		return err
	}

	args := []string{}
	args = append(args, flags...)
	args = append(args, fname)

	fmt.Fprintf(GinkgoWriter, "Running %q %q\n", *kubecfgBin, args)
	cmd := exec.Command(*kubecfgBin, args...)
	cmd.Stdout = GinkgoWriter
	cmd.Stderr = GinkgoWriter

	if err := cmd.Run(); err != nil {
		return err
	}

	return nil
}

func TestE2e(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "kubecfg integration tests")
}
<commit_msg>fix integration tests<commit_after>// +build integration

package integration

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"testing"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/client-go/pkg/api"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"

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

	// For client auth plugins
	_ "k8s.io/client-go/plugin/pkg/client/auth"

	// For apimachinery serialisation magic
	_ "k8s.io/client-go/pkg/api/install"
)

var kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
var kubecfgBin = flag.String("kubecfg-bin", "kubecfg", "path to kubecfg executable under test")

func init() {
	if missingVersions := api.Registry.ValidateEnvRequestedVersions(); len(missingVersions) != 0 {
		panic(fmt.Sprintf("KUBE_API_VERSIONS contains versions that are not installed: %q.", missingVersions))
	}
}

func clusterConfigOrDie() *rest.Config {
	var config *rest.Config
	var err error

	if *kubeconfig != "" {
		config, err = clientcmd.BuildConfigFromFlags("", *kubeconfig)
	} else {
		config, err = rest.InClusterConfig()
	}
	if err != nil {
		panic(err.Error())
	}

	return config
}

func createNsOrDie(c corev1.CoreV1Interface, ns string) string {
	result, err := c.Namespaces().Create(
		&v1.Namespace{
			ObjectMeta: metav1.ObjectMeta{
				GenerateName: ns,
			},
		})
	if err != nil {
		panic(err.Error())
	}
	name := result.GetName()
	fmt.Fprintf(GinkgoWriter, "Created namespace %s\n", name)
	return name
}

func deleteNsOrDie(c corev1.CoreV1Interface, ns string) {
	err := c.Namespaces().Delete(ns, &metav1.DeleteOptions{})
	if err != nil {
		panic(err.Error())
	}
}

func runKubecfgWith(flags []string, input []runtime.Object) error {
	tmpdir, err := ioutil.TempDir("", "kubecfg-testdata")
	if err != nil {
		return err
	}
	defer os.RemoveAll(tmpdir)

	fname := filepath.Join(tmpdir, "input.yaml")

	f, err := os.Create(fname)
	if err != nil {
		return err
	}
	enc := api.Codecs.LegacyCodec(v1.SchemeGroupVersion)
	for _, o := range input {
		buf, err := runtime.Encode(enc, o)
		if err != nil {
			return err
		}
		fmt.Fprintf(f, "---\n")
		_, err = f.Write(buf)
		if err != nil {
			return err
		}
	}
	if err := f.Close(); err != nil {
		return err
	}

	args := []string{}
	args = append(args, flags...)
	args = append(args, "-f")
	args = append(args, fname)

	fmt.Fprintf(GinkgoWriter, "Running %q %q\n", *kubecfgBin, args)
	cmd := exec.Command(*kubecfgBin, args...)
	cmd.Stdout = GinkgoWriter
	cmd.Stderr = GinkgoWriter

	if err := cmd.Run(); err != nil {
		return err
	}

	return nil
}

func TestE2e(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "kubecfg integration tests")
}
<|endoftext|>


<commit_before>package lifecycle_test

import (
	"runtime/debug"
	"time"

	"github.com/cloudfoundry-incubator/garden"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

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

	var container garden.Container

	BeforeEach(func() {
		client = startGarden()
		var err error
		container, err = client.Create(garden.ContainerSpec{})
		Expect(err).ToNot(HaveOccurred())
	})

	Describe("signalling", func() {
		It("a process can be sent SIGTERM immediately after having been started", func() {
			stdout := gbytes.NewBuffer()

			process, err := container.Run(garden.ProcessSpec{
				User: "vcap",
				Path: "sh",
				Args: []string{
					"-c",
					`
                sleep 10
                exit 12
                `,
				},
			}, garden.ProcessIO{
				Stdout: stdout,
			})
			Expect(err).ToNot(HaveOccurred())

			err = process.Signal(garden.SignalTerminate)
			Expect(err).ToNot(HaveOccurred())
			Expect(process.Wait()).NotTo(Equal(12))
		})
	})

	startAndWait := func() (garden.Process, <-chan int) {
		buf := gbytes.NewBuffer()
		procIo := garden.ProcessIO{
			Stdout: buf,
			Stderr: buf,
		}
		process, err := container.Run(garden.ProcessSpec{
			User: "vcap",
			Path: "sh",
			Args: []string{"-c", `
				  trap 'echo termed; exit 42' SIGTERM

					while true; do
					  echo waiting
					  sleep 1
					done
				`},
		}, procIo)
		Expect(err).NotTo(HaveOccurred())

		attachedProcess, err := container.Attach(process.ID(), procIo)
		Expect(err).NotTo(HaveOccurred())
		Eventually(buf).Should(gbytes.Say("waiting"))

		exitChan := make(chan int)
		go func(p garden.Process, exited chan<- int) {
			GinkgoRecover()
			status, waitErr := p.Wait()
			Expect(waitErr).NotTo(HaveOccurred())
			exited <- status
		}(attachedProcess, exitChan)

		return attachedProcess, exitChan
	}

	waitForExit := func(p garden.Process, e <-chan int) {
		buf := gbytes.NewBuffer()
		procIo := garden.ProcessIO{
			Stdout: buf,
			Stderr: buf,
		}
		attachedProcess, err := container.Attach(p.ID(), procIo)
		Expect(err).NotTo(HaveOccurred())
		Eventually(buf).Should(gbytes.Say("waiting"))

		Expect(attachedProcess.Signal(garden.SignalTerminate)).To(Succeed())
		select {
		case status := <-e:
			Expect(status).To(Equal(42))
			Eventually(buf).Should(gbytes.Say("termed"))
		case <-time.After(time.Second * 10):
			debug.PrintStack()
			Fail("timed out!")
		}
	}

	It("should not allow process outcomes to interfere with each other", func() {
		p1, e1 := startAndWait()
		p2, e2 := startAndWait()
		p3, e3 := startAndWait()
		p4, e4 := startAndWait()

		waitForExit(p1, e1)
		waitForExit(p2, e2)
		waitForExit(p4, e4)
		waitForExit(p3, e3)
	})
})
<commit_msg>Test to verify current behaviour of process.Wait() when there are child processes<commit_after>package lifecycle_test

import (
	"os"
	"runtime/debug"
	"time"

	"github.com/cloudfoundry-incubator/garden"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

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

	var container garden.Container

	BeforeEach(func() {
		client = startGarden()
		var err error
		container, err = client.Create(garden.ContainerSpec{
			RootFSPath: os.Getenv("GARDEN_NESTABLE_TEST_ROOTFS"),
		})
		Expect(err).ToNot(HaveOccurred())
	})

	Describe("signalling", func() {
		It("a process can be sent SIGTERM immediately after having been started", func() {
			stdout := gbytes.NewBuffer()

			process, err := container.Run(garden.ProcessSpec{
				User: "vcap",
				Path: "sh",
				Args: []string{
					"-c",
					`
                sleep 10
                exit 12
                `,
				},
			}, garden.ProcessIO{
				Stdout: stdout,
			})
			Expect(err).ToNot(HaveOccurred())

			err = process.Signal(garden.SignalTerminate)
			Expect(err).ToNot(HaveOccurred())
			Expect(process.Wait()).NotTo(Equal(12))
		})
	})

	It("wait returns when all children of the process have exited", func() {
		process, err := container.Run(garden.ProcessSpec{
			User: "vcap",
			Path: "/bin/bash",
			Args: []string{"-c", `

				  cleanup ()
				  {
				  	kill $child_pid
				  	exit 42
				  }

				  trap cleanup TERM

				  sleep 1000 &
				  child_pid=$!
				  wait
				`},
		}, garden.ProcessIO{})
		Expect(err).NotTo(HaveOccurred())

		exitChan := make(chan int)
		go func(p garden.Process, exited chan<- int) {
			GinkgoRecover()
			status, waitErr := p.Wait()
			Expect(waitErr).NotTo(HaveOccurred())
			exited <- status
		}(process, exitChan)

		Expect(process.Signal(garden.SignalTerminate)).To(Succeed())
		select {
		case status := <-exitChan:
			Expect(status).To(Equal(42))
		case <-time.After(time.Second * 10):
			debug.PrintStack()
			Fail("timed out!")
		}
	})

	It("wait blocks when a child of the process has not exited", func() {
		process, err := container.Run(garden.ProcessSpec{
			User: "vcap",
			Path: "/bin/bash",
			Args: []string{"-c", `
					cleanup ()
					{
					  exit 42
					}

					trap cleanup TERM

					sleep 1000 &
					wait
				`},
		}, garden.ProcessIO{})
		Expect(err).NotTo(HaveOccurred())

		exitChan := make(chan int)
		go func(p garden.Process, exited chan<- int) {
			GinkgoRecover()
			status, waitErr := p.Wait()
			Expect(waitErr).NotTo(HaveOccurred())
			exited <- status
		}(process, exitChan)

		Expect(process.Signal(garden.SignalTerminate)).To(Succeed())
		select {
		case <-exitChan:
			Fail("Wait should block as a child has not exited")
		case <-time.After(time.Second * 10):
		}
	})

})
<|endoftext|>


<commit_before>package hostdb

import (
	"math"
	"math/big"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

var (
	// Because most weights would otherwise be fractional, we set the base
	// weight to be very large.
	baseWeight = types.NewCurrency(new(big.Int).Exp(big.NewInt(10), big.NewInt(80), nil))

	// tbMonth is the number of bytes in a terabyte times the number of blocks
	// in a month.
	tbMonth = uint64(4032) * uint64(1e12)

	// collateralExponentiation is the number of times that the collateral is
	// multiplied into the price.
	collateralExponentiation = 1

	// priceDiveNormalization reduces the raw value of the price so that not so
	// many digits are needed when operating on the weight. This also allows the
	// base weight to be a lot lower.
	priceDivNormalization = types.SiacoinPrecision.Div64(10e3).Div64(tbMonth)

	// minCollateral is the amount of collateral we weight all hosts as having,
	// even if they do not have any collateral. This is to temporarily prop up
	// weak / cheap hosts on the network while the network is bootstrapping.
	minCollateral = types.SiacoinPrecision.Mul64(25).Div64(tbMonth)

	// Set a mimimum price, below which setting lower prices will no longer put
	// this host at an advatnage. This price is considered the bar for
	// 'essentially free', and is kept to a minimum to prevent certain Sybil
	// attack related attack vectors.
	//
	// NOTE: This needs to be intelligently adjusted down as the practical price
	// of storage changes, and as the price of the siacoin changes.
	minTotalPrice = types.SiacoinPrecision.Mul64(250).Div64(tbMonth)

	// priceExponentiation is the number of times that the weight is divided by
	// the price.
	priceExponentiation = 5

	// requiredStorage indicates the amount of storage that the host must be
	// offering in order to be considered a valuable/worthwhile host.
	requiredStorage = build.Select(build.Var{
		Standard: uint64(20e9),
		Dev:      uint64(1e6),
		Testing:  uint64(1e3),
	}).(uint64)
)

// collateralAdjustments improves the host's weight according to the amount of
// collateral that they have provided.
func (hdb *HostDB) collateralAdjustments(entry modules.HostDBEntry) float64 {
	// Sanity checks - the constants values need to have certain relationships
	// to eachother
	if build.DEBUG {
		// If the minTotalPrice is not much larger than the divNormalization,
		// there will be problems with granularity after the divNormalization is
		// applied.
		if minCollateral.Div64(1e3).Cmp(priceDivNormalization) < 0 {
			build.Critical("Maladjusted minCollateral and divNormalization constants in hostdb package")
		}
	}

	// Set a minimum on the collateral, then normalize to a sane precision.
	usedCollateral := entry.Collateral
	if entry.Collateral.Cmp(minCollateral) < 0 {
		usedCollateral = minCollateral
	}
	baseU64, err := minCollateral.Div(priceDivNormalization).Uint64()
	if err != nil {
		baseU64 = math.MaxUint64
	}
	actualU64, err := usedCollateral.Div(priceDivNormalization).Uint64()
	if err != nil {
		actualU64 = math.MaxUint64
	}
	base := float64(baseU64)
	actual := float64(actualU64)

	// Exponentiate the results.
	weight := float64(1)
	for i := 0; i < collateralExponentiation; i++ {
		weight *= actual / base
	}
	return weight
}

// priceAdjustments will adjust the weight of the entry according to the prices
// that it has set.
func (hdb *HostDB) priceAdjustments(entry modules.HostDBEntry) float64 {
	// Sanity checks - the constants values need to have certain relationships
	// to eachother
	if build.DEBUG {
		// If the minTotalPrice is not much larger than the divNormalization,
		// there will be problems with granularity after the divNormalization is
		// applied.
		if minTotalPrice.Div64(1e3).Cmp(priceDivNormalization) < 0 {
			build.Critical("Maladjusted minDivePrice and divNormalization constants in hostdb package")
		}
	}

	// Prices tiered as follows:
	//    - the storage price is presented as 'per block per byte'
	//    - the contract price is presented as a flat rate
	//    - the upload bandwidth price is per byte
	//    - the download bandwidth price is per byte
	//
	// The hostdb will naively assume the following for now:
	//    - each contract covers 6 weeks of storage (default is 12 weeks, but
	//      renewals occur at midpoint) - 6048 blocks - and 25GB of storage.
	//    - uploads happen once per 12 weeks (average lifetime of a file is 12 weeks)
	//    - downloads happen once per 12 weeks (files are on average downloaded once throughout lifetime)
	//
	// In the future, the renter should be able to track average user behavior
	// and adjust accordingly. This flexibility will be added later.
	adjustedContractPrice := entry.ContractPrice.Div64(6048).Div64(25e9)        // Adjust contract price to match 25GB for 6 weeks.
	adjustedUploadPrice := entry.UploadBandwidthPrice.Div64(24192)              // Adjust upload price to match a single upload over 24 weeks.
	adjustedDownloadPrice := entry.DownloadBandwidthPrice.Div64(12096).Div64(3) // Adjust download price to match one download over 12 weeks, 1 redundancy.
	siafundFee := adjustedContractPrice.Add(adjustedUploadPrice).Add(adjustedDownloadPrice).Add(entry.Collateral).MulTax()
	totalPrice := entry.StoragePrice.Add(adjustedContractPrice).Add(adjustedUploadPrice).Add(adjustedDownloadPrice).Add(siafundFee)

	// Set a minimum on the price, then normalize to a sane precision.
	if totalPrice.Cmp(minTotalPrice) < 0 {
		totalPrice = minTotalPrice
	}
	baseU64, err := minTotalPrice.Div(priceDivNormalization).Uint64()
	if err != nil {
		baseU64 = math.MaxUint64
	}
	actualU64, err := totalPrice.Div(priceDivNormalization).Uint64()
	if err != nil {
		actualU64 = math.MaxUint64
	}
	base := float64(baseU64)
	actual := float64(actualU64)

	weight := float64(1)
	for i := 0; i < priceExponentiation; i++ {
		weight *= base / actual
	}
	return weight
}

// storageRemainingAdjustments adjusts the weight of the entry according to how
// much storage it has remaining.
func storageRemainingAdjustments(entry modules.HostDBEntry) float64 {
	base := float64(1)
	if entry.RemainingStorage < 200*requiredStorage {
		base = base / 2 // 2x total penalty
	}
	if entry.RemainingStorage < 150*requiredStorage {
		base = base / 2 // 4x total penalty
	}
	if entry.RemainingStorage < 100*requiredStorage {
		base = base / 3 // 12x total penalty
	}
	if entry.RemainingStorage < 80*requiredStorage {
		base = base / 3 // 36x total penalty
	}
	if entry.RemainingStorage < 40*requiredStorage {
		base = base / 4 // 144x total penalty
	}
	if entry.RemainingStorage < 20*requiredStorage {
		base = base / 5 // 720x total penalty
	}
	if entry.RemainingStorage < 10*requiredStorage {
		base = base / 5 // 3,600x total penalty
	}
	if entry.RemainingStorage < 5*requiredStorage {
		base = base / 5 // 14,400x total penalty
	}
	if entry.RemainingStorage < requiredStorage {
		base = base / 5 // 72,000x total penalty
	}
	return base
}

// versionAdjustments will adjust the weight of the entry according to the siad
// version reported by the host.
func versionAdjustments(entry modules.HostDBEntry) float64 {
	base := float64(1)
	if build.VersionCmp(entry.Version, "1.1.2") <= 0 {
		base = base * 0.99999 // Safety value to make sure we update the version penalties every time we update the host.
	}
	if build.VersionCmp(entry.Version, "1.1.1") < 0 {
		base = base / 5 // 5x total penalty.
	}
	if build.VersionCmp(entry.Version, "1.0.3") < 0 {
		base = base / 5 // 25x total penalty.
	}
	if build.VersionCmp(entry.Version, "1.0.0") < 0 {
		base = base / 20 // 500x total penalty.
	}
	return base
}

// lifetimeAdjustments will adjust the weight of the host according to the total
// amount of time that has passed since the host's original announcement.
func (hdb *HostDB) lifetimeAdjustments(entry modules.HostDBEntry) float64 {
	base := float64(1)
	if hdb.blockHeight >= entry.FirstSeen {
		age := hdb.blockHeight - entry.FirstSeen
		if age < 6000 {
			base = base / 2 // 2x total
		}
		if age < 4000 {
			base = base / 2 // 4x total
		}
		if age < 2000 {
			base = base / 2 // 8x total
		}
		if age < 1000 {
			base = base / 8 // 64x total
		}
		if age < 576 {
			base = base / 2 // 128x total
		}
		if age < 288 {
			base = base / 2 // 256x total
		}
	}
	return base
}

// uptimeAdjustments penalizes the host for having poor uptime, and for being
// offline.
//
// CAUTION: The function 'updateEntry' will manually fill out two scans for a
// new host to give the host some initial uptime or downtime. Modification of
// this function needs to be made paying attention to the structure of that
// function.
func (hdb *HostDB) uptimeAdjustments(entry modules.HostDBEntry) float64 {
	// Special case: if we have scanned the host twice or fewer, don't perform
	// uptime math.
	if len(entry.ScanHistory) == 0 {
		return 0.25
	}
	if len(entry.ScanHistory) == 1 {
		if entry.ScanHistory[0].Success {
			return 0.75
		}
		return 0.25
	}
	if len(entry.ScanHistory) == 2 {
		if entry.ScanHistory[0].Success && entry.ScanHistory[1].Success {
			return 0.85
		}
		if entry.ScanHistory[0].Success || entry.ScanHistory[1].Success {
			return 0.50
		}
		return 0.05
	}

	// Compute the total measured uptime and total measured downtime for this
	// host.
	downtime := entry.HistoricDowntime
	uptime := entry.HistoricUptime
	recentTime := entry.ScanHistory[0].Timestamp
	recentSuccess := entry.ScanHistory[0].Success
	for _, scan := range entry.ScanHistory[1:] {
		if recentTime.After(scan.Timestamp) {
			hdb.log.Critical("Host entry scan history not sorted.")
			// Ignore the unsorted scan entry.
			continue
		}
		if recentSuccess {
			uptime += scan.Timestamp.Sub(recentTime)
		} else {
			downtime += scan.Timestamp.Sub(recentTime)
		}
		recentTime = scan.Timestamp
		recentSuccess = scan.Success
	}
	// Sanity check against 0 total time.
	if uptime == 0 && downtime == 0 {
		return 0.001 // Shouldn't happen.
	}

	// Compute the uptime ratio, but shift by 0.02 to acknowledge fully that
	// 98% uptime and 100% uptime is valued the same.
	uptimeRatio := float64(uptime) / float64(uptime+downtime)
	if uptimeRatio > 0.98 {
		uptimeRatio = 0.98
	}
	uptimeRatio += 0.02

	// Cap the total amount of downtime allowed based on the total number of
	// scans that have happened.
	allowedDowntime := 0.03 * float64(len(entry.ScanHistory))
	if uptimeRatio < 1-allowedDowntime {
		uptimeRatio = 1 - allowedDowntime
	}

	// Calculate the penalty for low uptime. Penalties increase extremely
	// quickly as uptime falls away from 95%.
	//
	// 100% uptime = 1
	// 98%  uptime = 1
	// 95%  uptime = 0.91
	// 90%  uptime = 0.51
	// 85%  uptime = 0.16
	// 80%  uptime = 0.03
	// 75%  uptime = 0.005
	// 70%  uptime = 0.001
	// 50%  uptime = 0.000002
	exp := 100 * math.Min(1-uptimeRatio, 0.20)
	return math.Pow(uptimeRatio, exp)
}

// calculateHostWeight returns the weight of a host according to the settings of
// the host database entry. Currently, only the price is considered.
func (hdb *HostDB) calculateHostWeight(entry modules.HostDBEntry) types.Currency {
	collateralReward := hdb.collateralAdjustments(entry)
	pricePenalty := hdb.priceAdjustments(entry)
	storageRemainingPenalty := storageRemainingAdjustments(entry)
	versionPenalty := versionAdjustments(entry)
	lifetimePenalty := hdb.lifetimeAdjustments(entry)
	uptimePenalty := hdb.uptimeAdjustments(entry)

	// Combine the adjustments.
	fullPenalty := collateralReward * pricePenalty * storageRemainingPenalty * versionPenalty * lifetimePenalty * uptimePenalty

	// Return a types.Currency.
	weight := baseWeight.MulFloat(fullPenalty)
	if weight.IsZero() {
		// A weight of zero is problematic for for the host tree.
		return types.NewCurrency64(1)
	}
	return weight
}

// ScoreBreakdown provdes a detailed set of scalars and bools indicating
// elements of the host's overall score.
func (hdb *HostDB) ScoreBreakdown(entry modules.HostDBEntry) modules.HostScoreBreakdown {
	return modules.HostScoreBreakdown{
		Score: hdb.calculateHostWeight(entry),

		AgeAdjustment:              hdb.lifetimeAdjustments(entry),
		BurnAdjustment:             1,
		CollateralAdjustment:       hdb.collateralAdjustments(entry),
		PriceAdjustment:            hdb.priceAdjustments(entry),
		StorageRemainingAdjustment: storageRemainingAdjustments(entry),
		UptimeAdjustment:           hdb.uptimeAdjustments(entry),
		VersionAdjustment:          versionAdjustments(entry),
	}
}
<commit_msg>soften remaining storage penalties<commit_after>package hostdb

import (
	"math"
	"math/big"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

var (
	// Because most weights would otherwise be fractional, we set the base
	// weight to be very large.
	baseWeight = types.NewCurrency(new(big.Int).Exp(big.NewInt(10), big.NewInt(80), nil))

	// tbMonth is the number of bytes in a terabyte times the number of blocks
	// in a month.
	tbMonth = uint64(4032) * uint64(1e12)

	// collateralExponentiation is the number of times that the collateral is
	// multiplied into the price.
	collateralExponentiation = 1

	// priceDiveNormalization reduces the raw value of the price so that not so
	// many digits are needed when operating on the weight. This also allows the
	// base weight to be a lot lower.
	priceDivNormalization = types.SiacoinPrecision.Div64(10e3).Div64(tbMonth)

	// minCollateral is the amount of collateral we weight all hosts as having,
	// even if they do not have any collateral. This is to temporarily prop up
	// weak / cheap hosts on the network while the network is bootstrapping.
	minCollateral = types.SiacoinPrecision.Mul64(25).Div64(tbMonth)

	// Set a mimimum price, below which setting lower prices will no longer put
	// this host at an advatnage. This price is considered the bar for
	// 'essentially free', and is kept to a minimum to prevent certain Sybil
	// attack related attack vectors.
	//
	// NOTE: This needs to be intelligently adjusted down as the practical price
	// of storage changes, and as the price of the siacoin changes.
	minTotalPrice = types.SiacoinPrecision.Mul64(250).Div64(tbMonth)

	// priceExponentiation is the number of times that the weight is divided by
	// the price.
	priceExponentiation = 5

	// requiredStorage indicates the amount of storage that the host must be
	// offering in order to be considered a valuable/worthwhile host.
	requiredStorage = build.Select(build.Var{
		Standard: uint64(20e9),
		Dev:      uint64(1e6),
		Testing:  uint64(1e3),
	}).(uint64)
)

// collateralAdjustments improves the host's weight according to the amount of
// collateral that they have provided.
func (hdb *HostDB) collateralAdjustments(entry modules.HostDBEntry) float64 {
	// Sanity checks - the constants values need to have certain relationships
	// to eachother
	if build.DEBUG {
		// If the minTotalPrice is not much larger than the divNormalization,
		// there will be problems with granularity after the divNormalization is
		// applied.
		if minCollateral.Div64(1e3).Cmp(priceDivNormalization) < 0 {
			build.Critical("Maladjusted minCollateral and divNormalization constants in hostdb package")
		}
	}

	// Set a minimum on the collateral, then normalize to a sane precision.
	usedCollateral := entry.Collateral
	if entry.Collateral.Cmp(minCollateral) < 0 {
		usedCollateral = minCollateral
	}
	baseU64, err := minCollateral.Div(priceDivNormalization).Uint64()
	if err != nil {
		baseU64 = math.MaxUint64
	}
	actualU64, err := usedCollateral.Div(priceDivNormalization).Uint64()
	if err != nil {
		actualU64 = math.MaxUint64
	}
	base := float64(baseU64)
	actual := float64(actualU64)

	// Exponentiate the results.
	weight := float64(1)
	for i := 0; i < collateralExponentiation; i++ {
		weight *= actual / base
	}
	return weight
}

// priceAdjustments will adjust the weight of the entry according to the prices
// that it has set.
func (hdb *HostDB) priceAdjustments(entry modules.HostDBEntry) float64 {
	// Sanity checks - the constants values need to have certain relationships
	// to eachother
	if build.DEBUG {
		// If the minTotalPrice is not much larger than the divNormalization,
		// there will be problems with granularity after the divNormalization is
		// applied.
		if minTotalPrice.Div64(1e3).Cmp(priceDivNormalization) < 0 {
			build.Critical("Maladjusted minDivePrice and divNormalization constants in hostdb package")
		}
	}

	// Prices tiered as follows:
	//    - the storage price is presented as 'per block per byte'
	//    - the contract price is presented as a flat rate
	//    - the upload bandwidth price is per byte
	//    - the download bandwidth price is per byte
	//
	// The hostdb will naively assume the following for now:
	//    - each contract covers 6 weeks of storage (default is 12 weeks, but
	//      renewals occur at midpoint) - 6048 blocks - and 25GB of storage.
	//    - uploads happen once per 12 weeks (average lifetime of a file is 12 weeks)
	//    - downloads happen once per 12 weeks (files are on average downloaded once throughout lifetime)
	//
	// In the future, the renter should be able to track average user behavior
	// and adjust accordingly. This flexibility will be added later.
	adjustedContractPrice := entry.ContractPrice.Div64(6048).Div64(25e9)        // Adjust contract price to match 25GB for 6 weeks.
	adjustedUploadPrice := entry.UploadBandwidthPrice.Div64(24192)              // Adjust upload price to match a single upload over 24 weeks.
	adjustedDownloadPrice := entry.DownloadBandwidthPrice.Div64(12096).Div64(3) // Adjust download price to match one download over 12 weeks, 1 redundancy.
	siafundFee := adjustedContractPrice.Add(adjustedUploadPrice).Add(adjustedDownloadPrice).Add(entry.Collateral).MulTax()
	totalPrice := entry.StoragePrice.Add(adjustedContractPrice).Add(adjustedUploadPrice).Add(adjustedDownloadPrice).Add(siafundFee)

	// Set a minimum on the price, then normalize to a sane precision.
	if totalPrice.Cmp(minTotalPrice) < 0 {
		totalPrice = minTotalPrice
	}
	baseU64, err := minTotalPrice.Div(priceDivNormalization).Uint64()
	if err != nil {
		baseU64 = math.MaxUint64
	}
	actualU64, err := totalPrice.Div(priceDivNormalization).Uint64()
	if err != nil {
		actualU64 = math.MaxUint64
	}
	base := float64(baseU64)
	actual := float64(actualU64)

	weight := float64(1)
	for i := 0; i < priceExponentiation; i++ {
		weight *= base / actual
	}
	return weight
}

// storageRemainingAdjustments adjusts the weight of the entry according to how
// much storage it has remaining.
func storageRemainingAdjustments(entry modules.HostDBEntry) float64 {
	base := float64(1)
	if entry.RemainingStorage < 200*requiredStorage {
		base = base / 2 // 2x total penalty
	}
	if entry.RemainingStorage < 150*requiredStorage {
		base = base / 2 // 4x total penalty
	}
	if entry.RemainingStorage < 100*requiredStorage {
		base = base / 2 // 8x total penalty
	}
	if entry.RemainingStorage < 80*requiredStorage {
		base = base / 2 // 16x total penalty
	}
	if entry.RemainingStorage < 40*requiredStorage {
		base = base / 2 // 32x total penalty
	}
	if entry.RemainingStorage < 20*requiredStorage {
		base = base / 2 // 64x total penalty
	}
	if entry.RemainingStorage < 15*requiredStorage {
		base = base / 2 // 128x total penalty
	}
	if entry.RemainingStorage < 10*requiredStorage {
		base = base / 2 // 256x total penalty
	}
	if entry.RemainingStorage < 5*requiredStorage {
		base = base / 2 // 512x total penalty
	}
	if entry.RemainingStorage < 3*requiredStorage {
		base = base / 2 // 1024x total penalty
	}
	if entry.RemainingStorage < 2*requiredStorage {
		base = base / 2 // 2048x total penalty
	}
	if entry.RemainingStorage < requiredStorage {
		base = base / 2 // 4096x total penalty
	}
	return base
}

// versionAdjustments will adjust the weight of the entry according to the siad
// version reported by the host.
func versionAdjustments(entry modules.HostDBEntry) float64 {
	base := float64(1)
	if build.VersionCmp(entry.Version, "1.1.2") <= 0 {
		base = base * 0.99999 // Safety value to make sure we update the version penalties every time we update the host.
	}
	if build.VersionCmp(entry.Version, "1.1.1") < 0 {
		base = base / 5 // 5x total penalty.
	}
	if build.VersionCmp(entry.Version, "1.0.3") < 0 {
		base = base / 5 // 25x total penalty.
	}
	if build.VersionCmp(entry.Version, "1.0.0") < 0 {
		base = base / 20 // 500x total penalty.
	}
	return base
}

// lifetimeAdjustments will adjust the weight of the host according to the total
// amount of time that has passed since the host's original announcement.
func (hdb *HostDB) lifetimeAdjustments(entry modules.HostDBEntry) float64 {
	base := float64(1)
	if hdb.blockHeight >= entry.FirstSeen {
		age := hdb.blockHeight - entry.FirstSeen
		if age < 6000 {
			base = base / 2 // 2x total
		}
		if age < 4000 {
			base = base / 2 // 4x total
		}
		if age < 2000 {
			base = base / 2 // 8x total
		}
		if age < 1000 {
			base = base / 8 // 64x total
		}
		if age < 576 {
			base = base / 2 // 128x total
		}
		if age < 288 {
			base = base / 2 // 256x total
		}
	}
	return base
}

// uptimeAdjustments penalizes the host for having poor uptime, and for being
// offline.
//
// CAUTION: The function 'updateEntry' will manually fill out two scans for a
// new host to give the host some initial uptime or downtime. Modification of
// this function needs to be made paying attention to the structure of that
// function.
func (hdb *HostDB) uptimeAdjustments(entry modules.HostDBEntry) float64 {
	// Special case: if we have scanned the host twice or fewer, don't perform
	// uptime math.
	if len(entry.ScanHistory) == 0 {
		return 0.25
	}
	if len(entry.ScanHistory) == 1 {
		if entry.ScanHistory[0].Success {
			return 0.75
		}
		return 0.25
	}
	if len(entry.ScanHistory) == 2 {
		if entry.ScanHistory[0].Success && entry.ScanHistory[1].Success {
			return 0.85
		}
		if entry.ScanHistory[0].Success || entry.ScanHistory[1].Success {
			return 0.50
		}
		return 0.05
	}

	// Compute the total measured uptime and total measured downtime for this
	// host.
	downtime := entry.HistoricDowntime
	uptime := entry.HistoricUptime
	recentTime := entry.ScanHistory[0].Timestamp
	recentSuccess := entry.ScanHistory[0].Success
	for _, scan := range entry.ScanHistory[1:] {
		if recentTime.After(scan.Timestamp) {
			hdb.log.Critical("Host entry scan history not sorted.")
			// Ignore the unsorted scan entry.
			continue
		}
		if recentSuccess {
			uptime += scan.Timestamp.Sub(recentTime)
		} else {
			downtime += scan.Timestamp.Sub(recentTime)
		}
		recentTime = scan.Timestamp
		recentSuccess = scan.Success
	}
	// Sanity check against 0 total time.
	if uptime == 0 && downtime == 0 {
		return 0.001 // Shouldn't happen.
	}

	// Compute the uptime ratio, but shift by 0.02 to acknowledge fully that
	// 98% uptime and 100% uptime is valued the same.
	uptimeRatio := float64(uptime) / float64(uptime+downtime)
	if uptimeRatio > 0.98 {
		uptimeRatio = 0.98
	}
	uptimeRatio += 0.02

	// Cap the total amount of downtime allowed based on the total number of
	// scans that have happened.
	allowedDowntime := 0.03 * float64(len(entry.ScanHistory))
	if uptimeRatio < 1-allowedDowntime {
		uptimeRatio = 1 - allowedDowntime
	}

	// Calculate the penalty for low uptime. Penalties increase extremely
	// quickly as uptime falls away from 95%.
	//
	// 100% uptime = 1
	// 98%  uptime = 1
	// 95%  uptime = 0.91
	// 90%  uptime = 0.51
	// 85%  uptime = 0.16
	// 80%  uptime = 0.03
	// 75%  uptime = 0.005
	// 70%  uptime = 0.001
	// 50%  uptime = 0.000002
	exp := 100 * math.Min(1-uptimeRatio, 0.20)
	return math.Pow(uptimeRatio, exp)
}

// calculateHostWeight returns the weight of a host according to the settings of
// the host database entry. Currently, only the price is considered.
func (hdb *HostDB) calculateHostWeight(entry modules.HostDBEntry) types.Currency {
	collateralReward := hdb.collateralAdjustments(entry)
	pricePenalty := hdb.priceAdjustments(entry)
	storageRemainingPenalty := storageRemainingAdjustments(entry)
	versionPenalty := versionAdjustments(entry)
	lifetimePenalty := hdb.lifetimeAdjustments(entry)
	uptimePenalty := hdb.uptimeAdjustments(entry)

	// Combine the adjustments.
	fullPenalty := collateralReward * pricePenalty * storageRemainingPenalty * versionPenalty * lifetimePenalty * uptimePenalty

	// Return a types.Currency.
	weight := baseWeight.MulFloat(fullPenalty)
	if weight.IsZero() {
		// A weight of zero is problematic for for the host tree.
		return types.NewCurrency64(1)
	}
	return weight
}

// ScoreBreakdown provdes a detailed set of scalars and bools indicating
// elements of the host's overall score.
func (hdb *HostDB) ScoreBreakdown(entry modules.HostDBEntry) modules.HostScoreBreakdown {
	return modules.HostScoreBreakdown{
		Score: hdb.calculateHostWeight(entry),

		AgeAdjustment:              hdb.lifetimeAdjustments(entry),
		BurnAdjustment:             1,
		CollateralAdjustment:       hdb.collateralAdjustments(entry),
		PriceAdjustment:            hdb.priceAdjustments(entry),
		StorageRemainingAdjustment: storageRemainingAdjustments(entry),
		UptimeAdjustment:           hdb.uptimeAdjustments(entry),
		VersionAdjustment:          versionAdjustments(entry),
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Tekton 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 tektonaddon

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"time"

	mf "github.com/manifestival/manifestival"
	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
	clientset "github.com/tektoncd/operator/pkg/client/clientset/versioned"
	informer "github.com/tektoncd/operator/pkg/client/informers/externalversions/operator/v1alpha1"
	tektonaddonreconciler "github.com/tektoncd/operator/pkg/client/injection/reconciler/operator/v1alpha1/tektonaddon"
	"github.com/tektoncd/operator/pkg/reconciler/common"
	"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"knative.dev/pkg/logging"
	pkgreconciler "knative.dev/pkg/reconciler"
)

// Reconciler implements controller.Reconciler for TektonAddon resources.
type Reconciler struct {
	manifest          mf.Manifest
	operatorClientSet clientset.Interface
	extension         common.Extension

	// enqueueAfter enqueues a obj after a duration
	enqueueAfter func(obj interface{}, after time.Duration)

	pipelineInformer informer.TektonPipelineInformer
	triggerInformer  informer.TektonTriggerInformer

	operatorVersion string
}

const (
	retain int = iota
	overwrite

	labelProviderType     = "operator.tekton.dev/provider-type"
	providerTypeCommunity = "community"
	providerTypeRedHat    = "redhat"
)

// Check that our Reconciler implements controller.Reconciler
var _ tektonaddonreconciler.Interface = (*Reconciler)(nil)
var _ tektonaddonreconciler.Finalizer = (*Reconciler)(nil)

// FinalizeKind removes all resources after deletion of a TektonTriggers.
func (r *Reconciler) FinalizeKind(ctx context.Context, original *v1alpha1.TektonAddon) pkgreconciler.Event {
	logger := logging.FromContext(ctx)

	installerSets := original.Status.AddonsInstallerSet
	if len(installerSets) == 0 {
		return nil
	}

	for _, value := range installerSets {
		err := r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets().Delete(ctx, value, metav1.DeleteOptions{})
		if err != nil && !errors.IsNotFound(err) {
			return err
		}
	}

	if err := r.extension.Finalize(ctx, original); err != nil {
		logger.Error("Failed to finalize platform resources", err)
	}

	return nil
}

// ReconcileKind compares the actual state with the desired, and attempts to
// converge the two.
func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon) pkgreconciler.Event {
	logger := logging.FromContext(ctx)
	ta.Status.InitializeConditions()

	if ta.GetName() != v1alpha1.AddonResourceName {
		msg := fmt.Sprintf("Resource ignored, Expected Name: %s, Got Name: %s",
			v1alpha1.AddonResourceName,
			ta.GetName(),
		)
		logger.Error(msg)
		ta.Status.MarkNotReady(msg)
		return nil
	}

	// Pass the object through defaulting
	ta.SetDefaults(ctx)

	// Mark TektonAddon Instance as Not Ready if an upgrade is needed
	if err := r.markUpgrade(ctx, ta); err != nil {
		return err
	}

	// Make sure TektonPipeline & TektonTrigger is installed before proceeding with
	// TektonAddons

	if _, err := common.PipelineReady(r.pipelineInformer); err != nil {
		if err.Error() == common.PipelineNotReady {
			ta.Status.MarkDependencyInstalling("tekton-pipelines is still installing")
			// wait for pipeline status to change
			r.enqueueAfter(ta, 10*time.Second)
			return nil
		}
		// (tektonpipeline.operator.tekton.dev instance not available yet)
		ta.Status.MarkDependencyMissing("tekton-pipelines does not exist")
		return err
	}

	if _, err := common.TriggerReady(r.triggerInformer); err != nil {
		if err.Error() == common.TriggerNotReady {
			ta.Status.MarkDependencyInstalling("tekton-triggers is still installing")
			// wait for trigger status to change
			r.enqueueAfter(ta, 10*time.Second)
			return nil
		}
		// (tektontrigger.operator.tekton.dev instance not available yet)
		ta.Status.MarkDependencyMissing("tekton-triggers does not exist")
		return err
	}

	ta.Status.MarkDependenciesInstalled()

	if err := tektoninstallerset.CleanUpObsoleteResources(ctx, r.operatorClientSet, CreatedByValue); err != nil {
		return err
	}

	// validate the params
	ptVal, _ := findValue(ta.Spec.Params, v1alpha1.PipelineTemplatesParam)
	ctVal, _ := findValue(ta.Spec.Params, v1alpha1.ClusterTasksParam)

	if ptVal == "true" && ctVal == "false" {
		ta.Status.MarkNotReady("pipelineTemplates cannot be true if clusterTask is false")
		return nil
	}

	if err := r.extension.PreReconcile(ctx, ta); err != nil {
		ta.Status.MarkPreReconcilerFailed(err.Error())
		return err
	}

	ta.Status.MarkPreReconcilerComplete()

	if err := r.EnsureClusterTask(ctx, ctVal, ta); err != nil {
		return err
	}

	if err := r.EnsureVersionedClusterTask(ctx, ctVal, ta); err != nil {
		return err
	}

	if err := r.EnsurePipelineTemplates(ctx, ptVal, ta); err != nil {
		return err
	}

	if err := r.EnsureTriggersResources(ctx, ta); err != nil {
		return err
	}

	if err := r.EnsurePipelinesAsCode(ctx, ta); err != nil {
		return err
	}

	ta.Status.MarkInstallerSetReady()

	if err := r.extension.PostReconcile(ctx, ta); err != nil {
		if err == v1alpha1.RECONCILE_AGAIN_ERR {
			r.enqueueAfter(ta, 10*time.Second)
			return nil
		}
		ta.Status.MarkPostReconcilerFailed(err.Error())
		return err
	}

	ta.Status.MarkPostReconcilerComplete()

	ta.Status.SetVersion(r.operatorVersion)

	return nil
}

func applyAddons(manifest *mf.Manifest, subpath string) error {
	koDataDir := os.Getenv(common.KoEnvKey)
	addonLocation := filepath.Join(koDataDir, "tekton-addon", "addons", subpath)
	return common.AppendManifest(manifest, addonLocation)
}

// addonTransform mutates the passed manifest to one with common, component
// and platform transformations applied
func (r *Reconciler) addonTransform(ctx context.Context, manifest *mf.Manifest, comp v1alpha1.TektonComponent) error {
	instance := comp.(*v1alpha1.TektonAddon)
	extra := []mf.Transformer{
		injectLabel(labelProviderType, providerTypeRedHat, overwrite, "ClusterTask"),
	}
	extra = append(extra, r.extension.Transformers(instance)...)
	return common.Transform(ctx, manifest, instance, extra...)
}

func findValue(params []v1alpha1.Param, name string) (string, bool) {
	for _, p := range params {
		if p.Name == name {
			return p.Value, true
		}
	}
	return "", false
}

func (r *Reconciler) markUpgrade(ctx context.Context, ta *v1alpha1.TektonAddon) error {
	labels := ta.GetLabels()
	ver, ok := labels[v1alpha1.ReleaseVersionKey]
	if ok && ver == r.operatorVersion {
		return nil
	}
	if ok && ver != r.operatorVersion {
		ta.Status.MarkInstallerSetNotReady(v1alpha1.UpgradePending)
		ta.Status.MarkPreReconcilerFailed(v1alpha1.UpgradePending)
		ta.Status.MarkPostReconcilerFailed(v1alpha1.UpgradePending)
		ta.Status.MarkNotReady(v1alpha1.UpgradePending)
	}
	if labels == nil {
		labels = map[string]string{}
	}
	labels[v1alpha1.ReleaseVersionKey] = r.operatorVersion
	ta.SetLabels(labels)

	if _, err := r.operatorClientSet.OperatorV1alpha1().TektonAddons().Update(ctx,
		ta, metav1.UpdateOptions{}); err != nil {
		return err
	}
	return v1alpha1.RECONCILE_AGAIN_ERR
}
<commit_msg>Updates Addon finalizer to delete all installerSet by label<commit_after>/*
Copyright 2020 The Tekton 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 tektonaddon

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"time"

	mf "github.com/manifestival/manifestival"
	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
	clientset "github.com/tektoncd/operator/pkg/client/clientset/versioned"
	informer "github.com/tektoncd/operator/pkg/client/informers/externalversions/operator/v1alpha1"
	tektonaddonreconciler "github.com/tektoncd/operator/pkg/client/injection/reconciler/operator/v1alpha1/tektonaddon"
	"github.com/tektoncd/operator/pkg/reconciler/common"
	"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"knative.dev/pkg/logging"
	pkgreconciler "knative.dev/pkg/reconciler"
)

// Reconciler implements controller.Reconciler for TektonAddon resources.
type Reconciler struct {
	manifest          mf.Manifest
	operatorClientSet clientset.Interface
	extension         common.Extension

	// enqueueAfter enqueues a obj after a duration
	enqueueAfter func(obj interface{}, after time.Duration)

	pipelineInformer informer.TektonPipelineInformer
	triggerInformer  informer.TektonTriggerInformer

	operatorVersion string
}

const (
	retain int = iota
	overwrite

	labelProviderType     = "operator.tekton.dev/provider-type"
	providerTypeCommunity = "community"
	providerTypeRedHat    = "redhat"
)

// Check that our Reconciler implements controller.Reconciler
var _ tektonaddonreconciler.Interface = (*Reconciler)(nil)
var _ tektonaddonreconciler.Finalizer = (*Reconciler)(nil)

var ls = metav1.LabelSelector{
	MatchLabels: map[string]string{
		v1alpha1.CreatedByKey: CreatedByValue,
	},
}

// FinalizeKind removes all resources after deletion of a TektonTriggers.
func (r *Reconciler) FinalizeKind(ctx context.Context, original *v1alpha1.TektonAddon) pkgreconciler.Event {
	logger := logging.FromContext(ctx)

	labelSelector, err := common.LabelSelector(ls)
	if err != nil {
		return err
	}
	if err := r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets().
		DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{
			LabelSelector: labelSelector,
		}); err != nil {
		logger.Error("Failed to delete installer set created by TektonAddon", err)
		return err
	}

	if err := r.extension.Finalize(ctx, original); err != nil {
		logger.Error("Failed to finalize platform resources", err)
	}

	return nil
}

// ReconcileKind compares the actual state with the desired, and attempts to
// converge the two.
func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon) pkgreconciler.Event {
	logger := logging.FromContext(ctx)
	ta.Status.InitializeConditions()

	if ta.GetName() != v1alpha1.AddonResourceName {
		msg := fmt.Sprintf("Resource ignored, Expected Name: %s, Got Name: %s",
			v1alpha1.AddonResourceName,
			ta.GetName(),
		)
		logger.Error(msg)
		ta.Status.MarkNotReady(msg)
		return nil
	}

	// Pass the object through defaulting
	ta.SetDefaults(ctx)

	// Mark TektonAddon Instance as Not Ready if an upgrade is needed
	if err := r.markUpgrade(ctx, ta); err != nil {
		return err
	}

	// Make sure TektonPipeline & TektonTrigger is installed before proceeding with
	// TektonAddons

	if _, err := common.PipelineReady(r.pipelineInformer); err != nil {
		if err.Error() == common.PipelineNotReady {
			ta.Status.MarkDependencyInstalling("tekton-pipelines is still installing")
			// wait for pipeline status to change
			r.enqueueAfter(ta, 10*time.Second)
			return nil
		}
		// (tektonpipeline.operator.tekton.dev instance not available yet)
		ta.Status.MarkDependencyMissing("tekton-pipelines does not exist")
		return err
	}

	if _, err := common.TriggerReady(r.triggerInformer); err != nil {
		if err.Error() == common.TriggerNotReady {
			ta.Status.MarkDependencyInstalling("tekton-triggers is still installing")
			// wait for trigger status to change
			r.enqueueAfter(ta, 10*time.Second)
			return nil
		}
		// (tektontrigger.operator.tekton.dev instance not available yet)
		ta.Status.MarkDependencyMissing("tekton-triggers does not exist")
		return err
	}

	ta.Status.MarkDependenciesInstalled()

	if err := tektoninstallerset.CleanUpObsoleteResources(ctx, r.operatorClientSet, CreatedByValue); err != nil {
		return err
	}

	// validate the params
	ptVal, _ := findValue(ta.Spec.Params, v1alpha1.PipelineTemplatesParam)
	ctVal, _ := findValue(ta.Spec.Params, v1alpha1.ClusterTasksParam)

	if ptVal == "true" && ctVal == "false" {
		ta.Status.MarkNotReady("pipelineTemplates cannot be true if clusterTask is false")
		return nil
	}

	if err := r.extension.PreReconcile(ctx, ta); err != nil {
		ta.Status.MarkPreReconcilerFailed(err.Error())
		return err
	}

	ta.Status.MarkPreReconcilerComplete()

	if err := r.EnsureClusterTask(ctx, ctVal, ta); err != nil {
		return err
	}

	if err := r.EnsureVersionedClusterTask(ctx, ctVal, ta); err != nil {
		return err
	}

	if err := r.EnsurePipelineTemplates(ctx, ptVal, ta); err != nil {
		return err
	}

	if err := r.EnsureTriggersResources(ctx, ta); err != nil {
		return err
	}

	if err := r.EnsurePipelinesAsCode(ctx, ta); err != nil {
		return err
	}

	ta.Status.MarkInstallerSetReady()

	if err := r.extension.PostReconcile(ctx, ta); err != nil {
		if err == v1alpha1.RECONCILE_AGAIN_ERR {
			r.enqueueAfter(ta, 10*time.Second)
			return nil
		}
		ta.Status.MarkPostReconcilerFailed(err.Error())
		return err
	}

	ta.Status.MarkPostReconcilerComplete()

	ta.Status.SetVersion(r.operatorVersion)

	return nil
}

func applyAddons(manifest *mf.Manifest, subpath string) error {
	koDataDir := os.Getenv(common.KoEnvKey)
	addonLocation := filepath.Join(koDataDir, "tekton-addon", "addons", subpath)
	return common.AppendManifest(manifest, addonLocation)
}

// addonTransform mutates the passed manifest to one with common, component
// and platform transformations applied
func (r *Reconciler) addonTransform(ctx context.Context, manifest *mf.Manifest, comp v1alpha1.TektonComponent) error {
	instance := comp.(*v1alpha1.TektonAddon)
	extra := []mf.Transformer{
		injectLabel(labelProviderType, providerTypeRedHat, overwrite, "ClusterTask"),
	}
	extra = append(extra, r.extension.Transformers(instance)...)
	return common.Transform(ctx, manifest, instance, extra...)
}

func findValue(params []v1alpha1.Param, name string) (string, bool) {
	for _, p := range params {
		if p.Name == name {
			return p.Value, true
		}
	}
	return "", false
}

func (r *Reconciler) markUpgrade(ctx context.Context, ta *v1alpha1.TektonAddon) error {
	labels := ta.GetLabels()
	ver, ok := labels[v1alpha1.ReleaseVersionKey]
	if ok && ver == r.operatorVersion {
		return nil
	}
	if ok && ver != r.operatorVersion {
		ta.Status.MarkInstallerSetNotReady(v1alpha1.UpgradePending)
		ta.Status.MarkPreReconcilerFailed(v1alpha1.UpgradePending)
		ta.Status.MarkPostReconcilerFailed(v1alpha1.UpgradePending)
		ta.Status.MarkNotReady(v1alpha1.UpgradePending)
	}
	if labels == nil {
		labels = map[string]string{}
	}
	labels[v1alpha1.ReleaseVersionKey] = r.operatorVersion
	ta.SetLabels(labels)

	if _, err := r.operatorClientSet.OperatorV1alpha1().TektonAddons().Update(ctx,
		ta, metav1.UpdateOptions{}); err != nil {
		return err
	}
	return v1alpha1.RECONCILE_AGAIN_ERR
}
<|endoftext|>


<commit_before>package linux

import (
	"errors"
	"io/ioutil"
	"strconv"
	"strings"
)

type NetUnixDomainSockets struct {
	Sockets []NetUnixDomainSocket `json:"sockets"`
}

type NetUnixDomainSocket struct {
	Protocol uint64 `json:"protocol"`
	RefCount uint64 `json:"ref_count"`
	Flags    uint64 `json:"flags"`
	Type     uint64 `json:"type"`
	State    uint64 `json:"state"`
	Inode    uint64 `json:"inode"`
	Path     string `json:"path"`
}

// ReadNetUnixDomainSockets parser to /proc/net/unix
func ReadNetUnixDomainSockets(fpath string) (*NetUnixDomainSockets, error) {
	b, err := ioutil.ReadFile(fpath)

	if err != nil {
		return nil, err
	}

	lines := strings.Split(string(b), "\n")
	unixDomainSockets := &NetUnixDomainSockets{}

	for i := 1; i < len(lines); i++ {
		line := lines[i]
		f := strings.Fields(line)

		if len(f) < 8 {
			continue
		}

		socket := NetUnixDomainSocket{}
		if socket.RefCount, err = strconv.ParseUint(f[1], 10, 64); err != nil {
			return nil, errors.New("Cannot parse unix domain socket [invalid RefCount]: " + f[1])
		}

		if socket.Protocol, err = strconv.ParseUint(f[2], 10, 64); err != nil {
			return nil, errors.New("Cannot parse unix domain socket [invalid Protocol]: " + f[2])
		}

		if socket.Flags, err = strconv.ParseUint(f[3], 10, 64); err != nil {
			return nil, errors.New("Cannot parse unix domain socket [invalid Flags]: " + f[3])
		}

		if socket.Type, err = strconv.ParseUint(f[4], 10, 64); err != nil {
			return nil, errors.New("Cannot parse unix domain socket [invalid Type]: " + f[4])
		}

		if socket.State, err = strconv.ParseUint(f[5], 10, 64); err != nil {
			return nil, errors.New("Cannot parse unix domain socket [invalid State]: " + f[5])
		}

		if socket.Inode, err = strconv.ParseUint(f[6], 10, 64); err != nil {
			return nil, errors.New("Cannot parse unix domain socket [invalid Inode]: " + f[6])
		}

		socket.Path = f[7]
		unixDomainSockets.Sockets = append(unixDomainSockets.Sockets, socket)
	}
	return unixDomainSockets, nil
}
<commit_msg>Network socket's ref count can be hex<commit_after>package linux

import (
	"errors"
	"io/ioutil"
	"strconv"
	"strings"
)

type NetUnixDomainSockets struct {
	Sockets []NetUnixDomainSocket `json:"sockets"`
}

type NetUnixDomainSocket struct {
	Protocol uint64 `json:"protocol"`
	RefCount uint64 `json:"ref_count"`
	Flags    uint64 `json:"flags"`
	Type     uint64 `json:"type"`
	State    uint64 `json:"state"`
	Inode    uint64 `json:"inode"`
	Path     string `json:"path"`
}

// ReadNetUnixDomainSockets parser to /proc/net/unix
func ReadNetUnixDomainSockets(fpath string) (*NetUnixDomainSockets, error) {
	b, err := ioutil.ReadFile(fpath)

	if err != nil {
		return nil, err
	}

	lines := strings.Split(string(b), "\n")
	unixDomainSockets := &NetUnixDomainSockets{}

	for i := 1; i < len(lines); i++ {
		line := lines[i]
		f := strings.Fields(line)

		if len(f) < 8 {
			continue
		}

		socket := NetUnixDomainSocket{}
		if socket.RefCount, err = strconv.ParseUint(f[1], 16, 64); err != nil {
			return nil, errors.New("Cannot parse unix domain socket [invalid RefCount]: " + f[1])
		}

		if socket.Protocol, err = strconv.ParseUint(f[2], 10, 64); err != nil {
			return nil, errors.New("Cannot parse unix domain socket [invalid Protocol]: " + f[2])
		}

		if socket.Flags, err = strconv.ParseUint(f[3], 10, 64); err != nil {
			return nil, errors.New("Cannot parse unix domain socket [invalid Flags]: " + f[3])
		}

		if socket.Type, err = strconv.ParseUint(f[4], 10, 64); err != nil {
			return nil, errors.New("Cannot parse unix domain socket [invalid Type]: " + f[4])
		}

		if socket.State, err = strconv.ParseUint(f[5], 10, 64); err != nil {
			return nil, errors.New("Cannot parse unix domain socket [invalid State]: " + f[5])
		}

		if socket.Inode, err = strconv.ParseUint(f[6], 10, 64); err != nil {
			return nil, errors.New("Cannot parse unix domain socket [invalid Inode]: " + f[6])
		}

		socket.Path = f[7]
		unixDomainSockets.Sockets = append(unixDomainSockets.Sockets, socket)
	}
	return unixDomainSockets, nil
}
<|endoftext|>