<commit_before>package crawler

import (
	"fmt"
	"github.com/ak1t0/flame/format"
	"golang.org/x/net/proxy"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"time"
)

func Crawl(logs format.OnionLogs) format.OnionLogs {
	var scanned format.OnionLogs

	// data channel
	c := make(chan format.OnionLog, 3000)
	// semaphore
	sem := 10
	semc := make(chan bool, sem)

	// crawl concurrently
	for _, v := range logs {
		semc <- true
		go func(v format.OnionLog) {
			defer func() { <-semc }()
			v.Result = scan(v.Address)
			c <- v
		}(v)
	}

	// crawled data
	for i := 0; i < len(logs); i++ {
		data := <-c
		scanned = append(scanned, data)
	}

	return scanned
}

func scan(target string) string {
	hostPort := "127.0.0.1:9050"
	p, err := proxy.SOCKS5("tcp", hostPort, nil, proxy.Direct)
	if err != nil {
		fmt.Println(err)
	}

	client := http.DefaultClient
	client.Transport = &http.Transport{
		Dial: p.Dial,
	}

	// connection and timeout
	c := make(chan string, 1)
	limit := 30

	go func() {
		resp, err := client.Get("http://" + target)

		if err != nil {
			log.Println(err)

			e := err.Error()
			if strings.Contains(e, "connection refused") {
				c <- "connection refused"
			} else if strings.Contains(e, "connection forbidden") {
				c <- "connection forbidden"
			} else if strings.Contains(e, "host unreachable") {
				c <- "general failure"
			} else if strings.Contains(e, "TTL expired") {
				c <- "TTL expired"
			} else {
				c <- e //"Unknown Error"
			}

			return
		}

		contents, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			c <- "available"
		}
		c <- string(contents)
		return
	}()

	select {
	case res := <-c:
		return res
	// timeout
	case <-time.After(time.Second * time.Duration(limit)):
		return "timeout"
	}
}
<commit_msg>fix parameter<commit_after>package crawler

import (
	"fmt"
	"github.com/ak1t0/flame/format"
	"golang.org/x/net/proxy"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"time"
)

func Crawl(logs format.OnionLogs) format.OnionLogs {
	var scanned format.OnionLogs

	// data channel
	c := make(chan format.OnionLog, 6000)
	// semaphore
	sem := 10
	semc := make(chan bool, sem)

	// crawl concurrently
	for _, v := range logs {
		semc <- true
		go func(v format.OnionLog) {
			defer func() { <-semc }()
			v.Result = scan(v.Address)
			c <- v
		}(v)
	}

	// crawled data
	for i := 0; i < len(logs); i++ {
		data := <-c
		scanned = append(scanned, data)
	}

	return scanned
}

func scan(target string) string {
	hostPort := "127.0.0.1:9050"
	p, err := proxy.SOCKS5("tcp", hostPort, nil, proxy.Direct)
	if err != nil {
		fmt.Println(err)
	}

	client := http.DefaultClient
	client.Transport = &http.Transport{
		Dial: p.Dial,
	}

	// connection and timeout
	c := make(chan string, 1)
	limit := 30

	go func() {
		resp, err := client.Get("http://" + target)

		if err != nil {
			log.Println(err)

			e := err.Error()
			if strings.Contains(e, "connection refused") {
				c <- "connection refused"
			} else if strings.Contains(e, "connection forbidden") {
				c <- "connection forbidden"
			} else if strings.Contains(e, "host unreachable") {
				c <- "general failure"
			} else if strings.Contains(e, "TTL expired") {
				c <- "TTL expired"
			} else {
				c <- e //"Unknown Error"
			}

			return
		}

		contents, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			c <- "available"
		}
		c <- string(contents)
		return
	}()

	select {
	case res := <-c:
		return res
	// timeout
	case <-time.After(time.Second * time.Duration(limit)):
		return "timeout"
	}
}
<|endoftext|>


<commit_before>// +build e2e

/*
Copyright 2019 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 test

import (
	"fmt"
	"strings"
	"testing"
	"time"

	"github.com/google/go-cmp/cmp"
	"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
	tb "github.com/tektoncd/pipeline/test/builder"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	knativetest "knative.dev/pkg/test"
)

const (
	kanikoTaskName          = "kanikotask"
	kanikoTaskRunName       = "kanikotask-run"
	kanikoGitResourceName   = "go-example-git"
	kanikoImageResourceName = "go-example-image"
	// This is a random revision chosen on 10/11/2019
	revision = "1c9d566ecd13535f93789595740f20932f655905"
)

// TestTaskRun is an integration test that will verify a TaskRun using kaniko
func TestKanikoTaskRun(t *testing.T) {
	c, namespace := setup(t, withRegistry)
	t.Parallel()

	repo := fmt.Sprintf("registry.%s:5000/kanikotasktest", namespace)

	knativetest.CleanupOnInterrupt(func() { tearDown(t, c, namespace) }, t.Logf)
	defer tearDown(t, c, namespace)

	t.Logf("Creating Git PipelineResource %s", kanikoGitResourceName)
	if _, err := c.PipelineResourceClient.Create(getGitResource(namespace)); err != nil {
		t.Fatalf("Failed to create Pipeline Resource `%s`: %s", kanikoGitResourceName, err)
	}

	t.Logf("Creating Image PipelineResource %s", repo)
	if _, err := c.PipelineResourceClient.Create(getImageResource(namespace, repo)); err != nil {
		t.Fatalf("Failed to create Pipeline Resource `%s`: %s", kanikoGitResourceName, err)
	}

	t.Logf("Creating Task %s", kanikoTaskName)
	if _, err := c.TaskClient.Create(getTask(repo, namespace)); err != nil {
		t.Fatalf("Failed to create Task `%s`: %s", kanikoTaskName, err)
	}

	t.Logf("Creating TaskRun %s", kanikoTaskRunName)
	if _, err := c.TaskRunClient.Create(getTaskRun(namespace)); err != nil {
		t.Fatalf("Failed to create TaskRun `%s`: %s", kanikoTaskRunName, err)
	}

	// Verify status of TaskRun (wait for it)

	if err := WaitForTaskRunState(c, kanikoTaskRunName, func(tr *v1alpha1.TaskRun) (bool, error) {
		return TaskRunSucceed(kanikoTaskRunName)(tr)
	}, "TaskRunCompleted"); err != nil {
		t.Errorf("Error waiting for TaskRun %s to finish: %s", kanikoTaskRunName, err)
	}

	tr, err := c.TaskRunClient.Get(kanikoTaskRunName, metav1.GetOptions{})
	if err != nil {
		t.Errorf("Error retrieving taskrun: %s", err)
	}
	digest := ""
	commit := ""
	for _, rr := range tr.Status.ResourcesResult {
		switch rr.Key {
		case "digest":
			digest = rr.Value
		case "commit":
			commit = rr.Value
		}
	}
	if digest == "" {
		t.Errorf("Digest not found in TaskRun.Status: %v", tr.Status)
	}
	if commit == "" {
		t.Errorf("Commit not found in TaskRun.Status: %v", tr.Status)
	}

	if revision != commit {
		t.Fatalf("Expected remote commit to match local revision: %s, %s", commit, revision)
	}

	// match the local digest, which is first capture group against the remote image
	remoteDigest, err := getRemoteDigest(t, c, namespace, repo)
	if err != nil {
		t.Fatalf("Expected to get digest for remote image %s: %v", repo, err)
	}
	if d := cmp.Diff(digest, remoteDigest); d != "" {
		t.Fatalf("Expected local digest %s to match remote digest %s: %s", digest, remoteDigest, d)
	}
}

func getGitResource(namespace string) *v1alpha1.PipelineResource {
	return tb.PipelineResource(kanikoGitResourceName, namespace, tb.PipelineResourceSpec(
		v1alpha1.PipelineResourceTypeGit,
		tb.PipelineResourceSpecParam("Url", "https://github.com/GoogleContainerTools/kaniko"),
		tb.PipelineResourceSpecParam("Revision", revision),
	))
}

func getImageResource(namespace, repo string) *v1alpha1.PipelineResource {
	return tb.PipelineResource(kanikoImageResourceName, namespace, tb.PipelineResourceSpec(
		v1alpha1.PipelineResourceTypeImage,
		tb.PipelineResourceSpecParam("url", repo),
	))
}

func getTask(repo, namespace string) *v1alpha1.Task {
	root := int64(0)
	taskSpecOps := []tb.TaskSpecOp{
		tb.TaskInputs(tb.InputsResource("gitsource", v1alpha1.PipelineResourceTypeGit)),
		tb.TaskOutputs(tb.OutputsResource("builtImage", v1alpha1.PipelineResourceTypeImage)),
	}
	stepOps := []tb.StepOp{
		tb.StepArgs(
			"--dockerfile=/workspace/gitsource/integration/dockerfiles/Dockerfile_test_label",
			fmt.Sprintf("--destination=%s", repo),
			"--context=/workspace/gitsource",
			"--oci-layout-path=/workspace/output/builtImage",
			"--insecure",
			"--insecure-pull",
			"--insecure-registry=registry."+namespace+":5000/",
		),
		tb.StepSecurityContext(&corev1.SecurityContext{RunAsUser: &root}),
	}
	step := tb.Step("kaniko", "gcr.io/kaniko-project/executor:v0.13.0", stepOps...)
	taskSpecOps = append(taskSpecOps, step)
	sidecar := tb.Sidecar("registry", "registry")
	taskSpecOps = append(taskSpecOps, sidecar)

	return tb.Task(kanikoTaskName, namespace, tb.TaskSpec(taskSpecOps...))
}

func getTaskRun(namespace string) *v1alpha1.TaskRun {
	return tb.TaskRun(kanikoTaskRunName, namespace, tb.TaskRunSpec(
		tb.TaskRunTaskRef(kanikoTaskName),
		tb.TaskRunTimeout(2*time.Minute),
		tb.TaskRunInputs(tb.TaskRunInputsResource("gitsource", tb.TaskResourceBindingRef(kanikoGitResourceName))),
		tb.TaskRunOutputs(tb.TaskRunOutputsResource("builtImage", tb.TaskResourceBindingRef(kanikoImageResourceName))),
	))
}

// getRemoteDigest starts a pod to query the registry from the namespace itself, using skopeo (and jq).
// The reason we have to do that is because the image is pushed on a local registry that is not exposed
// to the "outside" of the test, this means it can be query by the test itself. It can only be query from
// a pod in the namespace. skopeo is able to do that query and we use jq to extract the digest from its
// output. The image used for this pod is build in the tektoncd/plumbing repository.
func getRemoteDigest(t *testing.T, c *clients, namespace, image string) (string, error) {
	t.Helper()
	podName := "skopeo-jq"
	if _, err := c.KubeClient.Kube.CoreV1().Pods(namespace).Create(&corev1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: namespace,
			Name:      podName,
		},
		Spec: corev1.PodSpec{
			Containers: []corev1.Container{{
				Name:    "skopeo",
				Image:   "gcr.io/tekton-releases/dogfooding/skopeo:latest",
				Command: []string{"/bin/sh", "-c"},
				Args:    []string{"skopeo inspect --tls-verify=false docker://" + image + ":latest| jq '.Digest'"},
			}},
			RestartPolicy: corev1.RestartPolicyNever,
		},
	}); err != nil {
		t.Fatalf("Failed to create the skopeo-jq pod: %v", err)
	}
	if err := WaitForPodState(c, podName, namespace, func(pod *corev1.Pod) (bool, error) {
		return pod.Status.Phase == "Succeeded" || pod.Status.Phase == "Failed", nil
	}, "PodContainersTerminated"); err != nil {
		t.Fatalf("Error waiting for Pod %q to terminate: %v", podName, err)
	}
	logs, err := getContainerLogsFromPod(c.KubeClient.Kube, podName, "skopeo", namespace)
	if err != nil {
		t.Fatalf("Could not get logs for pod %s: %s", podName, err)
	}
	return strings.TrimSpace(strings.ReplaceAll(logs, "\"", "")), nil
}
<commit_msg>Make kanikotest skip on environment using scc<commit_after>// +build e2e

/*
Copyright 2019 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 test

import (
	"fmt"
	"strings"
	"testing"
	"time"

	"github.com/google/go-cmp/cmp"
	"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
	tb "github.com/tektoncd/pipeline/test/builder"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	knativetest "knative.dev/pkg/test"
)

const (
	kanikoTaskName          = "kanikotask"
	kanikoTaskRunName       = "kanikotask-run"
	kanikoGitResourceName   = "go-example-git"
	kanikoImageResourceName = "go-example-image"
	// This is a random revision chosen on 10/11/2019
	revision = "1c9d566ecd13535f93789595740f20932f655905"
)

var (
	skipRootUserTests = "false"
)

// TestTaskRun is an integration test that will verify a TaskRun using kaniko
func TestKanikoTaskRun(t *testing.T) {
	if skipRootUserTests == "true" {
		t.Skip("Skip test as skipRootUserTests set to true")
	}

	c, namespace := setup(t, withRegistry)
	t.Parallel()

	repo := fmt.Sprintf("registry.%s:5000/kanikotasktest", namespace)

	knativetest.CleanupOnInterrupt(func() { tearDown(t, c, namespace) }, t.Logf)
	defer tearDown(t, c, namespace)

	t.Logf("Creating Git PipelineResource %s", kanikoGitResourceName)
	if _, err := c.PipelineResourceClient.Create(getGitResource(namespace)); err != nil {
		t.Fatalf("Failed to create Pipeline Resource `%s`: %s", kanikoGitResourceName, err)
	}

	t.Logf("Creating Image PipelineResource %s", repo)
	if _, err := c.PipelineResourceClient.Create(getImageResource(namespace, repo)); err != nil {
		t.Fatalf("Failed to create Pipeline Resource `%s`: %s", kanikoGitResourceName, err)
	}

	t.Logf("Creating Task %s", kanikoTaskName)
	if _, err := c.TaskClient.Create(getTask(repo, namespace)); err != nil {
		t.Fatalf("Failed to create Task `%s`: %s", kanikoTaskName, err)
	}

	t.Logf("Creating TaskRun %s", kanikoTaskRunName)
	if _, err := c.TaskRunClient.Create(getTaskRun(namespace)); err != nil {
		t.Fatalf("Failed to create TaskRun `%s`: %s", kanikoTaskRunName, err)
	}

	// Verify status of TaskRun (wait for it)

	if err := WaitForTaskRunState(c, kanikoTaskRunName, func(tr *v1alpha1.TaskRun) (bool, error) {
		return TaskRunSucceed(kanikoTaskRunName)(tr)
	}, "TaskRunCompleted"); err != nil {
		t.Errorf("Error waiting for TaskRun %s to finish: %s", kanikoTaskRunName, err)
	}

	tr, err := c.TaskRunClient.Get(kanikoTaskRunName, metav1.GetOptions{})
	if err != nil {
		t.Errorf("Error retrieving taskrun: %s", err)
	}
	digest := ""
	commit := ""
	for _, rr := range tr.Status.ResourcesResult {
		switch rr.Key {
		case "digest":
			digest = rr.Value
		case "commit":
			commit = rr.Value
		}
	}
	if digest == "" {
		t.Errorf("Digest not found in TaskRun.Status: %v", tr.Status)
	}
	if commit == "" {
		t.Errorf("Commit not found in TaskRun.Status: %v", tr.Status)
	}

	if revision != commit {
		t.Fatalf("Expected remote commit to match local revision: %s, %s", commit, revision)
	}

	// match the local digest, which is first capture group against the remote image
	remoteDigest, err := getRemoteDigest(t, c, namespace, repo)
	if err != nil {
		t.Fatalf("Expected to get digest for remote image %s: %v", repo, err)
	}
	if d := cmp.Diff(digest, remoteDigest); d != "" {
		t.Fatalf("Expected local digest %s to match remote digest %s: %s", digest, remoteDigest, d)
	}
}

func getGitResource(namespace string) *v1alpha1.PipelineResource {
	return tb.PipelineResource(kanikoGitResourceName, namespace, tb.PipelineResourceSpec(
		v1alpha1.PipelineResourceTypeGit,
		tb.PipelineResourceSpecParam("Url", "https://github.com/GoogleContainerTools/kaniko"),
		tb.PipelineResourceSpecParam("Revision", revision),
	))
}

func getImageResource(namespace, repo string) *v1alpha1.PipelineResource {
	return tb.PipelineResource(kanikoImageResourceName, namespace, tb.PipelineResourceSpec(
		v1alpha1.PipelineResourceTypeImage,
		tb.PipelineResourceSpecParam("url", repo),
	))
}

func getTask(repo, namespace string) *v1alpha1.Task {
	root := int64(0)
	taskSpecOps := []tb.TaskSpecOp{
		tb.TaskInputs(tb.InputsResource("gitsource", v1alpha1.PipelineResourceTypeGit)),
		tb.TaskOutputs(tb.OutputsResource("builtImage", v1alpha1.PipelineResourceTypeImage)),
	}
	stepOps := []tb.StepOp{
		tb.StepArgs(
			"--dockerfile=/workspace/gitsource/integration/dockerfiles/Dockerfile_test_label",
			fmt.Sprintf("--destination=%s", repo),
			"--context=/workspace/gitsource",
			"--oci-layout-path=/workspace/output/builtImage",
			"--insecure",
			"--insecure-pull",
			"--insecure-registry=registry."+namespace+":5000/",
		),
		tb.StepSecurityContext(&corev1.SecurityContext{RunAsUser: &root}),
	}
	step := tb.Step("kaniko", "gcr.io/kaniko-project/executor:v0.13.0", stepOps...)
	taskSpecOps = append(taskSpecOps, step)
	sidecar := tb.Sidecar("registry", "registry")
	taskSpecOps = append(taskSpecOps, sidecar)

	return tb.Task(kanikoTaskName, namespace, tb.TaskSpec(taskSpecOps...))
}

func getTaskRun(namespace string) *v1alpha1.TaskRun {
	return tb.TaskRun(kanikoTaskRunName, namespace, tb.TaskRunSpec(
		tb.TaskRunTaskRef(kanikoTaskName),
		tb.TaskRunTimeout(2*time.Minute),
		tb.TaskRunInputs(tb.TaskRunInputsResource("gitsource", tb.TaskResourceBindingRef(kanikoGitResourceName))),
		tb.TaskRunOutputs(tb.TaskRunOutputsResource("builtImage", tb.TaskResourceBindingRef(kanikoImageResourceName))),
	))
}

// getRemoteDigest starts a pod to query the registry from the namespace itself, using skopeo (and jq).
// The reason we have to do that is because the image is pushed on a local registry that is not exposed
// to the "outside" of the test, this means it can be query by the test itself. It can only be query from
// a pod in the namespace. skopeo is able to do that query and we use jq to extract the digest from its
// output. The image used for this pod is build in the tektoncd/plumbing repository.
func getRemoteDigest(t *testing.T, c *clients, namespace, image string) (string, error) {
	t.Helper()
	podName := "skopeo-jq"
	if _, err := c.KubeClient.Kube.CoreV1().Pods(namespace).Create(&corev1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: namespace,
			Name:      podName,
		},
		Spec: corev1.PodSpec{
			Containers: []corev1.Container{{
				Name:    "skopeo",
				Image:   "gcr.io/tekton-releases/dogfooding/skopeo:latest",
				Command: []string{"/bin/sh", "-c"},
				Args:    []string{"skopeo inspect --tls-verify=false docker://" + image + ":latest| jq '.Digest'"},
			}},
			RestartPolicy: corev1.RestartPolicyNever,
		},
	}); err != nil {
		t.Fatalf("Failed to create the skopeo-jq pod: %v", err)
	}
	if err := WaitForPodState(c, podName, namespace, func(pod *corev1.Pod) (bool, error) {
		return pod.Status.Phase == "Succeeded" || pod.Status.Phase == "Failed", nil
	}, "PodContainersTerminated"); err != nil {
		t.Fatalf("Error waiting for Pod %q to terminate: %v", podName, err)
	}
	logs, err := getContainerLogsFromPod(c.KubeClient.Kube, podName, "skopeo", namespace)
	if err != nil {
		t.Fatalf("Could not get logs for pod %s: %s", podName, err)
	}
	return strings.TrimSpace(strings.ReplaceAll(logs, "\"", "")), nil
}
<|endoftext|>


<commit_before>package chalk

import (
	"fmt"
	"strconv"
	"strings"
)

// Formatter is
type Formatter []attribute

// colorFormatString reports basic formatting for string
func (f Formatter) colorFormatString() string {
	if !coloringEnabled {
		return ""
	}

	format := make([]string, len(f))
	for i, v := range f {
		format[i] = strconv.Itoa(int(v))
	}
	return fmt.Sprintf("%s[%sm", spEscape, strings.Join(format, ";"))
}

// Set sets formatting until other formatting function or Clear is called
func (f Formatter) Set() {
	fmt.Printf(f.colorFormatString())
}

// Clear clears formatting set by Set function
func Clear() {
	fmt.Print(spClear)
}

// Print is colored equivalent of fmt.Print
func (f Formatter) Print(a ...interface{}) {
	fmt.Print(f.colorFormatString() + fmt.Sprint(a...) + spClear)
}

// Sprint is colored equivalent of fmt.Sprint
func (f Formatter) Sprint(a ...interface{}) string {
	return fmt.Sprint(f.colorFormatString() + fmt.Sprint(a...) + spClear)
}

// Println is colored equivalent of fmt.Println
func (f Formatter) Println(a ...interface{}) {
	fmt.Println(f.colorFormatString() + fmt.Sprint(a...) + spClear)
}

// Sprintln is colored equivalent of fmt.Sprintln
func (f Formatter) Sprintln(a ...interface{}) string {
	return fmt.Sprintln(f.colorFormatString() + fmt.Sprint(a...) + spClear)
}

// Printf is colored equivalent of fmt.Printf
func (f Formatter) Printf(format string, a ...interface{}) {
	fmt.Printf(f.colorFormatString()+format+spClear, a...)
}

// Sprintf is colored equivalent of fmt.Sprintf
func (f Formatter) Sprintf(format string, a ...interface{}) string {
	return fmt.Sprintf(f.colorFormatString()+format+spClear, a...)
}
<commit_msg>++missing comment<commit_after>package chalk

import (
	"fmt"
	"strconv"
	"strings"
)

// Formatter is color formatter
type Formatter []attribute

// colorFormatString reports basic formatting for string
func (f Formatter) colorFormatString() string {
	if !coloringEnabled {
		return ""
	}

	format := make([]string, len(f))
	for i, v := range f {
		format[i] = strconv.Itoa(int(v))
	}
	return fmt.Sprintf("%s[%sm", spEscape, strings.Join(format, ";"))
}

// Set sets formatting until other formatting function or Clear is called
func (f Formatter) Set() {
	fmt.Printf(f.colorFormatString())
}

// Clear clears formatting set by Set function
func Clear() {
	fmt.Print(spClear)
}

// Print is colored equivalent of fmt.Print
func (f Formatter) Print(a ...interface{}) {
	fmt.Print(f.colorFormatString() + fmt.Sprint(a...) + spClear)
}

// Sprint is colored equivalent of fmt.Sprint
func (f Formatter) Sprint(a ...interface{}) string {
	return fmt.Sprint(f.colorFormatString() + fmt.Sprint(a...) + spClear)
}

// Println is colored equivalent of fmt.Println
func (f Formatter) Println(a ...interface{}) {
	fmt.Println(f.colorFormatString() + fmt.Sprint(a...) + spClear)
}

// Sprintln is colored equivalent of fmt.Sprintln
func (f Formatter) Sprintln(a ...interface{}) string {
	return fmt.Sprintln(f.colorFormatString() + fmt.Sprint(a...) + spClear)
}

// Printf is colored equivalent of fmt.Printf
func (f Formatter) Printf(format string, a ...interface{}) {
	fmt.Printf(f.colorFormatString()+format+spClear, a...)
}

// Sprintf is colored equivalent of fmt.Sprintf
func (f Formatter) Sprintf(format string, a ...interface{}) string {
	return fmt.Sprintf(f.colorFormatString()+format+spClear, a...)
}
<|endoftext|>


<commit_before><commit_msg>Oops.. It's a crawler not a DDOS machine<commit_after><|endoftext|>


<commit_before>// Package fastrand implements a cryptographically secure pseudorandom number
// generator. The generator is seeded using the system's default entropy
// source, and thereafter produces random values via repeated hashing. As a
// result, fastrand can generate randomness much faster than crypto/rand, and
// generation cannot fail.
package fastrand

import (
	"crypto/rand"
	"io"
	"math"
	"math/big"
	"runtime"
	"unsafe"

	"github.com/minio/blake2b-simd"
)

// A randReader produces random values via repeated hashing. The entropy field
// is the concatenation of an initial seed and a 128-bit counter. Each time
// the entropy is hashed, the counter is incremented.
type randReader struct {
	entropy chan []byte
}

// Read fills b with random data. It always returns len(b), nil.
func (r *randReader) Read(b []byte) (int, error) {
	n := 0
	for n < len(b) {
		n += copy(b[n:], <-r.entropy)
	}
	return n, nil
}

// fillEntropy continuously fills r.entropy with new entropy.
func (r *randReader) fillEntropy() {
	// Create a hasher and fill it with 64 bytes of entropy. Technically only 16
	// should be needed, but the underlying RNG may not be secure.
	h := blake2b.New256()
	_, err := io.CopyN(h, rand.Reader, 64)
	if err != nil {
		panic("fastrand: no entropy available")
	}
	seed := h.Sum(nil)

	for {
		for i := uint64(0); i < math.MaxUint64; i++ {
			// Update the seed.
			*(*uint64)(unsafe.Pointer(&seed[0])) = i

			// Hash the seed.
			h.Reset()
			h.Write(seed)

			// Send the entropy down the entropy channel.
			r.entropy <- h.Sum(nil)
		}

		// Re-seed the hasher. Use the entropy that existed previously,
		// protecting against a compromised RNG.
		h.Reset()
		h.Write(seed[:])
		io.CopyN(h, rand.Reader, 64)
		seed = h.Sum(seed[:0])
	}
}

// Reader is a global, shared instance of a cryptographically strong pseudo-
// random generator. It uses blake2b as its hashing function. Reader is safe
// for concurrent use by multiple goroutines.
var Reader io.Reader

func init() {
	r := &randReader{
		entropy: make(chan []byte, 1000),
	}
	for i := 0; i < runtime.NumCPU(); i++ {
		go r.fillEntropy()
	}
	Reader = r
}

// Read is a helper function that calls Reader.Read on b. It always fills b
// completely.
func Read(b []byte) { Reader.Read(b) }

// Bytes is a helper function that returns n bytes of random data.
func Bytes(n int) []byte {
	b := make([]byte, n)
	Read(b)
	return b
}

// Intn returns a uniform random value in [0,n). It panics if n <= 0.
func Intn(n int) int {
	if n <= 0 {
		panic("fastrand: argument to Intn is <= 0")
	}
	// To eliminate modulo bias, keep selecting at random until we fall within
	// a range that is evenly divisible by n.
	// NOTE: since n is at most math.MaxUint64/2, max is minimized when:
	//    n = math.MaxUint64/4 + 1 -> max = math.MaxUint64 - math.MaxUint64/4
	// This gives an expected 1.333 tries before choosing a value < max.
	max := math.MaxUint64 - math.MaxUint64%uint64(n)
	b := Bytes(8)
	r := *(*uint64)(unsafe.Pointer(&b[0]))
	for r >= max {
		Read(b)
		r = *(*uint64)(unsafe.Pointer(&b[0]))
	}
	return int(r % uint64(n))
}

// BigIntn returns a uniform random value in [0,n). It panics if n <= 0.
func BigIntn(n *big.Int) *big.Int {
	i, _ := rand.Int(Reader, n)
	return i
}

// Perm returns a random permutation of the integers [0,n).
func Perm(n int) []int {
	m := make([]int, n)
	for i := 1; i < n; i++ {
		j := Intn(i + 1)
		m[i] = m[j]
		m[j] = i
	}
	return m
}
<commit_msg>remove possibility of error upon reseed<commit_after>// Package fastrand implements a cryptographically secure pseudorandom number
// generator. The generator is seeded using the system's default entropy
// source, and thereafter produces random values via repeated hashing. As a
// result, fastrand can generate randomness much faster than crypto/rand, and
// generation cannot fail.
package fastrand

import (
	"crypto/rand"
	"io"
	"math"
	"math/big"
	"runtime"
	"unsafe"

	"github.com/minio/blake2b-simd"
)

// A randReader produces random values via repeated hashing. The entropy field
// is the concatenation of an initial seed and a 128-bit counter. Each time
// the entropy is hashed, the counter is incremented.
type randReader struct {
	entropy chan []byte
}

// Read fills b with random data. It always returns len(b), nil.
func (r *randReader) Read(b []byte) (int, error) {
	n := 0
	for n < len(b) {
		n += copy(b[n:], <-r.entropy)
	}
	return n, nil
}

// fillEntropy continuously fills r.entropy with new entropy.
func (r *randReader) fillEntropy() {
	// Create a hasher and fill it with 64 bytes of entropy. Technically only 16
	// should be needed, but the underlying RNG may not be secure.
	h := blake2b.New256()
	_, err := io.CopyN(h, rand.Reader, 64)
	if err != nil {
		panic("fastrand: no entropy available")
	}
	seed := h.Sum(nil)

	for {
		for i := uint64(0); i < math.MaxUint64; i++ {
			// Update the seed.
			*(*uint64)(unsafe.Pointer(&seed[0])) = i

			// Hash the seed.
			h.Reset()
			h.Write(seed)

			// Send the entropy down the entropy channel.
			r.entropy <- h.Sum(nil)
		}

		// Re-seed the hasher. Use the entropy that existed previously,
		// protecting against a compromised RNG.
		h.Reset()
		h.Write(seed[:])
		seed = h.Sum(seed[:0])
	}
}

// Reader is a global, shared instance of a cryptographically strong pseudo-
// random generator. It uses blake2b as its hashing function. Reader is safe
// for concurrent use by multiple goroutines.
var Reader io.Reader

func init() {
	r := &randReader{
		entropy: make(chan []byte, 1000),
	}
	for i := 0; i < runtime.NumCPU(); i++ {
		go r.fillEntropy()
	}
	Reader = r
}

// Read is a helper function that calls Reader.Read on b. It always fills b
// completely.
func Read(b []byte) { Reader.Read(b) }

// Bytes is a helper function that returns n bytes of random data.
func Bytes(n int) []byte {
	b := make([]byte, n)
	Read(b)
	return b
}

// Intn returns a uniform random value in [0,n). It panics if n <= 0.
func Intn(n int) int {
	if n <= 0 {
		panic("fastrand: argument to Intn is <= 0")
	}
	// To eliminate modulo bias, keep selecting at random until we fall within
	// a range that is evenly divisible by n.
	// NOTE: since n is at most math.MaxUint64/2, max is minimized when:
	//    n = math.MaxUint64/4 + 1 -> max = math.MaxUint64 - math.MaxUint64/4
	// This gives an expected 1.333 tries before choosing a value < max.
	max := math.MaxUint64 - math.MaxUint64%uint64(n)
	b := Bytes(8)
	r := *(*uint64)(unsafe.Pointer(&b[0]))
	for r >= max {
		Read(b)
		r = *(*uint64)(unsafe.Pointer(&b[0]))
	}
	return int(r % uint64(n))
}

// BigIntn returns a uniform random value in [0,n). It panics if n <= 0.
func BigIntn(n *big.Int) *big.Int {
	i, _ := rand.Int(Reader, n)
	return i
}

// Perm returns a random permutation of the integers [0,n).
func Perm(n int) []int {
	m := make([]int, n)
	for i := 1; i < n; i++ {
		j := Intn(i + 1)
		m[i] = m[j]
		m[j] = i
	}
	return m
}
<|endoftext|>


<commit_before>// Copyright 2017-2021 the LinuxBoot 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 main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/linuxboot/fiano/pkg/intel/metadata/manifest/common/manifestcodegen/pkg/analyze"
)

func deleteBackupFiles(dirPath string) error {
	files, err := ioutil.ReadDir(dirPath)
	if err != nil {
		return fmt.Errorf("unable to open '%s' as dir: %w", dirPath, err)
	}

	for _, file := range files {
		if file.IsDir() || !strings.HasSuffix(file.Name(), "_manifestcodegen.go~") {
			continue
		}

		path := filepath.Join(dirPath, file.Name())
		err := os.Remove(path)
		if err != nil {
			return fmt.Errorf("unable to delete file '%s': %w", path, err)
		}
	}

	return nil
}

func backupGeneratedFiles(dirPath string, isReverse bool) error {
	files, err := ioutil.ReadDir(dirPath)
	if err != nil {
		return fmt.Errorf("unable to open '%s' as dir: %w", dirPath, err)
	}

	suffix := "_manifestcodegen.go"
	if isReverse {
		suffix += "~"
	}

	for _, file := range files {
		if file.IsDir() || !strings.HasSuffix(file.Name(), suffix) {
			continue
		}

		var err error
		path := filepath.Join(dirPath, file.Name())
		if isReverse {
			err = os.Rename(path, path[:len(path)-1])
		} else {
			err = os.Rename(path, path+"~")
		}
		if err != nil {
			return fmt.Errorf("unable to delete file '%s': %w", path, err)
		}
	}

	return nil
}

func processPath(path string, isCheck, enableTracing bool) error {
	if stat, err := os.Stat(path); err == nil && stat.IsDir() {
		err := backupGeneratedFiles(path, false)
		if err != nil {
			return fmt.Errorf("unable to rename old generated files: %w", err)
		}
	}

	// ugly terrible hack to workaround versioning support
	// TODO: fix the importer to recognize `/v2/` as version, not as path
	os.Setenv("GO111MODULE", "off")

	var goPaths []string
	if gopathEnv := os.Getenv("GOPATH"); gopathEnv != "" {
		goPaths = filepath.SplitList(gopathEnv)
	} else {
		homeDir, err := os.UserHomeDir()
		if err != nil {
			return fmt.Errorf("unable to determine the homedir: %w", err)
		}

		goPaths = append(goPaths, filepath.Join(homeDir, "go"))
	}

	dirInfo, err := analyze.Scan(path, goPaths)
	if err != nil {
		return fmt.Errorf("unable to analyze path '%s': %w", path, err)
	}

	for _, fileInfo := range dirInfo.Files {
		err := generateMethodsFile(*fileInfo, isCheck, enableTracing)
		if err != nil {
			_ = backupGeneratedFiles(path, true)
			return err
		}
	}

	if isCheck {
		err := backupGeneratedFiles(path, true)
		if err != nil {
			return fmt.Errorf("unable to rename back old generated files: %w", err)
		}
	} else {
		err := deleteBackupFiles(path)
		if err != nil {
			return fmt.Errorf("unable to rename back old generated files: %w", err)
		}
	}

	return nil
}

func processPaths(paths []string, checkFlag, traceFlag bool) int {
	errorCount := 0
	for _, path := range paths {
		err := processPath(path, checkFlag, traceFlag)
		if err != nil {
			log.Printf("an error: %v", err)
			errorCount++
		}
	}

	return errorCount
}

func main() {
	checkFlag := flag.Bool("check", false, "generate with tracing code")
	traceFlag := flag.Bool("trace", false, "generate with tracing code")
	flag.Parse()

	var paths []string

	switch {
	case flag.NArg() > 0:
		paths = append(paths, flag.Args()...)
	case os.Getenv("GOFILE") != "":
		paths = append(paths, os.Getenv("GOFILE"))
	default:
		paths = append(paths, ".")
	}

	errorCount := processPaths(paths, *checkFlag, *traceFlag)
	if errorCount != 0 {
		os.Exit(1)
	}
}
<commit_msg>clean(intel/.../manifest): Remove GO111MODULE hack<commit_after>// Copyright 2017-2021 the LinuxBoot 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 main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/linuxboot/fiano/pkg/intel/metadata/manifest/common/manifestcodegen/pkg/analyze"
)

func deleteBackupFiles(dirPath string) error {
	files, err := ioutil.ReadDir(dirPath)
	if err != nil {
		return fmt.Errorf("unable to open '%s' as dir: %w", dirPath, err)
	}

	for _, file := range files {
		if file.IsDir() || !strings.HasSuffix(file.Name(), "_manifestcodegen.go~") {
			continue
		}

		path := filepath.Join(dirPath, file.Name())
		err := os.Remove(path)
		if err != nil {
			return fmt.Errorf("unable to delete file '%s': %w", path, err)
		}
	}

	return nil
}

func backupGeneratedFiles(dirPath string, isReverse bool) error {
	files, err := ioutil.ReadDir(dirPath)
	if err != nil {
		return fmt.Errorf("unable to open '%s' as dir: %w", dirPath, err)
	}

	suffix := "_manifestcodegen.go"
	if isReverse {
		suffix += "~"
	}

	for _, file := range files {
		if file.IsDir() || !strings.HasSuffix(file.Name(), suffix) {
			continue
		}

		var err error
		path := filepath.Join(dirPath, file.Name())
		if isReverse {
			err = os.Rename(path, path[:len(path)-1])
		} else {
			err = os.Rename(path, path+"~")
		}
		if err != nil {
			return fmt.Errorf("unable to delete file '%s': %w", path, err)
		}
	}

	return nil
}

func processPath(path string, isCheck, enableTracing bool) error {
	if stat, err := os.Stat(path); err == nil && stat.IsDir() {
		err := backupGeneratedFiles(path, false)
		if err != nil {
			return fmt.Errorf("unable to rename old generated files: %w", err)
		}
	}

	var goPaths []string
	if gopathEnv := os.Getenv("GOPATH"); gopathEnv != "" {
		goPaths = filepath.SplitList(gopathEnv)
	} else {
		homeDir, err := os.UserHomeDir()
		if err != nil {
			return fmt.Errorf("unable to determine the homedir: %w", err)
		}

		goPaths = append(goPaths, filepath.Join(homeDir, "go"))
	}

	dirInfo, err := analyze.Scan(path, goPaths)
	if err != nil {
		return fmt.Errorf("unable to analyze path '%s': %w", path, err)
	}

	for _, fileInfo := range dirInfo.Files {
		err := generateMethodsFile(*fileInfo, isCheck, enableTracing)
		if err != nil {
			_ = backupGeneratedFiles(path, true)
			return err
		}
	}

	if isCheck {
		err := backupGeneratedFiles(path, true)
		if err != nil {
			return fmt.Errorf("unable to rename back old generated files: %w", err)
		}
	} else {
		err := deleteBackupFiles(path)
		if err != nil {
			return fmt.Errorf("unable to rename back old generated files: %w", err)
		}
	}

	return nil
}

func processPaths(paths []string, checkFlag, traceFlag bool) int {
	errorCount := 0
	for _, path := range paths {
		err := processPath(path, checkFlag, traceFlag)
		if err != nil {
			log.Printf("an error: %v", err)
			errorCount++
		}
	}

	return errorCount
}

func main() {
	checkFlag := flag.Bool("check", false, "generate with tracing code")
	traceFlag := flag.Bool("trace", false, "generate with tracing code")
	flag.Parse()

	var paths []string

	switch {
	case flag.NArg() > 0:
		paths = append(paths, flag.Args()...)
	case os.Getenv("GOFILE") != "":
		paths = append(paths, os.Getenv("GOFILE"))
	default:
		paths = append(paths, ".")
	}

	errorCount := processPaths(paths, *checkFlag, *traceFlag)
	if errorCount != 0 {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package webhook

import (
	"encoding/json"
	"github.com/HouzuoGuo/tiedot/db"
	"github.com/tyler-sommer/squircy2/squircy/script"
	"sort"
)

type Webhook struct {
	ID              int
	Type            script.ScriptType
	Body            string // script to execute for processing
	Title           string
	Url             string
	Key             string
	SignatureHeader string // header containing signature
	Enabled         bool
}

type WebhookRepository struct {
	database *db.DB
}

func NewWebhookRepository(database *db.DB) WebhookRepository {
	return WebhookRepository{database}
}

func hydrateWebhook(rawWebhook map[string]interface{}) *Webhook {
	webhook := &Webhook{}

	webhook.Type = script.ScriptType(rawWebhook["Type"].(string))
	webhook.Body = rawWebhook["Body"].(string)
	webhook.Title = rawWebhook["Title"].(string)
	webhook.Url = rawWebhook["Url"].(string)
	webhook.Key = rawWebhook["Key"].(string)
	webhook.SignatureHeader = rawWebhook["SignatureHeader"].(string)
	webhook.Enabled = rawWebhook["Enabled"].(bool)

	return webhook
}

func flattenWebhook(webhook *Webhook) map[string]interface{} {
	rawWebhook := make(map[string]interface{})

	rawWebhook["Type"] = webhook.Type
	rawWebhook["Body"] = webhook.Body
	rawWebhook["Title"] = webhook.Title
	rawWebhook["Url"] = webhook.Url
	rawWebhook["Key"] = webhook.Key
	rawWebhook["SignatureHeader"] = webhook.SignatureHeader
	rawWebhook["Enabled"] = webhook.Enabled

	return rawWebhook
}

type webhookSlice []*Webhook

func (s webhookSlice) Len() int {
	return len(s)
}

func (s webhookSlice) Less(i, j int) bool {
	return s[i].Title < s[j].Title
}

func (s webhookSlice) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (repo *WebhookRepository) FetchAll() []*Webhook {
	col := repo.database.Use("Webhooks")
	webhooks := make([]*Webhook, 0)
	col.ForEachDoc(func(id int, doc []byte) (moveOn bool) {
		moveOn = true

		val := make(map[string]interface{}, 0)

		json.Unmarshal(doc, &val)
		webhook := hydrateWebhook(val)
		webhook.ID = id

		webhooks = append(webhooks, webhook)

		return
	})

	sort.Sort(webhookSlice(webhooks))

	return webhooks
}

func (repo *WebhookRepository) Fetch(id int) *Webhook {
	col := repo.database.Use("Webhooks")

	rawWebhook, err := col.Read(id)
	if err != nil {
		panic(err)
	}
	webhook := hydrateWebhook(rawWebhook)
	webhook.ID = id

	return webhook
}

func (repo *WebhookRepository) Save(webhook *Webhook) {
	col := repo.database.Use("Webhooks")
	data := flattenWebhook(webhook)

	if webhook.ID <= 0 {
		id, _ := col.Insert(data)
		webhook.ID = id

	} else {
		col.Update(webhook.ID, data)
	}
}

func (repo *WebhookRepository) Delete(id int) {
	col := repo.database.Use("Webhooks")
	col.Delete(id)
}
<commit_msg>a WebhookRepository.FetchByUrl method<commit_after>package webhook

import (
	"encoding/json"
	"github.com/HouzuoGuo/tiedot/db"
	"github.com/tyler-sommer/squircy2/squircy/script"
	"sort"
)

type Webhook struct {
	ID              int
	Type            script.ScriptType
	Body            string // script to execute for processing
	Title           string
	Url             string
	Key             string
	SignatureHeader string // header containing signature
	Enabled         bool
}

type WebhookRepository struct {
	database *db.DB
}

func NewWebhookRepository(database *db.DB) WebhookRepository {
	return WebhookRepository{database}
}

func hydrateWebhook(rawWebhook map[string]interface{}) *Webhook {
	webhook := &Webhook{}

	webhook.Type = script.ScriptType(rawWebhook["Type"].(string))
	webhook.Body = rawWebhook["Body"].(string)
	webhook.Title = rawWebhook["Title"].(string)
	webhook.Url = rawWebhook["Url"].(string)
	webhook.Key = rawWebhook["Key"].(string)
	webhook.SignatureHeader = rawWebhook["SignatureHeader"].(string)
	webhook.Enabled = rawWebhook["Enabled"].(bool)

	return webhook
}

func flattenWebhook(webhook *Webhook) map[string]interface{} {
	rawWebhook := make(map[string]interface{})

	rawWebhook["Type"] = webhook.Type
	rawWebhook["Body"] = webhook.Body
	rawWebhook["Title"] = webhook.Title
	rawWebhook["Url"] = webhook.Url
	rawWebhook["Key"] = webhook.Key
	rawWebhook["SignatureHeader"] = webhook.SignatureHeader
	rawWebhook["Enabled"] = webhook.Enabled

	return rawWebhook
}

type webhookSlice []*Webhook

func (s webhookSlice) Len() int {
	return len(s)
}

func (s webhookSlice) Less(i, j int) bool {
	return s[i].Title < s[j].Title
}

func (s webhookSlice) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (repo *WebhookRepository) FetchAll() []*Webhook {
	col := repo.database.Use("Webhooks")
	webhooks := make([]*Webhook, 0)
	col.ForEachDoc(func(id int, doc []byte) (moveOn bool) {
		moveOn = true

		val := make(map[string]interface{}, 0)

		json.Unmarshal(doc, &val)
		webhook := hydrateWebhook(val)
		webhook.ID = id

		webhooks = append(webhooks, webhook)

		return
	})

	sort.Sort(webhookSlice(webhooks))

	return webhooks
}

func (repo *WebhookRepository) Fetch(id int) *Webhook {
	col := repo.database.Use("Webhooks")

	rawWebhook, err := col.Read(id)
	if err != nil {
		panic(err)
	}
	webhook := hydrateWebhook(rawWebhook)
	webhook.ID = id

	return webhook
}

func (repo *WebhookRepository) Save(webhook *Webhook) {
	col := repo.database.Use("Webhooks")
	data := flattenWebhook(webhook)

	if webhook.ID <= 0 {
		id, _ := col.Insert(data)
		webhook.ID = id

	} else {
		col.Update(webhook.ID, data)
	}
}

func (repo *WebhookRepository) Delete(id int) {
	col := repo.database.Use("Webhooks")
	col.Delete(id)
}

func (repo *WebhookRepository) FetchByUrl(url string) *Webhook {
	col := repo.database.Use("Webhooks")
	webhook := &Webhook{}
	col.ForEachDoc(func(id int, doc []byte) (moveOn bool) {
		moveOn = true
		val := make(map[string]interface{}, 0)
		json.Unmarshal(doc, &val)
		webhook := hydrateWebhook(val)
		webhook.ID = id
		if val["Url"] == url {
			return false
		}
		return
	})
	return webhook
}
<|endoftext|>


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

package job

import (
	"context"
	"fmt"
	"reflect"
	"sync"

	"github.com/google/gapid/core/event"
	"github.com/google/gapid/core/os/device"
	"github.com/google/gapid/test/robot/record"
	"github.com/google/gapid/test/robot/search"
	"github.com/google/gapid/test/robot/search/eval"
)

type devices struct {
	mu       sync.Mutex
	ledger   record.Ledger
	entries  []*Device
	byID     map[string]*Device
	onChange event.Broadcast
}

func (l *devices) init(ctx context.Context, library record.Library) error {
	ledger, err := library.Open(ctx, "devices", &Device{})
	if err != nil {
		return err
	}
	l.ledger = ledger
	l.byID = map[string]*Device{}
	apply := event.AsHandler(ctx, l.apply)
	if err := ledger.Read(ctx, apply); err != nil {
		return err
	}
	ledger.Watch(ctx, apply)
	return nil
}

func (l *devices) apply(ctx context.Context, entry *Device) error {
	l.entries = append(l.entries, entry)
	l.byID[entry.Id] = entry
	l.onChange.Send(ctx, entry)
	return nil
}

func (l *devices) search(ctx context.Context, query *search.Query, handler DeviceHandler) error {
	filter := eval.Filter(ctx, query, reflect.TypeOf(&Device{}), event.AsHandler(ctx, handler))
	initial := event.AsProducer(ctx, l.entries)
	if query.Monitor {
		return event.Monitor(ctx, &l.mu, l.onChange.Listen, initial, filter)
	}
	return event.Feed(ctx, filter, initial)
}

func (l *devices) uniqueName(ctx context.Context, name string) string {
	index := 0
	id := name
	for {
		if _, found := l.byID[id]; !found {
			return id
		}
		index++
		id = fmt.Sprintf("%s-%d", name, index)
	}
}

func sameDevice(match *Device, info *device.Instance) bool {
	if match == nil {
		return info == nil
	}
	if info == nil {
		return false
	}
	return match.Information.SameAs(info)
}

func (l *devices) find(ctx context.Context, info *device.Instance) *Device {
	for _, entry := range l.entries {
		if sameDevice(entry, info) {
			return entry
		}
	}
	return nil
}

func (l *devices) get(ctx context.Context, info *device.Instance) (*Device, error) {
	if info == nil {
		return nil, nil
	}
	l.mu.Lock()
	defer l.mu.Unlock()
	entry := l.find(ctx, info)
	if entry == nil {
		entry = &Device{
			Id:          l.uniqueName(ctx, info.Id.ID().String()),
			Information: info,
		}
		if err := l.ledger.Add(ctx, entry); err != nil {
			return nil, err
		}
	} else {
		entry.Information = info
	}
	return entry, nil
}
<commit_msg>Fix a case error in robot.<commit_after>// Copyright (C) 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package job

import (
	"context"
	"fmt"
	"reflect"
	"sync"

	"github.com/google/gapid/core/event"
	"github.com/google/gapid/core/os/device"
	"github.com/google/gapid/test/robot/record"
	"github.com/google/gapid/test/robot/search"
	"github.com/google/gapid/test/robot/search/eval"
)

type devices struct {
	mu       sync.Mutex
	ledger   record.Ledger
	entries  []*Device
	byID     map[string]*Device
	onChange event.Broadcast
}

func (l *devices) init(ctx context.Context, library record.Library) error {
	ledger, err := library.Open(ctx, "devices", &Device{})
	if err != nil {
		return err
	}
	l.ledger = ledger
	l.byID = map[string]*Device{}
	apply := event.AsHandler(ctx, l.apply)
	if err := ledger.Read(ctx, apply); err != nil {
		return err
	}
	ledger.Watch(ctx, apply)
	return nil
}

func (l *devices) apply(ctx context.Context, entry *Device) error {
	l.entries = append(l.entries, entry)
	l.byID[entry.Id] = entry
	l.onChange.Send(ctx, entry)
	return nil
}

func (l *devices) search(ctx context.Context, query *search.Query, handler DeviceHandler) error {
	filter := eval.Filter(ctx, query, reflect.TypeOf(&Device{}), event.AsHandler(ctx, handler))
	initial := event.AsProducer(ctx, l.entries)
	if query.Monitor {
		return event.Monitor(ctx, &l.mu, l.onChange.Listen, initial, filter)
	}
	return event.Feed(ctx, filter, initial)
}

func (l *devices) uniqueName(ctx context.Context, name string) string {
	index := 0
	id := name
	for {
		if _, found := l.byID[id]; !found {
			return id
		}
		index++
		id = fmt.Sprintf("%s-%d", name, index)
	}
}

func sameDevice(match *Device, info *device.Instance) bool {
	if match == nil {
		return info == nil
	}
	if info == nil {
		return false
	}
	return match.Information.SameAs(info)
}

func (l *devices) find(ctx context.Context, info *device.Instance) *Device {
	for _, entry := range l.entries {
		if sameDevice(entry, info) {
			return entry
		}
	}
	return nil
}

func (l *devices) get(ctx context.Context, info *device.Instance) (*Device, error) {
	if info == nil {
		return nil, nil
	}
	l.mu.Lock()
	defer l.mu.Unlock()
	entry := l.find(ctx, info)
	if entry == nil {
		entry = &Device{
			Id:          l.uniqueName(ctx, info.ID.ID().String()),
			Information: info,
		}
		if err := l.ledger.Add(ctx, entry); err != nil {
			return nil, err
		}
	} else {
		entry.Information = info
	}
	return entry, nil
}
<|endoftext|>


<commit_before>// Copyright 2013 Alexandre Fiori
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Diameter server.

// Generate SSL certificates:
// go run $GOROOT/src/pkg/crypto/tls/generate_cert.go --host localhost

package main

import (
	"flag"
	"log"
	"net"

	"github.com/fiorix/go-diameter/diam"
)

const (
	Identity    = "server"
	Realm       = "localhost"
	VendorId    = 13
	ProductName = "go-diameter"
)

func main() {
	addr := flag.String("l", ":3868", "listen address and port")
	cert := flag.String("cert", "", "SSL cert file (e.g. cert.pem)")
	key := flag.String("key", "", "SSL key file (e.g. key.pem)")
	flag.Parse()
	diam.HandleFunc("CER", OnCER)
	diam.HandleFunc("DWR", OnDWR)
	diam.HandleFunc("ALL", OnMSG) // Catch all
	// Handle server errors.
	go func() {
		for {
			report := <-diam.ErrorReports()
			log.Println("Error:", report.Error)
		}
	}()
	// Start server.
	if *cert != "" && *key != "" {
		log.Println("Starting secure server on", *addr)
		diam.ListenAndServeTLS(*addr, *cert, *key, nil, nil)
	} else {
		log.Println("Starting server on", *addr)
		diam.ListenAndServe(*addr, nil, nil)
	}
}

// OnCER handles Capabilities-Exchange-Request messages.
func OnCER(c diam.Conn, m *diam.Message) {
	// Reject client if there's no Origin-Host.
	host, err := m.FindAVP("Origin-Host")
	if err != nil {
		c.Close()
		return
	}
	// Reject client if there's no Origin-Realm.
	realm, err := m.FindAVP("Origin-Realm")
	if err != nil {
		c.Close()
		return
	}
	// Reject client if there's no Host-IP-Address.
	ipaddr, err := m.FindAVP("Host-IP-Address")
	if err != nil {
		c.Close()
		return
	}
	// Reject client if there's no Origin-State-Id.
	stateId, err := m.FindAVP("Origin-State-Id")
	if err != nil {
		c.Close()
		return
	}
	//log.Println("Receiving message from %s", c.RemoteAddr().String())
	log.Printf("Receiving message from %s.%s (%s)",
		host.Data().(string),
		realm.Data().(string),
		ipaddr.Data().(net.IP).String(),
	)
	m.PrettyPrint()
	// Craft CEA with result code 2001 (OK).
	a := m.Answer(2001)
	a.NewAVP("Origin-Host", 0x40, 0x00, Identity)
	a.NewAVP("Origin-Realm", 0x40, 0x00, Realm)
	IP, _, _ := net.SplitHostPort(c.LocalAddr().String())
	a.NewAVP("Host-IP-Address", 0x40, 0x0, IP)
	a.NewAVP("Vendor-Id", 0x40, 0x0, VendorId)
	a.NewAVP("Product-Name", 0x40, 0x0, ProductName)
	// Copy origin Origin-State-Id.
	a.Add(stateId)
	log.Printf("Sending message to %s", c.RemoteAddr().String())
	a.PrettyPrint()
	// Send message to the connection
	if _, err := c.Write(a); err != nil {
		log.Println("Write failed:", err)
		c.Close()
	}
	go func() {
		<-c.(diam.CloseNotifier).CloseNotify()
		log.Printf("Client %s disconnected", c.RemoteAddr().String())
	}()
}

// OnDWR handles Device-Watchdog-Request messages.
func OnDWR(c diam.Conn, m *diam.Message) {
	// Reject client if there's no Origin-State-Id.
	stateId, err := m.FindAVP("Origin-State-Id")
	if err != nil {
		c.Close()
		return
	}
	log.Printf("Receiving message from %s", c.RemoteAddr().String())
	m.PrettyPrint()
	// Craft DWA with result code 2001 (OK).
	a := m.Answer(2001)
	a.NewAVP("Origin-Host", 0x40, 0x00, Identity)
	a.NewAVP("Origin-Realm", 0x40, 0x00, Realm)
	a.Add(stateId)
	log.Printf("Sending message to %s", c.RemoteAddr().String())
	a.PrettyPrint()
	// Send message to the connection
	if _, err := c.Write(a); err != nil {
		log.Println("Write failed:", err)
		c.Close()
	}
}

// OnMSG handles all other messages. Catch all.
func OnMSG(c diam.Conn, m *diam.Message) {
	log.Printf("Receiving message from %s", c.RemoteAddr().String())
	m.PrettyPrint()
}
<commit_msg>Improvements<commit_after>// Copyright 2013 Alexandre Fiori
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Diameter server.

// Generate SSL certificates:
// go run $GOROOT/src/pkg/crypto/tls/generate_cert.go --host localhost

package main

import (
	"flag"
	"log"
	"net"

	"github.com/fiorix/go-diameter/diam"
)

const (
	Identity    = "server"
	Realm       = "localhost"
	VendorId    = 13
	ProductName = "go-diameter"
)

var Quiet bool

func main() {
	addr := flag.String("l", ":3868", "listen address and port")
	cert := flag.String("cert", "", "SSL cert file (e.g. cert.pem)")
	key := flag.String("key", "", "SSL key file (e.g. key.pem)")
	q := flag.Bool("q", false, "quiet, do not print messages")
	flag.Parse()
	Quiet = *q
	diam.HandleFunc("CER", OnCER)
	diam.HandleFunc("ALL", OnMSG) // Catch all
	// Handle server errors.
	go func() {
		for {
			report := <-diam.ErrorReports()
			log.Println("Error:", report.Error)
		}
	}()
	// Start server.
	if *cert != "" && *key != "" {
		log.Println("Starting secure server on", *addr)
		diam.ListenAndServeTLS(*addr, *cert, *key, nil, nil)
	} else {
		log.Println("Starting server on", *addr)
		diam.ListenAndServe(*addr, nil, nil)
	}
}

// OnCER handles Capabilities-Exchange-Request messages.
func OnCER(c diam.Conn, m *diam.Message) {
	// Reject client if there's no Origin-Host.
	host, err := m.FindAVP("Origin-Host")
	if err != nil {
		c.Close()
		return
	}
	// Reject client if there's no Origin-Realm.
	realm, err := m.FindAVP("Origin-Realm")
	if err != nil {
		c.Close()
		return
	}
	// Reject client if there's no Host-IP-Address.
	ipaddr, err := m.FindAVP("Host-IP-Address")
	if err != nil {
		c.Close()
		return
	}
	// Reject client if there's no Origin-State-Id.
	stateId, err := m.FindAVP("Origin-State-Id")
	if err != nil {
		c.Close()
		return
	}
	if !Quiet {
		//log.Println("Receiving message from %s", c.RemoteAddr().String())
		log.Printf("Receiving message from %s.%s (%s)",
			host.Data().(string),
			realm.Data().(string),
			ipaddr.Data().(net.IP).String(),
		)
		m.PrettyPrint()
	}
	// Craft CEA with result code 2001 (OK).
	a := m.Answer(2001)
	a.NewAVP("Origin-Host", 0x40, 0x00, Identity)
	a.NewAVP("Origin-Realm", 0x40, 0x00, Realm)
	IP, _, _ := net.SplitHostPort(c.LocalAddr().String())
	a.NewAVP("Host-IP-Address", 0x40, 0x0, IP)
	a.NewAVP("Vendor-Id", 0x40, 0x0, VendorId)
	a.NewAVP("Product-Name", 0x40, 0x0, ProductName)
	// Copy origin Origin-State-Id.
	a.Add(stateId)
	if !Quiet {
		log.Printf("Sending message to %s", c.RemoteAddr().String())
		a.PrettyPrint()
	}
	// Send message to the connection
	if _, err := c.Write(a); err != nil {
		log.Println("Write failed:", err)
		c.Close()
	}
	go func() {
		<-c.(diam.CloseNotifier).CloseNotify()
		log.Printf("Client %s disconnected", c.RemoteAddr().String())
	}()
}

// OnMSG handles all other messages and replies to them
// with a generic 2001 (OK) answer.
func OnMSG(c diam.Conn, m *diam.Message) {
	// Ignored message if there's no Origin-State-Id.
	stateId, err := m.FindAVP("Origin-State-Id")
	if err != nil {
		return
	}
	if !Quiet {
		log.Printf(
			"Receiving message from %s", c.RemoteAddr().String())
		m.PrettyPrint()
	}
	// Craft DWA with result code 2001 (OK).
	a := m.Answer(2001)
	a.NewAVP("Origin-Host", 0x40, 0x00, Identity)
	a.NewAVP("Origin-Realm", 0x40, 0x00, Realm)
	a.Add(stateId)
	if !Quiet {
		log.Printf("Sending message to %s", c.RemoteAddr().String())
		a.PrettyPrint()
	}
	// Send message to the connection
	if _, err := c.Write(a); err != nil {
		log.Println("Write failed:", err)
		c.Close()
	}
}
<|endoftext|>


<commit_before><commit_msg>fnserver: 0.3.280 release [skip ci]<commit_after><|endoftext|>


<commit_before>package mqswag

const TYPE_OBJECT = "object"
const TYPE_BOOL = "boolean"
const TYPE_STRING = "string"

// This file implements the in-memory DB that holds all the entity objects.

type ProperInterface interface {
}

type EntityInterface interface {
	Type() string

	// PropertyType returns the type for the named property. Returns "" if not found.
	// For non-object typed entities, always return ""
	PropertyType(propertyName string) string

	// Whether the given object matches this entity - the object is the same type and has all the attributes.
	Matches(entity EntityInterface) bool
}

// Definition is the same as the swagger definition of type "object".
type ObjectDefinition struct {
	Name       string
	Properties map[string]EntityInterface
}

func (self *ObjectDefinition) Type() string {
	return "object"
}

func (self *ObjectDefinition) PropertyType(propertyName string) string {
	if property, ok := self.Properties[propertyName]; ok {
		return property.Type()
	}
	return ""
}

func (self *ObjectDefinition) Matches(entity EntityInterface) bool {
	if self.Type() != entity.Type() {
		return false
	}
	panic("not implemented")
	return true
}
<commit_msg>Add SchemaDB search functions.<commit_after>package mqswag

import (
	"errors"
	"meqa/mqutil"
	"reflect"

	"github.com/go-openapi/spec"
	"github.com/xeipuuv/gojsonschema"
)

// This file implements the in-memory DB that holds all the entity objects.

// Schema is the swagger spec schema.
type Schema spec.Schema

// Matches checks if the Schema matches the input interface. In proper swagger.json
// Enums should have types as well. So we don't check for untyped enums.
// TODO check format, handle AllOf, AnyOf, OneOf
func (schema *Schema) Matches(object interface{}) bool {
	if object == nil {
		return schema.Type[0] == gojsonschema.TYPE_NULL
	}

	k := reflect.TypeOf(object).Kind()
	if k == reflect.Bool {
		return schema.Type[0] == gojsonschema.TYPE_BOOLEAN
	} else if k >= reflect.Int && k <= reflect.Uint64 {
		return schema.Type[0] == gojsonschema.TYPE_INTEGER || schema.Type[0] == gojsonschema.TYPE_NUMBER
	} else if k == reflect.Float32 || k == reflect.Float64 {
		return schema.Type[0] == gojsonschema.TYPE_NUMBER
	} else if k == reflect.Array || k == reflect.Slice {
		if schema.Type[0] != gojsonschema.TYPE_ARRAY {
			return false
		}
		// Check the array elements.
		itemsSchema := (*Schema)(schema.Items.Schema)
		ar := object.([]interface{})
		for _, item := range ar {
			if !itemsSchema.Matches(item) {
				return false
			}
		}
		return true
	} else if k == reflect.Map {
		if schema.Type[0] != gojsonschema.TYPE_OBJECT {
			return false
		}
		// check the object content.
		return schema.MatchesMap(object.(map[string]interface{}))
	} else if k == reflect.String {
		if schema.Type[0] == gojsonschema.TYPE_STRING {
			return true
		}
	} else {
		mqutil.Logger.Printf("unknown type: %v", k)
	}
	return false
}

// MatchesMap checks if the Schema matches the input map.
func (schema *Schema) MatchesMap(obj map[string]interface{}) bool {
	if obj == nil {
		return false
	}
	// check all required fields in Schema are present in the object.
	for _, requiredName := range schema.Required {
		if obj[requiredName] == nil {
			return false
		}
	}
	// check all object's fields are in schema and the types match.
	for k, v := range obj {
		if p, ok := schema.Properties[k]; ok {
			if !((*Schema)(&p)).Matches(v) {
				return false
			}
		}
	}
	return true
}

// SchemaDB is our in-memory DB. It is organized around Schemas. Each schema maintains a list of objects that matches
// the schema. We don't build indexes and do linear search. This keeps the searching flexible for now.
type SchemaDB struct {
	Name    string
	Schema  Schema
	Objects []interface{}
}

// Insert inserts an object into the schema's object list.
func (db *SchemaDB) Insert(name string, obj interface{}) error {
	if !db.Schema.Matches(obj) {
		return errors.New("object and schema doesn't match")
	}
	db.Objects = append(db.Objects, obj)
	return nil
}

// MatchFunc checks whether the input criteria and an input object matches.
type MatchFunc func(interface{}, interface{}) bool

// Find finds the specified number of objects that match the input criteria.
func (db *SchemaDB) Find(criteria interface{}, matches MatchFunc, desiredCount int) []interface{} {
	var result []interface{}
	for _, obj := range db.Objects {
		if matches(criteria, obj) {
			result = append(result, obj)
			if len(result) >= desiredCount {
				return result
			}
		}
	}
	return result
}

// DB holds schema name to Schema mapping.
var DB map[string]SchemaDB

func init() {
	DB = make(map[string]SchemaDB)
}
<|endoftext|>


<commit_before>package infermedica

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
)

type Prevalence string

const (
	PrevalenceVeryRare Prevalence = "very_rare"
	PrevalenceRare     Prevalence = "rare"
	PrevalenceModerate Prevalence = "moderate"
	PrevalenceCommon   Prevalence = "common"
)

func (p Prevalence) Ptr() *Prevalence { return &p }
func (p Prevalence) String() string   { return string(p) }

func (p *Prevalence) IsValid() bool {
	_, err := PrevalenceFromString(p.String())
	if err != nil {
		return false
	}
	return true
}

func PrevalenceFromString(x string) (Prevalence, error) {
	switch strings.ToLower(x) {
	case "very_rare":
		return PrevalenceVeryRare, nil
	case "rare":
		return PrevalenceRare, nil
	case "moderate":
		return PrevalenceModerate, nil
	case "common":
		return PrevalenceCommon, nil
	default:
		return "", fmt.Errorf("Unexpected value for Prevalence: %q", x)
	}
}

type Acuteness string

const (
	AcutenessChronic                  Acuteness = "chronic"
	AcutenessChronicWithExacerbations Acuteness = "chronic_with_exacerbations"
	AcutenessAcutePotentiallyChronic  Acuteness = "acute_potentially_chronic"
	AcutenessAcute                    Acuteness = "acute"
)

func (a Acuteness) Ptr() *Acuteness { return &a }
func (a Acuteness) String() string  { return string(a) }

func (a *Acuteness) IsValid() bool {
	_, err := AcutenessFromString(a.String())
	if err != nil {
		return false
	}
	return true
}

func AcutenessFromString(x string) (Acuteness, error) {
	switch strings.ToLower(x) {
	case "chronic":
		return AcutenessChronic, nil
	case "chronic_with_exacerbations":
		return AcutenessChronicWithExacerbations, nil
	case "acute_potentially_chronic":
		return AcutenessAcutePotentiallyChronic, nil
	case "acute":
		return AcutenessAcute, nil
	default:
		return "", fmt.Errorf("Unexpected value for Acuteness: %q", x)
	}
}

type Severity string

const (
	SeverityMild     Severity = "mild"
	SeverityModerate Severity = "moderate"
	SeveritySevere   Severity = "severe"
)

func (s Severity) Ptr() *Severity { return &s }
func (s Severity) String() string { return string(s) }

func (s *Severity) IsValid() bool {
	_, err := SeverityFromString(s.String())
	if err != nil {
		return false
	}
	return true
}

func SeverityFromString(x string) (Severity, error) {
	switch strings.ToLower(x) {
	case "mild":
		return SeverityMild, nil
	case "moderate":
		return SeverityModerate, nil
	case "severe":
		return SeveritySevere, nil
	default:
		return "", fmt.Errorf("Unexpected value for Severity: %q", x)
	}
}

type Condition struct {
	ID         string `json:"id"`
	Name       string `json:"name"`
	CommonName string `json:"common_name"`
}

type ConditionRes struct {
	Condition
	SexFilter   SexFilter       `json:"sex_filter"`
	Categories  []string        `json:"categories"`
	Prevalence  Prevalence      `json:"prevalence"`
	Acuteness   Acuteness       `json:"acuteness"`
	Severity    Severity        `json:"severity"`
	Extras      ConditionExtras `json:"extras"`
	TriageLevel string          `json:"triage_level"`
}

type ConditionExtras struct {
	Hint      string `json:"hint"`
	ICD10Code string `json:"icd10_code"`
}

func (a *App) Conditions() (*[]ConditionRes, error) {
	req, err := a.prepareRequest("GET", "conditions", nil)
	if err != nil {
		return nil, err
	}
	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	r := []ConditionRes{}
	err = json.NewDecoder(res.Body).Decode(&r)
	if err != nil {
		return nil, err
	}
	return &r, nil
}

func (a *App) ConditionByID(id string) (*ConditionRes, error) {
	req, err := a.prepareGETRequest("conditions/" + id)
	if err != nil {
		return nil, err
	}
	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	r := ConditionRes{}
	err = json.NewDecoder(res.Body).Decode(&r)
	if err != nil {
		return nil, err
	}
	return &r, nil
}
<commit_msg>added condtionsIDMap func<commit_after>package infermedica

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
)

type Prevalence string

const (
	PrevalenceVeryRare Prevalence = "very_rare"
	PrevalenceRare     Prevalence = "rare"
	PrevalenceModerate Prevalence = "moderate"
	PrevalenceCommon   Prevalence = "common"
)

func (p Prevalence) Ptr() *Prevalence { return &p }
func (p Prevalence) String() string   { return string(p) }

func (p *Prevalence) IsValid() bool {
	_, err := PrevalenceFromString(p.String())
	if err != nil {
		return false
	}
	return true
}

func PrevalenceFromString(x string) (Prevalence, error) {
	switch strings.ToLower(x) {
	case "very_rare":
		return PrevalenceVeryRare, nil
	case "rare":
		return PrevalenceRare, nil
	case "moderate":
		return PrevalenceModerate, nil
	case "common":
		return PrevalenceCommon, nil
	default:
		return "", fmt.Errorf("Unexpected value for Prevalence: %q", x)
	}
}

type Acuteness string

const (
	AcutenessChronic                  Acuteness = "chronic"
	AcutenessChronicWithExacerbations Acuteness = "chronic_with_exacerbations"
	AcutenessAcutePotentiallyChronic  Acuteness = "acute_potentially_chronic"
	AcutenessAcute                    Acuteness = "acute"
)

func (a Acuteness) Ptr() *Acuteness { return &a }
func (a Acuteness) String() string  { return string(a) }

func (a *Acuteness) IsValid() bool {
	_, err := AcutenessFromString(a.String())
	if err != nil {
		return false
	}
	return true
}

func AcutenessFromString(x string) (Acuteness, error) {
	switch strings.ToLower(x) {
	case "chronic":
		return AcutenessChronic, nil
	case "chronic_with_exacerbations":
		return AcutenessChronicWithExacerbations, nil
	case "acute_potentially_chronic":
		return AcutenessAcutePotentiallyChronic, nil
	case "acute":
		return AcutenessAcute, nil
	default:
		return "", fmt.Errorf("Unexpected value for Acuteness: %q", x)
	}
}

type Severity string

const (
	SeverityMild     Severity = "mild"
	SeverityModerate Severity = "moderate"
	SeveritySevere   Severity = "severe"
)

func (s Severity) Ptr() *Severity { return &s }
func (s Severity) String() string { return string(s) }

func (s *Severity) IsValid() bool {
	_, err := SeverityFromString(s.String())
	if err != nil {
		return false
	}
	return true
}

func SeverityFromString(x string) (Severity, error) {
	switch strings.ToLower(x) {
	case "mild":
		return SeverityMild, nil
	case "moderate":
		return SeverityModerate, nil
	case "severe":
		return SeveritySevere, nil
	default:
		return "", fmt.Errorf("Unexpected value for Severity: %q", x)
	}
}

type Condition struct {
	ID         string `json:"id"`
	Name       string `json:"name"`
	CommonName string `json:"common_name"`
}

type ConditionRes struct {
	Condition
	SexFilter   SexFilter       `json:"sex_filter"`
	Categories  []string        `json:"categories"`
	Prevalence  Prevalence      `json:"prevalence"`
	Acuteness   Acuteness       `json:"acuteness"`
	Severity    Severity        `json:"severity"`
	Extras      ConditionExtras `json:"extras"`
	TriageLevel string          `json:"triage_level"`
}

type ConditionExtras struct {
	Hint      string `json:"hint"`
	ICD10Code string `json:"icd10_code"`
}

func (a *App) Conditions() (*[]ConditionRes, error) {
	req, err := a.prepareRequest("GET", "conditions", nil)
	if err != nil {
		return nil, err
	}
	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	r := []ConditionRes{}
	err = json.NewDecoder(res.Body).Decode(&r)
	if err != nil {
		return nil, err
	}
	return &r, nil
}

func (a *App) ConditionsIDMap() (*map[string]ConditionRes, error) {
	r, err := a.Conditions()
	if err != nil {
		return nil, err
	}
	rmap := make(map[string]ConditionRes)
	for _, sr := range *r {
		rmap[sr.ID] = sr
	}
	return &rmap, nil
}

func (a *App) ConditionByID(id string) (*ConditionRes, error) {
	req, err := a.prepareGETRequest("conditions/" + id)
	if err != nil {
		return nil, err
	}
	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	r := ConditionRes{}
	err = json.NewDecoder(res.Body).Decode(&r)
	if err != nil {
		return nil, err
	}
	return &r, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/spf13/cobra"

	// Used by cgo
	_ "github.com/lxc/lxd/lxd/include"
)

/*
#include "config.h"

#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/fsuid.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <unistd.h>

#include "lxd.h"
#include "file_utils.h"
#include "macro.h"
#include "memory_utils.h"
#include "mount_utils.h"
#include "process_utils.h"
#include "syscall_numbers.h"
#include "syscall_wrappers.h"

#ifndef PIPEFS_MAGIC
#define PIPEFS_MAGIC 0x50495045
#endif

#define FD_PIPE_UIDMAP 3
#define FD_PIPE_GIDMAP 4

#define MAP_SIZE ((ssize_t)4096)

typedef __typeof__(((struct statfs *)NULL)->f_type) fs_type_magic;
static bool is_fs_type(const struct statfs *fs, fs_type_magic magic_val)
{
	return (fs->f_type == (fs_type_magic)magic_val);
}

static bool fhas_fs_type(int fd, fs_type_magic magic_val)
{
	int ret;
	struct statfs sb;

	ret = fstatfs(fd, &sb);
	if (ret < 0)
		return false;

	return is_fs_type(&sb, magic_val);
}

static inline bool drop_groups(void)
{
	return setgroups(0, NULL) == 0;
}

static inline bool switch_resids(uid_t uid, gid_t gid)
{
	if (setresgid(gid, gid, gid))
		return false;

	if (setresuid(uid, uid, uid))
		return false;

	if (setfsgid(-1) != gid)
		return false;

	if (setfsuid(-1) != uid)
		return false;

	return true;
}

static int write_id_mapping(bool is_uid)
{
	__do_close int fd_idmap = -EBADF;
	ssize_t bytes_read, ret;
	char buf[PROC_PID_IDMAP_LEN], idmap[LXC_IDMAPLEN];

	if (is_uid)
		ret = strnprintf(buf, sizeof(buf), "/proc/%d/uid_map", getppid());
	else
		ret = strnprintf(buf, sizeof(buf), "/proc/%d/gid_map", getppid());
	if (ret < 0)
		return -errno;

	fd_idmap = open(buf, O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW);
	if (fd_idmap < 0)
		return -1;

	if (is_uid)
		bytes_read = read_nointr(FD_PIPE_UIDMAP, idmap, sizeof(idmap));
	else
		bytes_read = read_nointr(FD_PIPE_GIDMAP, idmap, sizeof(idmap));
	if (bytes_read < 0 || bytes_read >= sizeof(idmap))
		return -errno;

	ret = write_nointr(fd_idmap, idmap, bytes_read);
	if (ret < 0 || ret != bytes_read)
		return -errno;

	return 0;
}

static int write_id_mappings(void)
{
	int ret;

	ret = write_id_mapping(true);
	if (!ret)
		ret = write_id_mapping(false);
	return ret;
}

__attribute__ ((noinline)) int __forkusernsexec(void)
{
	__do_free_string_list char **argvp = NULL;
	pid_t pid;
	ssize_t ret;
	int fd_socket[2];
	char c;
	char *cur;

	if (geteuid() != 0)
		return log_error(EXIT_FAILURE, "Error: forkexec requires root privileges");

	cur = advance_arg(false);
	if (!cur || (strcmp(cur, "--help") == 0 ||
	     strcmp(cur, "--version") == 0 || strcmp(cur, "-h") == 0))
		return EXIT_SUCCESS;

	if (!fhas_fs_type(FD_PIPE_UIDMAP, PIPEFS_MAGIC))
		return EXIT_FAILURE;

	if (!fhas_fs_type(FD_PIPE_GIDMAP, PIPEFS_MAGIC))
		return EXIT_FAILURE;

	ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, fd_socket);
	if (ret < 0)
		return EXIT_FAILURE;

	pid = fork();
	if (pid < 0)
		return EXIT_FAILURE;

	if (pid == 0) {
		close_prot_errno_disarm(fd_socket[0]);

		ret = read_nointr(fd_socket[1], &c, 1);
		if (ret != 1)
			_exit(EXIT_FAILURE);

		ret = write_id_mappings();
		if (ret < 0)
			_exit(EXIT_FAILURE);

		ret = write_nointr(fd_socket[1], &c, 1);
		if (ret != 1)
			_exit(EXIT_FAILURE);

		_exit(EXIT_SUCCESS);
	}

	close_prot_errno_disarm(fd_socket[1]);

	ret = unshare(CLONE_NEWUSER);
	if (ret) {
		kill(pid, SIGKILL);
		goto out_reap;
	}

	ret = write_nointr(fd_socket[0], &c, 1);
	if (ret == 1)
		ret = read_nointr(fd_socket[0], &c, 1);
	if (ret != 1) {
		kill(pid, SIGKILL);
		goto out_reap;
	}

	if (!drop_groups()) {
		kill(pid, SIGKILL);
		goto out_reap;
	}

	if (!switch_resids(0, 0)) {
		kill(pid, SIGKILL);
		goto out_reap;
	}

	close_prot_errno_disarm(fd_socket[0]);

out_reap:
	ret = wait_for_pid(pid);
	if (ret)
		return EXIT_FAILURE;

	ret = push_vargs(&argvp, cur);
	if (ret < 0)
		return log_error(EXIT_FAILURE, "Failed to add %s to arg array", cur);

	for (cur = NULL; (cur = advance_arg(false)); ) {
		ret = push_vargs(&argvp, cur);
		if (ret < 0)
			return log_error(EXIT_FAILURE, "Failed to add %s to arg array", cur);
	}

	if (!argvp || !*argvp)
		return log_error(EXIT_FAILURE, "No command specified");

	execvp(argvp[0], argvp);
	return EXIT_FAILURE;
}

void forkusernsexec(void)
{
	_exit(__forkusernsexec());
}
*/
import "C"

type cmdForkusernsexec struct {
	global *cmdGlobal
}

func (c *cmdForkusernsexec) Command() *cobra.Command {
	// Main subcommand
	cmd := &cobra.Command{}
	cmd.Use = "forkusernsexec <cmd> <args>"
	cmd.Short = "Run command in user namespace"
	cmd.Long = `Description:
  Run command in user namespace

  This command is used to execute a program in a new user namespace.
`
	cmd.RunE = c.Run
	cmd.Hidden = true

	return cmd
}

func (c *cmdForkusernsexec) Run(cmd *cobra.Command, args []string) error {
	return fmt.Errorf("This command should have been intercepted in cgo")
}
<commit_msg>lxd/main/forkusernsexec: Return error if uid or gid map FDs not supplied<commit_after>package main

import (
	"fmt"

	"github.com/spf13/cobra"

	// Used by cgo
	_ "github.com/lxc/lxd/lxd/include"
)

/*
#include "config.h"

#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/fsuid.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <unistd.h>

#include "lxd.h"
#include "file_utils.h"
#include "macro.h"
#include "memory_utils.h"
#include "mount_utils.h"
#include "process_utils.h"
#include "syscall_numbers.h"
#include "syscall_wrappers.h"

#ifndef PIPEFS_MAGIC
#define PIPEFS_MAGIC 0x50495045
#endif

#define FD_PIPE_UIDMAP 3
#define FD_PIPE_GIDMAP 4

#define MAP_SIZE ((ssize_t)4096)

typedef __typeof__(((struct statfs *)NULL)->f_type) fs_type_magic;
static bool is_fs_type(const struct statfs *fs, fs_type_magic magic_val)
{
	return (fs->f_type == (fs_type_magic)magic_val);
}

static bool fhas_fs_type(int fd, fs_type_magic magic_val)
{
	int ret;
	struct statfs sb;

	ret = fstatfs(fd, &sb);
	if (ret < 0)
		return false;

	return is_fs_type(&sb, magic_val);
}

static inline bool drop_groups(void)
{
	return setgroups(0, NULL) == 0;
}

static inline bool switch_resids(uid_t uid, gid_t gid)
{
	if (setresgid(gid, gid, gid))
		return false;

	if (setresuid(uid, uid, uid))
		return false;

	if (setfsgid(-1) != gid)
		return false;

	if (setfsuid(-1) != uid)
		return false;

	return true;
}

static int write_id_mapping(bool is_uid)
{
	__do_close int fd_idmap = -EBADF;
	ssize_t bytes_read, ret;
	char buf[PROC_PID_IDMAP_LEN], idmap[LXC_IDMAPLEN];

	if (is_uid)
		ret = strnprintf(buf, sizeof(buf), "/proc/%d/uid_map", getppid());
	else
		ret = strnprintf(buf, sizeof(buf), "/proc/%d/gid_map", getppid());
	if (ret < 0)
		return -errno;

	fd_idmap = open(buf, O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW);
	if (fd_idmap < 0)
		return -1;

	if (is_uid)
		bytes_read = read_nointr(FD_PIPE_UIDMAP, idmap, sizeof(idmap));
	else
		bytes_read = read_nointr(FD_PIPE_GIDMAP, idmap, sizeof(idmap));
	if (bytes_read < 0 || bytes_read >= sizeof(idmap))
		return -errno;

	ret = write_nointr(fd_idmap, idmap, bytes_read);
	if (ret < 0 || ret != bytes_read)
		return -errno;

	return 0;
}

static int write_id_mappings(void)
{
	int ret;

	ret = write_id_mapping(true);
	if (!ret)
		ret = write_id_mapping(false);
	return ret;
}

__attribute__ ((noinline)) int __forkusernsexec(void)
{
	__do_free_string_list char **argvp = NULL;
	pid_t pid;
	ssize_t ret;
	int fd_socket[2];
	char c;
	char *cur;

	if (geteuid() != 0)
		return log_error(EXIT_FAILURE, "Error: forkexec requires root privileges");

	cur = advance_arg(false);
	if (!cur || (strcmp(cur, "--help") == 0 ||
	     strcmp(cur, "--version") == 0 || strcmp(cur, "-h") == 0))
		return EXIT_SUCCESS;

	if (!fhas_fs_type(FD_PIPE_UIDMAP, PIPEFS_MAGIC))
		return log_error(EXIT_FAILURE, "Error: Missing UID map FD");

	if (!fhas_fs_type(FD_PIPE_GIDMAP, PIPEFS_MAGIC))
		return log_error(EXIT_FAILURE, "Error: Missing GID map FD");

	ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, fd_socket);
	if (ret < 0)
		return EXIT_FAILURE;

	pid = fork();
	if (pid < 0)
		return EXIT_FAILURE;

	if (pid == 0) {
		close_prot_errno_disarm(fd_socket[0]);

		ret = read_nointr(fd_socket[1], &c, 1);
		if (ret != 1)
			_exit(EXIT_FAILURE);

		ret = write_id_mappings();
		if (ret < 0)
			_exit(EXIT_FAILURE);

		ret = write_nointr(fd_socket[1], &c, 1);
		if (ret != 1)
			_exit(EXIT_FAILURE);

		_exit(EXIT_SUCCESS);
	}

	close_prot_errno_disarm(fd_socket[1]);

	ret = unshare(CLONE_NEWUSER);
	if (ret) {
		kill(pid, SIGKILL);
		goto out_reap;
	}

	ret = write_nointr(fd_socket[0], &c, 1);
	if (ret == 1)
		ret = read_nointr(fd_socket[0], &c, 1);
	if (ret != 1) {
		kill(pid, SIGKILL);
		goto out_reap;
	}

	if (!drop_groups()) {
		kill(pid, SIGKILL);
		goto out_reap;
	}

	if (!switch_resids(0, 0)) {
		kill(pid, SIGKILL);
		goto out_reap;
	}

	close_prot_errno_disarm(fd_socket[0]);

out_reap:
	ret = wait_for_pid(pid);
	if (ret)
		return EXIT_FAILURE;

	ret = push_vargs(&argvp, cur);
	if (ret < 0)
		return log_error(EXIT_FAILURE, "Failed to add %s to arg array", cur);

	for (cur = NULL; (cur = advance_arg(false)); ) {
		ret = push_vargs(&argvp, cur);
		if (ret < 0)
			return log_error(EXIT_FAILURE, "Failed to add %s to arg array", cur);
	}

	if (!argvp || !*argvp)
		return log_error(EXIT_FAILURE, "No command specified");

	execvp(argvp[0], argvp);
	return EXIT_FAILURE;
}

void forkusernsexec(void)
{
	_exit(__forkusernsexec());
}
*/
import "C"

type cmdForkusernsexec struct {
	global *cmdGlobal
}

func (c *cmdForkusernsexec) Command() *cobra.Command {
	// Main subcommand
	cmd := &cobra.Command{}
	cmd.Use = "forkusernsexec <cmd> <args>"
	cmd.Short = "Run command in user namespace"
	cmd.Long = `Description:
  Run command in user namespace

  This command is used to execute a program in a new user namespace.
`
	cmd.RunE = c.Run
	cmd.Hidden = true

	return cmd
}

func (c *cmdForkusernsexec) Run(cmd *cobra.Command, args []string) error {
	return fmt.Errorf("This command should have been intercepted in cgo")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/lxc/lxd/lxd/cluster/request"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/revert"
	"github.com/lxc/lxd/lxd/state"
	storagePools "github.com/lxc/lxd/lxd/storage"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
)

// storagePoolDBCreate creates a storage pool DB entry and returns the created Pool ID.
func storagePoolDBCreate(s *state.State, poolName, poolDescription string, driver string, config map[string]string) (int64, error) {
	// Check that the storage pool does not already exist.
	_, err := s.Cluster.GetStoragePoolID(poolName)
	if err == nil {
		return -1, fmt.Errorf("The storage pool already exists: %w", db.ErrAlreadyDefined)
	}

	// Make sure that we don't pass a nil to the next function.
	if config == nil {
		config = map[string]string{}
	}
	err = storagePoolValidate(s, poolName, driver, config)
	if err != nil {
		return -1, err
	}

	// Fill in the defaults.
	err = storagePoolFillDefault(poolName, driver, config)
	if err != nil {
		return -1, err
	}

	// Create the database entry for the storage pool.
	id, err := dbStoragePoolCreateAndUpdateCache(s, poolName, poolDescription, driver, config)
	if err != nil {
		return -1, fmt.Errorf("Error inserting %s into database: %w", poolName, err)
	}

	return id, nil
}

func storagePoolValidate(s *state.State, poolName string, driverName string, config map[string]string) error {
	poolType, err := storagePools.LoadByType(s, driverName)
	if err != nil {
		return err
	}

	// Check if the storage pool name is valid.
	err = poolType.ValidateName(poolName)
	if err != nil {
		return err
	}

	// Validate the requested storage pool configuration.
	err = storagePoolValidateConfig(poolName, driverName, config, nil)
	if err != nil {
		return err
	}

	return nil
}

func storagePoolCreateGlobal(state *state.State, req api.StoragePoolsPost, clientType request.ClientType) error {
	// Create the database entry.
	id, err := storagePoolDBCreate(state, req.Name, req.Description, req.Driver, req.Config)
	if err != nil {
		return err
	}

	// Define a function which reverts everything.  Defer this function
	// so that it doesn't need to be explicitly called in every failing
	// return path. Track whether or not we want to undo the changes
	// using a closure.
	tryUndo := true
	defer func() {
		if !tryUndo {
			return
		}

		dbStoragePoolDeleteAndUpdateCache(state, req.Name)
	}()

	_, err = storagePoolCreateLocal(state, id, req, clientType)
	if err != nil {
		return err
	}

	tryUndo = false
	return nil
}

// This performs local pool setup and updates DB record if config was changed during pool setup.
// Returns resulting config.
func storagePoolCreateLocal(state *state.State, poolID int64, req api.StoragePoolsPost, clientType request.ClientType) (map[string]string, error) {
	// Setup revert.
	revert := revert.New()
	defer revert.Fail()

	// Make a copy of the req for later diff.
	var updatedReq api.StoragePoolsPost
	shared.DeepCopy(&req, &updatedReq)

	// Make sure that we don't pass a nil to the next function.
	if updatedReq.Config == nil {
		updatedReq.Config = map[string]string{}
	}

	// Fill in the node specific defaults.
	err := storagePoolFillDefault(updatedReq.Name, updatedReq.Driver, updatedReq.Config)
	if err != nil {
		return nil, err
	}

	configDiff, _ := storagePools.ConfigDiff(req.Config, updatedReq.Config)
	if len(configDiff) > 0 {
		// Update the database entry for the storage pool.
		err = state.Cluster.UpdateStoragePool(req.Name, req.Description, updatedReq.Config)
		if err != nil {
			return nil, fmt.Errorf("Error updating storage pool config after local fill defaults for %q: %w", req.Name, err)
		}
	}

	// Load pool record.
	pool, err := storagePools.LoadByName(state, updatedReq.Name)
	if err != nil {
		return nil, err
	}

	if pool.LocalStatus() == api.NetworkStatusCreated {
		logger.Debug("Skipping local storage pool create as already created", logger.Ctx{"pool": pool.Name()})

		return pool.Driver().Config(), nil
	}

	// Create the pool.
	err = pool.Create(clientType, nil)
	if err != nil {
		return nil, err
	}

	revert.Add(func() { pool.Delete(clientType, nil) })

	// Mount the pool.
	_, err = pool.Mount()
	if err != nil {
		return nil, err
	}

	// In case the storage pool config was changed during the pool creation, we need to update the database to
	// reflect this change. This can e.g. happen, when we create a loop file image. This means we append ".img"
	// to the path the user gave us and update the config in the storage callback. So diff the config here to
	// see if something like this has happened.
	configDiff, _ = storagePools.ConfigDiff(updatedReq.Config, pool.Driver().Config())
	if len(configDiff) > 0 {
		// Update the database entry for the storage pool.
		err = state.Cluster.UpdateStoragePool(req.Name, req.Description, pool.Driver().Config())
		if err != nil {
			return nil, fmt.Errorf("Error updating storage pool config after local create for %q: %w", req.Name, err)
		}
	}

	// Set storage pool node to storagePoolCreated.
	err = state.Cluster.Transaction(func(tx *db.ClusterTx) error {
		return tx.StoragePoolNodeCreated(poolID)
	})
	if err != nil {
		return nil, err
	}
	logger.Debug("Marked storage pool local status as created", logger.Ctx{"pool": req.Name})

	revert.Success()
	return pool.Driver().Config(), nil
}

// Helper around the low-level DB API, which also updates the driver names cache.
func dbStoragePoolCreateAndUpdateCache(s *state.State, poolName string, poolDescription string, poolDriver string, poolConfig map[string]string) (int64, error) {
	id, err := s.Cluster.CreateStoragePool(poolName, poolDescription, poolDriver, poolConfig)
	if err != nil {
		return id, err
	}

	// Update the storage drivers cache in api_1.0.go.
	storagePoolDriversCacheUpdate(s)

	return id, nil
}

// Helper around the low-level DB API, which also updates the driver names
// cache.
func dbStoragePoolDeleteAndUpdateCache(s *state.State, poolName string) error {
	_, err := s.Cluster.RemoveStoragePool(poolName)
	if err != nil {
		return err
	}

	// Update the storage drivers cache in api_1.0.go.
	storagePoolDriversCacheUpdate(s)

	return err
}
<commit_msg>lxd/storage/pools/utils: Call poolType.Validate in storagePoolValidate<commit_after>package main

import (
	"fmt"

	"github.com/lxc/lxd/lxd/cluster/request"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/revert"
	"github.com/lxc/lxd/lxd/state"
	storagePools "github.com/lxc/lxd/lxd/storage"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
)

// storagePoolDBCreate creates a storage pool DB entry and returns the created Pool ID.
func storagePoolDBCreate(s *state.State, poolName, poolDescription string, driver string, config map[string]string) (int64, error) {
	// Check that the storage pool does not already exist.
	_, err := s.Cluster.GetStoragePoolID(poolName)
	if err == nil {
		return -1, fmt.Errorf("The storage pool already exists: %w", db.ErrAlreadyDefined)
	}

	// Make sure that we don't pass a nil to the next function.
	if config == nil {
		config = map[string]string{}
	}
	err = storagePoolValidate(s, poolName, driver, config)
	if err != nil {
		return -1, err
	}

	// Fill in the defaults.
	err = storagePoolFillDefault(poolName, driver, config)
	if err != nil {
		return -1, err
	}

	// Create the database entry for the storage pool.
	id, err := dbStoragePoolCreateAndUpdateCache(s, poolName, poolDescription, driver, config)
	if err != nil {
		return -1, fmt.Errorf("Error inserting %s into database: %w", poolName, err)
	}

	return id, nil
}

func storagePoolValidate(s *state.State, poolName string, driverName string, config map[string]string) error {
	poolType, err := storagePools.LoadByType(s, driverName)
	if err != nil {
		return err
	}

	// Check if the storage pool name is valid.
	err = poolType.ValidateName(poolName)
	if err != nil {
		return err
	}

	// Validate the requested storage pool configuration.
	err = poolType.Validate(config)
	if err != nil {
		return err
	}

	return nil
}

func storagePoolCreateGlobal(state *state.State, req api.StoragePoolsPost, clientType request.ClientType) error {
	// Create the database entry.
	id, err := storagePoolDBCreate(state, req.Name, req.Description, req.Driver, req.Config)
	if err != nil {
		return err
	}

	// Define a function which reverts everything.  Defer this function
	// so that it doesn't need to be explicitly called in every failing
	// return path. Track whether or not we want to undo the changes
	// using a closure.
	tryUndo := true
	defer func() {
		if !tryUndo {
			return
		}

		dbStoragePoolDeleteAndUpdateCache(state, req.Name)
	}()

	_, err = storagePoolCreateLocal(state, id, req, clientType)
	if err != nil {
		return err
	}

	tryUndo = false
	return nil
}

// This performs local pool setup and updates DB record if config was changed during pool setup.
// Returns resulting config.
func storagePoolCreateLocal(state *state.State, poolID int64, req api.StoragePoolsPost, clientType request.ClientType) (map[string]string, error) {
	// Setup revert.
	revert := revert.New()
	defer revert.Fail()

	// Make a copy of the req for later diff.
	var updatedReq api.StoragePoolsPost
	shared.DeepCopy(&req, &updatedReq)

	// Make sure that we don't pass a nil to the next function.
	if updatedReq.Config == nil {
		updatedReq.Config = map[string]string{}
	}

	// Fill in the node specific defaults.
	err := storagePoolFillDefault(updatedReq.Name, updatedReq.Driver, updatedReq.Config)
	if err != nil {
		return nil, err
	}

	configDiff, _ := storagePools.ConfigDiff(req.Config, updatedReq.Config)
	if len(configDiff) > 0 {
		// Update the database entry for the storage pool.
		err = state.Cluster.UpdateStoragePool(req.Name, req.Description, updatedReq.Config)
		if err != nil {
			return nil, fmt.Errorf("Error updating storage pool config after local fill defaults for %q: %w", req.Name, err)
		}
	}

	// Load pool record.
	pool, err := storagePools.LoadByName(state, updatedReq.Name)
	if err != nil {
		return nil, err
	}

	if pool.LocalStatus() == api.NetworkStatusCreated {
		logger.Debug("Skipping local storage pool create as already created", logger.Ctx{"pool": pool.Name()})

		return pool.Driver().Config(), nil
	}

	// Create the pool.
	err = pool.Create(clientType, nil)
	if err != nil {
		return nil, err
	}

	revert.Add(func() { pool.Delete(clientType, nil) })

	// Mount the pool.
	_, err = pool.Mount()
	if err != nil {
		return nil, err
	}

	// In case the storage pool config was changed during the pool creation, we need to update the database to
	// reflect this change. This can e.g. happen, when we create a loop file image. This means we append ".img"
	// to the path the user gave us and update the config in the storage callback. So diff the config here to
	// see if something like this has happened.
	configDiff, _ = storagePools.ConfigDiff(updatedReq.Config, pool.Driver().Config())
	if len(configDiff) > 0 {
		// Update the database entry for the storage pool.
		err = state.Cluster.UpdateStoragePool(req.Name, req.Description, pool.Driver().Config())
		if err != nil {
			return nil, fmt.Errorf("Error updating storage pool config after local create for %q: %w", req.Name, err)
		}
	}

	// Set storage pool node to storagePoolCreated.
	err = state.Cluster.Transaction(func(tx *db.ClusterTx) error {
		return tx.StoragePoolNodeCreated(poolID)
	})
	if err != nil {
		return nil, err
	}
	logger.Debug("Marked storage pool local status as created", logger.Ctx{"pool": req.Name})

	revert.Success()
	return pool.Driver().Config(), nil
}

// Helper around the low-level DB API, which also updates the driver names cache.
func dbStoragePoolCreateAndUpdateCache(s *state.State, poolName string, poolDescription string, poolDriver string, poolConfig map[string]string) (int64, error) {
	id, err := s.Cluster.CreateStoragePool(poolName, poolDescription, poolDriver, poolConfig)
	if err != nil {
		return id, err
	}

	// Update the storage drivers cache in api_1.0.go.
	storagePoolDriversCacheUpdate(s)

	return id, nil
}

// Helper around the low-level DB API, which also updates the driver names
// cache.
func dbStoragePoolDeleteAndUpdateCache(s *state.State, poolName string) error {
	_, err := s.Cluster.RemoveStoragePool(poolName)
	if err != nil {
		return err
	}

	// Update the storage drivers cache in api_1.0.go.
	storagePoolDriversCacheUpdate(s)

	return err
}
<|endoftext|>