<commit_before>package csi

import (
	"fmt"

	e2e "github.com/hashicorp/nomad/e2e/e2eutil"
	"github.com/hashicorp/nomad/e2e/framework"
	"github.com/hashicorp/nomad/helper/uuid"
)

// CSIControllerPluginEBSTest exercises the AWS EBS plugin, which is an
// example of a plugin that supports most of the CSI Controller RPCs.
type CSIControllerPluginEBSTest struct {
	framework.TC
	uuid         string
	testJobIDs   []string
	volumeIDs    []string
	pluginJobIDs []string
}

const ebsPluginID = "aws-ebs0"

// BeforeAll waits for the cluster to be ready, deploys the CSI plugins, and
// creates two EBS volumes for use in the test.
func (tc *CSIControllerPluginEBSTest) BeforeAll(f *framework.F) {
	e2e.WaitForLeader(f.T(), tc.Nomad())
	e2e.WaitForNodesReady(f.T(), tc.Nomad(), 2)

	tc.uuid = uuid.Generate()[0:8]

	// deploy the controller plugin job
	controllerJobID := "aws-ebs-plugin-controller-" + tc.uuid
	f.NoError(e2e.Register(controllerJobID, "csi/input/plugin-aws-ebs-controller.nomad"))
	tc.pluginJobIDs = append(tc.pluginJobIDs, controllerJobID)
	expected := []string{"running", "running"}
	f.NoError(
		e2e.WaitForAllocStatusExpected(controllerJobID, ns, expected),
		"job should be running")

	// deploy the node plugins job
	nodesJobID := "aws-ebs-plugin-nodes-" + tc.uuid
	f.NoError(e2e.Register(nodesJobID, "csi/input/plugin-aws-ebs-nodes.nomad"))
	tc.pluginJobIDs = append(tc.pluginJobIDs, nodesJobID)

	f.NoError(e2e.WaitForAllocStatusComparison(
		func() ([]string, error) { return e2e.AllocStatuses(nodesJobID, ns) },
		func(got []string) bool {
			for _, status := range got {
				if status != "running" {
					return false
				}
			}
			return true
		}, nil,
	))

	f.NoError(waitForPluginStatusControllerCount(ebsPluginID, 2, pluginWait),
		"aws-ebs0 controller plugins did not become healthy")
	f.NoError(waitForPluginStatusMinNodeCount(ebsPluginID, 2, pluginWait),
		"aws-ebs0 node plugins did not become healthy")

	// ideally we'd wait until after we check `nomad volume status -verbose`
	// to verify these volumes are ready, but the plugin doesn't support the
	// CSI ListVolumes RPC
	volID := "ebs-vol[0]"
	err := volumeRegister(volID, "csi/input/ebs-volume0.hcl", "create")
	requireNoErrorElseDump(f, err, "could not create volume", tc.pluginJobIDs)
	tc.volumeIDs = append(tc.volumeIDs, volID)

	volID = "ebs-vol[1]"
	err = volumeRegister(volID, "csi/input/ebs-volume1.hcl", "create")
	requireNoErrorElseDump(f, err, "could not create volume", tc.pluginJobIDs)
	tc.volumeIDs = append(tc.volumeIDs, volID)
}

// AfterAll cleans up the volumes and plugin jobs created by the test.
func (tc *CSIControllerPluginEBSTest) AfterAll(f *framework.F) {
	for _, volID := range tc.volumeIDs {
		err := waitForVolumeClaimRelease(volID, reapWait)
		f.Assert().NoError(err, "volume claims were not released")

		out, err := e2e.Command("nomad", "volume", "delete", volID)
		assertNoErrorElseDump(f, err,
			fmt.Sprintf("could not delete volume:\n%v", out), tc.pluginJobIDs)
	}

	// Deregister all plugin jobs in test
	for _, id := range tc.pluginJobIDs {
		out, err := e2e.Command("nomad", "job", "stop", "-purge", id)
		f.Assert().NoError(err, out)
	}
	tc.pluginJobIDs = []string{}

	// Garbage collect
	out, err := e2e.Command("nomad", "system", "gc")
	f.Assert().NoError(err, out)

}

// TestVolumeClaim exercises the volume publish/unpublish workflows for the
// EBS plugin.
func (tc *CSIControllerPluginEBSTest) TestVolumeClaim(f *framework.F) {
	nomadClient := tc.Nomad()

	// deploy a job that writes to the volume
	writeJobID := "write-ebs-" + tc.uuid
	f.NoError(e2e.Register(writeJobID, "csi/input/use-ebs-volume.nomad"))
	f.NoError(
		e2e.WaitForAllocStatusExpected(writeJobID, ns, []string{"running"}),
		"job should be running")

	allocs, err := e2e.AllocsForJob(writeJobID, ns)
	f.NoError(err, "could not get allocs for write job")
	f.Len(allocs, 1, "could not get allocs for write job")
	writeAllocID := allocs[0]["ID"]

	// read data from volume and assert the writer wrote a file to it
	expectedPath := "/task/test/" + writeAllocID
	_, err = readFile(nomadClient, writeAllocID, expectedPath)
	f.NoError(err)

	// Shutdown (and purge) the writer so we can run a reader.
	// we could mount the EBS volume with multi-attach, but we
	// want this test to exercise the unpublish workflow.
	_, err = e2e.Command("nomad", "job", "stop", "-purge", writeJobID)
	f.NoError(err)

	// wait for the volume unpublish workflow to complete
	for _, volID := range tc.volumeIDs {
		err := waitForVolumeClaimRelease(volID, reapWait)
		f.NoError(err, "volume claims were not released")
	}

	// deploy a job so we can read from the volume
	readJobID := "read-ebs-" + tc.uuid
	tc.testJobIDs = append(tc.testJobIDs, readJobID) // ensure failed tests clean up
	f.NoError(e2e.Register(readJobID, "csi/input/use-ebs-volume.nomad"))
	f.NoError(
		e2e.WaitForAllocStatusExpected(readJobID, ns, []string{"running"}),
		"job should be running")

	allocs, err = e2e.AllocsForJob(readJobID, ns)
	f.NoError(err, "could not get allocs for read job")
	f.Len(allocs, 1, "could not get allocs for read job")
	readAllocID := allocs[0]["ID"]

	// read data from volume and assert we can read the file the writer wrote
	expectedPath = "/task/test/" + readAllocID
	_, err = readFile(nomadClient, readAllocID, expectedPath)
	f.NoError(err)
}

// TestSnapshot exercises the snapshot commands.
func (tc *CSIControllerPluginEBSTest) TestSnapshot(f *framework.F) {

	out, err := e2e.Command("nomad", "volume", "snapshot", "create",
		tc.volumeIDs[0], "snap-"+tc.uuid)
	requireNoErrorElseDump(f, err, "could not create volume snapshot", tc.pluginJobIDs)

	snaps, err := e2e.ParseColumns(out)

	defer func() {
		_, err := e2e.Command("nomad", "volume", "snapshot", "delete",
			ebsPluginID, snaps[0]["Snapshot ID"])
		requireNoErrorElseDump(f, err, "could not delete volume snapshot", tc.pluginJobIDs)
	}()

	f.NoError(err, fmt.Sprintf("could not parse output:\n%v", out))
	f.Len(snaps, 1, fmt.Sprintf("could not parse output:\n%v", out))

	out, err = e2e.Command("nomad", "volume", "snapshot", "list")
	requireNoErrorElseDump(f, err, "could not list volume snapshots", tc.pluginJobIDs)
	f.Contains(out, snaps[0]["ID"],
		fmt.Sprintf("volume snapshot list did not include expected snapshot:\n%v", out))
}
<commit_msg>E2E/CSI: ensure jobs are stopped before checking claims are released<commit_after>package csi

import (
	"fmt"

	e2e "github.com/hashicorp/nomad/e2e/e2eutil"
	"github.com/hashicorp/nomad/e2e/framework"
	"github.com/hashicorp/nomad/helper/uuid"
)

// CSIControllerPluginEBSTest exercises the AWS EBS plugin, which is an
// example of a plugin that supports most of the CSI Controller RPCs.
type CSIControllerPluginEBSTest struct {
	framework.TC
	uuid         string
	testJobIDs   []string
	volumeIDs    []string
	pluginJobIDs []string
}

const ebsPluginID = "aws-ebs0"

// BeforeAll waits for the cluster to be ready, deploys the CSI plugins, and
// creates two EBS volumes for use in the test.
func (tc *CSIControllerPluginEBSTest) BeforeAll(f *framework.F) {
	e2e.WaitForLeader(f.T(), tc.Nomad())
	e2e.WaitForNodesReady(f.T(), tc.Nomad(), 2)

	tc.uuid = uuid.Generate()[0:8]

	// deploy the controller plugin job
	controllerJobID := "aws-ebs-plugin-controller-" + tc.uuid
	f.NoError(e2e.Register(controllerJobID, "csi/input/plugin-aws-ebs-controller.nomad"))
	tc.pluginJobIDs = append(tc.pluginJobIDs, controllerJobID)
	expected := []string{"running", "running"}
	f.NoError(
		e2e.WaitForAllocStatusExpected(controllerJobID, ns, expected),
		"job should be running")

	// deploy the node plugins job
	nodesJobID := "aws-ebs-plugin-nodes-" + tc.uuid
	f.NoError(e2e.Register(nodesJobID, "csi/input/plugin-aws-ebs-nodes.nomad"))
	tc.pluginJobIDs = append(tc.pluginJobIDs, nodesJobID)

	f.NoError(e2e.WaitForAllocStatusComparison(
		func() ([]string, error) { return e2e.AllocStatuses(nodesJobID, ns) },
		func(got []string) bool {
			for _, status := range got {
				if status != "running" {
					return false
				}
			}
			return true
		}, nil,
	))

	f.NoError(waitForPluginStatusControllerCount(ebsPluginID, 2, pluginWait),
		"aws-ebs0 controller plugins did not become healthy")
	f.NoError(waitForPluginStatusMinNodeCount(ebsPluginID, 2, pluginWait),
		"aws-ebs0 node plugins did not become healthy")

	// ideally we'd wait until after we check `nomad volume status -verbose`
	// to verify these volumes are ready, but the plugin doesn't support the
	// CSI ListVolumes RPC
	volID := "ebs-vol[0]"
	err := volumeRegister(volID, "csi/input/ebs-volume0.hcl", "create")
	requireNoErrorElseDump(f, err, "could not create volume", tc.pluginJobIDs)
	tc.volumeIDs = append(tc.volumeIDs, volID)

	volID = "ebs-vol[1]"
	err = volumeRegister(volID, "csi/input/ebs-volume1.hcl", "create")
	requireNoErrorElseDump(f, err, "could not create volume", tc.pluginJobIDs)
	tc.volumeIDs = append(tc.volumeIDs, volID)
}

// AfterAll cleans up the volumes and plugin jobs created by the test.
func (tc *CSIControllerPluginEBSTest) AfterAll(f *framework.F) {

	// Stop all jobs in test
	for _, id := range tc.testJobIDs {
		out, err := e2e.Command("nomad", "job", "stop", "-purge", id)
		f.Assert().NoError(err, out)
	}
	tc.testJobIDs = []string{}

	for _, volID := range tc.volumeIDs {
		err := waitForVolumeClaimRelease(volID, reapWait)
		f.Assert().NoError(err, "volume claims were not released")

		out, err := e2e.Command("nomad", "volume", "delete", volID)
		assertNoErrorElseDump(f, err,
			fmt.Sprintf("could not delete volume:\n%v", out), tc.pluginJobIDs)
	}

	// Deregister all plugin jobs in test
	for _, id := range tc.pluginJobIDs {
		out, err := e2e.Command("nomad", "job", "stop", "-purge", id)
		f.Assert().NoError(err, out)
	}
	tc.pluginJobIDs = []string{}

	// Garbage collect
	out, err := e2e.Command("nomad", "system", "gc")
	f.Assert().NoError(err, out)

}

// TestVolumeClaim exercises the volume publish/unpublish workflows for the
// EBS plugin.
func (tc *CSIControllerPluginEBSTest) TestVolumeClaim(f *framework.F) {
	nomadClient := tc.Nomad()

	// deploy a job that writes to the volume
	writeJobID := "write-ebs-" + tc.uuid
	f.NoError(e2e.Register(writeJobID, "csi/input/use-ebs-volume.nomad"))
	f.NoError(
		e2e.WaitForAllocStatusExpected(writeJobID, ns, []string{"running"}),
		"job should be running")

	allocs, err := e2e.AllocsForJob(writeJobID, ns)
	f.NoError(err, "could not get allocs for write job")
	f.Len(allocs, 1, "could not get allocs for write job")
	writeAllocID := allocs[0]["ID"]

	// read data from volume and assert the writer wrote a file to it
	expectedPath := "/task/test/" + writeAllocID
	_, err = readFile(nomadClient, writeAllocID, expectedPath)
	f.NoError(err)

	// Shutdown (and purge) the writer so we can run a reader.
	// we could mount the EBS volume with multi-attach, but we
	// want this test to exercise the unpublish workflow.
	_, err = e2e.Command("nomad", "job", "stop", "-purge", writeJobID)
	f.NoError(err)

	// wait for the volume unpublish workflow to complete
	for _, volID := range tc.volumeIDs {
		err := waitForVolumeClaimRelease(volID, reapWait)
		f.NoError(err, "volume claims were not released")
	}

	// deploy a job so we can read from the volume
	readJobID := "read-ebs-" + tc.uuid
	tc.testJobIDs = append(tc.testJobIDs, readJobID) // ensure failed tests clean up
	f.NoError(e2e.Register(readJobID, "csi/input/use-ebs-volume.nomad"))
	f.NoError(
		e2e.WaitForAllocStatusExpected(readJobID, ns, []string{"running"}),
		"job should be running")

	allocs, err = e2e.AllocsForJob(readJobID, ns)
	f.NoError(err, "could not get allocs for read job")
	f.Len(allocs, 1, "could not get allocs for read job")
	readAllocID := allocs[0]["ID"]

	// read data from volume and assert we can read the file the writer wrote
	expectedPath = "/task/test/" + readAllocID
	_, err = readFile(nomadClient, readAllocID, expectedPath)
	f.NoError(err)
}

// TestSnapshot exercises the snapshot commands.
func (tc *CSIControllerPluginEBSTest) TestSnapshot(f *framework.F) {

	out, err := e2e.Command("nomad", "volume", "snapshot", "create",
		tc.volumeIDs[0], "snap-"+tc.uuid)
	requireNoErrorElseDump(f, err, "could not create volume snapshot", tc.pluginJobIDs)

	snaps, err := e2e.ParseColumns(out)

	defer func() {
		_, err := e2e.Command("nomad", "volume", "snapshot", "delete",
			ebsPluginID, snaps[0]["Snapshot ID"])
		requireNoErrorElseDump(f, err, "could not delete volume snapshot", tc.pluginJobIDs)
	}()

	f.NoError(err, fmt.Sprintf("could not parse output:\n%v", out))
	f.Len(snaps, 1, fmt.Sprintf("could not parse output:\n%v", out))

	out, err = e2e.Command("nomad", "volume", "snapshot", "list")
	requireNoErrorElseDump(f, err, "could not list volume snapshots", tc.pluginJobIDs)
	f.Contains(out, snaps[0]["ID"],
		fmt.Sprintf("volume snapshot list did not include expected snapshot:\n%v", out))
}
<|endoftext|>


<commit_before>package ecs

import "github.com/jiangshengwu/aliyun-sdk-for-go/util"

type VSwitchService interface {
	/**
	 * ZoneId(required): 可用区 Id
	 * CidrBlock(required): 指定VSwitch的网段
	 * VpcId(required): 指定VSwitch所在的 VPC
	 * VSwitchName(optional): VSwitch名称，不填则为空，默认值为空，[2, 128] 英文或中文字符，必须以大小字母或中文开头，可包含数字，”_”或”-”，这个值会展示在控制台。不能以 http:// 和 https:// 开头
	 * Description(optional): VSwitch 描述，不填则为空，默认值为空，[2, 256] 英文或中文字符，不能以 http:// 和 https:// 开头
	 * ClientToken(optional): 用于保证请求的幂等性。由客户端生成该参数值，要保证在不同请求间唯一，最大不值过 64 个 ASCII 字符
	 */
	CreateVSwitch(param map[string]string) (CreateVSwitchResponse, error)

	/**
	 * VSwitchId(required): 需要删除的 VSwitch 的 Id
	 */
	DeleteVSwitch(param map[string]string) (DeleteVSwitchResponse, error)

	/**
	 * VpcId(required): VpcId
	 * VSwitchId(optional): 需要查询的 VSwitch 的 Id
	 * ZoneId(optional): 可用区 Id
	 * PageNumber(optional):
	 * PageSize(optional):
	 */
	DescribeVSwitches(param map[string]string) (DescribeVSwitchesResponse, error)

	/**
	 * VSwitchId(required)
	 * VSwitchName(optional)
	 * Description(optional)
	 */
	ModifyVSwitchAttribute(param map[string]string) (ModifyVSwitchAttributeResponse, error)
}

type VSwitchOperator struct {
	Common *CommonParam
}

type CreateVSwitchResponse struct {
	util.ErrorResponse
	VSwitchId string `json:"VSwitchId"`
}

type DeleteVSwitchResponse struct {
	util.ErrorResponse
}

type DescribeVSwitchesResponse struct {
	util.ErrorResponse
	util.PageResponse
	VSwitches VSwitchTypes `json:"VSwitches"`
}

type ModifyVSwitchAttributeResponse struct {
	util.ErrorResponse
}

type VSwitchTypes struct {
	VSwitchType VSwitchType `json:"VSwitche"`
}

type VSwitchType struct {
	VSwitchId               string `json:"VSwitchId"`
	VpcId                   string `json:"VpcId"`
	Status                  string `json:"Status"`
	CidrBlock               string `json:"CidrBlock"`
	ZoneId                  string `json:"ZoneId"`
	AvailableIpAddressCount int    `json:"AvailableIpAddressCount"`
	Description             string `json:"Description"`
	VSwitchName             string `json:"VSwitchName"`
	CreationTime            string `json:"CreationTime"`
}

func (op *VSwitchOperator) CreateVSwitch(params map[string]string) (CreateVSwitchResponse, error) {
	var resp CreateVSwitchResponse
	err := op.Common.Request(GetFuncName(1), params, &resp)
	return resp, err
}

func (op *VSwitchOperator) DeleteVSwitch(params map[string]string) (DeleteVSwitchResponse, error) {
	var resp DeleteVSwitchResponse
	err := op.Common.Request(GetFuncName(1), params, &resp)
	return resp, err
}

func (op *VSwitchOperator) DescribeVSwitches(params map[string]string) (DescribeVSwitchesResponse, error) {
	var resp DescribeVSwitchesResponse
	err := op.Common.Request(GetFuncName(1), params, &resp)
	return resp, err
}

func (op *VSwitchOperator) ModifyVSwitchAttribute(params map[string]string) (ModifyVSwitchAttributeResponse, error) {
	var resp ModifyVSwitchAttributeResponse
	err := op.Common.Request(GetFuncName(1), params, &resp)
	return resp, err
}
<commit_msg>fix vswitch<commit_after>package ecs

import "github.com/jiangshengwu/aliyun-sdk-for-go/util"

type VSwitchService interface {
	/**
	 * ZoneId(required): 可用区 Id
	 * CidrBlock(required): 指定VSwitch的网段
	 * VpcId(required): 指定VSwitch所在的 VPC
	 * VSwitchName(optional): VSwitch名称，不填则为空，默认值为空，[2, 128] 英文或中文字符，必须以大小字母或中文开头，可包含数字，”_”或”-”，这个值会展示在控制台。不能以 http:// 和 https:// 开头
	 * Description(optional): VSwitch 描述，不填则为空，默认值为空，[2, 256] 英文或中文字符，不能以 http:// 和 https:// 开头
	 * ClientToken(optional): 用于保证请求的幂等性。由客户端生成该参数值，要保证在不同请求间唯一，最大不值过 64 个 ASCII 字符
	 */
	CreateVSwitch(param map[string]string) (CreateVSwitchResponse, error)

	/**
	 * VSwitchId(required): 需要删除的 VSwitch 的 Id
	 */
	DeleteVSwitch(param map[string]string) (DeleteVSwitchResponse, error)

	/**
	 * VpcId(required): VpcId
	 * VSwitchId(optional): 需要查询的 VSwitch 的 Id
	 * ZoneId(optional): 可用区 Id
	 * PageNumber(optional):
	 * PageSize(optional):
	 */
	DescribeVSwitches(param map[string]string) (DescribeVSwitchesResponse, error)

	/**
	 * VSwitchId(required)
	 * VSwitchName(optional)
	 * Description(optional)
	 */
	ModifyVSwitchAttribute(param map[string]string) (ModifyVSwitchAttributeResponse, error)
}

type VSwitchOperator struct {
	Common *CommonParam
}

type CreateVSwitchResponse struct {
	util.ErrorResponse
	VSwitchId string `json:"VSwitchId"`
}

type DeleteVSwitchResponse struct {
	util.ErrorResponse
}

type DescribeVSwitchesResponse struct {
	util.ErrorResponse
	util.PageResponse
	AllVSwitches VSwitchTypes `json:"VSwitches"`
}

type ModifyVSwitchAttributeResponse struct {
	util.ErrorResponse
}

type VSwitchTypes struct {
	AllVSwitch []VSwitchType `json:"VSwitch"`
}

type VSwitchType struct {
	VSwitchId               string `json:"VSwitchId"`
	VpcId                   string `json:"VpcId"`
	Status                  string `json:"Status"`
	CidrBlock               string `json:"CidrBlock"`
	ZoneId                  string `json:"ZoneId"`
	AvailableIpAddressCount int    `json:"AvailableIpAddressCount"`
	Description             string `json:"Description"`
	VSwitchName             string `json:"VSwitchName"`
	CreationTime            string `json:"CreationTime"`
}

func (op *VSwitchOperator) CreateVSwitch(params map[string]string) (CreateVSwitchResponse, error) {
	var resp CreateVSwitchResponse
	err := op.Common.Request(GetFuncName(1), params, &resp)
	return resp, err
}

func (op *VSwitchOperator) DeleteVSwitch(params map[string]string) (DeleteVSwitchResponse, error) {
	var resp DeleteVSwitchResponse
	err := op.Common.Request(GetFuncName(1), params, &resp)
	return resp, err
}

func (op *VSwitchOperator) DescribeVSwitches(params map[string]string) (DescribeVSwitchesResponse, error) {
	var resp DescribeVSwitchesResponse
	err := op.Common.Request(GetFuncName(1), params, &resp)
	return resp, err
}

func (op *VSwitchOperator) ModifyVSwitchAttribute(params map[string]string) (ModifyVSwitchAttributeResponse, error) {
	var resp ModifyVSwitchAttributeResponse
	err := op.Common.Request(GetFuncName(1), params, &resp)
	return resp, err
}
<|endoftext|>


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

package main

import (
	"encoding/binary"
	"fmt"
	"net"
	"os"

	"golang.org/x/net/context"

	"github.com/golang/glog"

	"github.com/01org/ciao/networking/libsnnet"
	"github.com/01org/ciao/payloads"
	"github.com/01org/ciao/ssntp"
)

var cnNet *libsnnet.ComputeNode
var hostname string
var nicInfo []*payloads.NetworkStat
var dockerNet *libsnnet.DockerPlugin

func initNetworkPhase1() error {

	cn := &libsnnet.ComputeNode{}
	var mnetList []net.IPNet
	var cnetList []net.IPNet

	if computeNet != "" {
		_, cnet, _ := net.ParseCIDR(computeNet)
		if cnet == nil {
			return fmt.Errorf("Unable to Parse CIDR :" + computeNet)
		}
		cnetList = []net.IPNet{*cnet}
	}

	if mgmtNet != "" {
		_, mnet, _ := net.ParseCIDR(mgmtNet)
		if mnet == nil {
			return fmt.Errorf("Unable to Parse CIDR :" + mgmtNet)
		}
		mnetList = []net.IPNet{*mnet}
	}

	cn.NetworkConfig = &libsnnet.NetworkConfig{
		ManagementNet: mnetList,
		ComputeNet:    cnetList,
		Mode:          libsnnet.GreTunnel,
	}

	libsnnet.CnMaxAPIConcurrency = 1
	if err := cn.Init(); err != nil {
		return err
	}

	cnNet = cn

	return nil
}

func initDockerNetworking(ctx context.Context) error {
	dockerPlugin := libsnnet.NewDockerPlugin()
	if err := dockerPlugin.Init(); err != nil {
		glog.Warningf("Docker Init failed: %v", err)
		return err
	}

	if err := dockerPlugin.Start(); err != nil {
		dockerPlugin.Close()
		glog.Warningf("Docker start failed: %v ", err)
		return err
	}

	dockerNet = dockerPlugin

	return nil
}

func shutdownNetwork() {
	if dockerNet == nil {
		return
	}

	if err := dockerNet.Stop(); err != nil {
		glog.Warningf("Docker stop failed: %v", err)
	}

	if err := dockerNet.Close(); err != nil {
		glog.Warningf("Docker close failed: %v", err)
	}

	glog.Infof("Docker networking shutdown successfully")
}

func initNetwork(ctx context.Context) error {

	if err := initNetworkPhase1(); err != nil {
		return err
	}

	if err := initDockerNetworking(ctx); err != nil {
		glog.Warning("Unable to initialise docker networking")
	}

	if err := cnNet.DbRebuild(nil); err != nil {
		return err
	}

	limit := len(cnNet.ComputeAddr)
	if len(cnNet.ComputeLink) < limit {
		limit = len(cnNet.ComputeLink)
	}

	for i := 0; i < limit; i++ {
		nicInfo = append(nicInfo, &payloads.NetworkStat{
			NodeIP:  cnNet.ComputeAddr[i].IP.String(),
			NodeMAC: cnNet.ComputeLink[i].Attrs().HardwareAddr.String(),
		})
		glog.Infof("Network card %d Info", i)
		glog.Infof("  IP address of node is %s", nicInfo[i].NodeIP)
		glog.Infof("  MAC address of node is %s", nicInfo[i].NodeMAC)
	}

	if len(nicInfo) == 0 {
		glog.Warning("Unable to determine IP address. Should not happen")
	}

	var err error
	hostname, err = os.Hostname()
	if err == nil {
		glog.Infof("Hostname of node is %s", hostname)
	} else {
		glog.Warning("Unable to determine hostname %s", err)
	}

	return nil
}

func initNetworking(ctx context.Context) chan error {
	ch := make(chan error)
	go func() {
		err := initNetwork(ctx)
		ch <- err
	}()
	return ch
}

func createCNVnicCfg(cfg *vmConfig) (*libsnnet.VnicConfig, error) {

	glog.Info("Creating CN Vnic CFG")

	mac, err := net.ParseMAC(cfg.VnicMAC)
	if err != nil {
		return nil, fmt.Errorf("Invalid mac address %v", err)
	}

	_, vnet, err := net.ParseCIDR(cfg.SubnetIP)
	if err != nil {
		return nil, fmt.Errorf("Invalid vnic subnet %v", err)
	}

	concIP := net.ParseIP(cfg.ConcIP)
	if concIP == nil {
		return nil, fmt.Errorf("Invalid concentrator ip %s", cfg.ConcIP)
	}

	vnicIP := net.ParseIP(cfg.VnicIP)
	if vnicIP == nil {
		return nil, fmt.Errorf("Invalid vnicIP ip %s", cfg.VnicIP)
	}

	subnetKey := binary.LittleEndian.Uint32(vnet.IP)
	var role libsnnet.VnicRole
	if cfg.Container {
		role = libsnnet.TenantContainer
	} else {
		role = libsnnet.TenantVM
	}

	return &libsnnet.VnicConfig{
		VnicRole:   role,
		VnicIP:     vnicIP,
		ConcIP:     concIP,
		VnicMAC:    mac,
		Subnet:     *vnet,
		SubnetKey:  int(subnetKey),
		VnicID:     cfg.VnicUUID,
		InstanceID: cfg.Instance,
		TenantID:   cfg.TennantUUID,
		SubnetID:   cfg.SubnetIP,
		ConcID:     cfg.ConcUUID}, nil
}

func createCNCIVnicCfg(cfg *vmConfig) (*libsnnet.VnicConfig, error) {

	glog.Info("Creating CNCI Vnic CFG")

	mac, err := net.ParseMAC(cfg.VnicMAC)
	if err != nil {
		return nil, fmt.Errorf("Invalid mac address %v", err)
	}

	return &libsnnet.VnicConfig{
		VnicRole:   libsnnet.DataCenter,
		VnicMAC:    mac,
		VnicID:     cfg.VnicUUID,
		InstanceID: cfg.Instance,
		TenantID:   cfg.TennantUUID}, nil
}

func createVnicCfg(cfg *vmConfig) (*libsnnet.VnicConfig, error) {
	if cfg.NetworkNode {
		return createCNCIVnicCfg(cfg)
	}

	return createCNVnicCfg(cfg)
}

func sendNetworkEvent(client *ssntpConn, eventType ssntp.Event,
	event *libsnnet.SsntpEventInfo) {

	if event == nil || !client.isConnected() {
		return
	}

	payload, err := generateNetEventPayload(event, client.UUID())
	if err != nil {
		glog.Warningf("Unable parse ssntpEvent %s", err)
		return
	}

	_, err = client.SendEvent(eventType, payload)
	if err != nil {
		glog.Warningf("Unable to send %s", event)
	}
}

func createVnic(client *ssntpConn, vnicCfg *libsnnet.VnicConfig) (string, string, error) {
	var name string
	var bridge string

	//BUG(markus): This function needs a context parameter

	if vnicCfg.VnicRole != libsnnet.DataCenter {
		var vnic *libsnnet.Vnic
		var event *libsnnet.SsntpEventInfo
		var info *libsnnet.ContainerInfo
		var err error
		if vnicCfg.VnicRole == libsnnet.TenantContainer {
			vnic, event, info, err = createDockerVnicV2(vnicCfg)
			bridge = info.SubnetID
		} else {
			vnic, event, info, err = cnNet.CreateVnicV2(vnicCfg)
		}
		if err != nil {
			glog.Errorf("cn.CreateVnic failed %v", err)
			return "", "", err
		}
		sendNetworkEvent(client, ssntp.TenantAdded, event)
		name = vnic.LinkName
		glog.Infoln("CN VNIC created =", name, info, event)
	} else {
		vnic, err := cnNet.CreateCnciVnic(vnicCfg)
		if err != nil {
			glog.Errorf("cn.CreateCnciVnic failed %v", err)
			return "", "", err
		}
		name = vnic.LinkName
		glog.Infoln("CNCI VNIC created =", name)
	}

	return name, bridge, nil
}

func destroyVnic(client *ssntpConn, vnicCfg *libsnnet.VnicConfig) error {
	if vnicCfg.VnicRole != libsnnet.DataCenter {
		var event *libsnnet.SsntpEventInfo
		var err error

		if vnicCfg.VnicRole == libsnnet.TenantContainer {
			event, err = destroyDockerVnicV2(vnicCfg)
		} else {
			event, _, err = cnNet.DestroyVnicV2(vnicCfg)
		}
		if err != nil {
			glog.Errorf("cn.DestroyVnic failed %v", err)
			return err
		}

		sendNetworkEvent(client, ssntp.TenantRemoved, event)

		glog.Infoln("CN VNIC Destroyed =", vnicCfg.VnicIP, event)
	} else {
		err := cnNet.DestroyCnciVnic(vnicCfg)
		if err != nil {
			glog.Errorf("cn.DestroyCnciVnic failed %v", err)
			return err
		}

		glog.Infoln("CNCI VNIC Destroyed =", vnicCfg.VnicIP)
	}

	return nil
}

func getNodeIPAddress() string {
	if len(nicInfo) == 0 {
		return "127.0.0.1"
	}

	return nicInfo[0].NodeIP
}
<commit_msg>ciao-launcher: networking: Fix a crash when Vnic creation fails<commit_after>/*
// Copyright (c) 2016 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/

package main

import (
	"encoding/binary"
	"fmt"
	"net"
	"os"

	"golang.org/x/net/context"

	"github.com/golang/glog"

	"github.com/01org/ciao/networking/libsnnet"
	"github.com/01org/ciao/payloads"
	"github.com/01org/ciao/ssntp"
)

var cnNet *libsnnet.ComputeNode
var hostname string
var nicInfo []*payloads.NetworkStat
var dockerNet *libsnnet.DockerPlugin

func initNetworkPhase1() error {

	cn := &libsnnet.ComputeNode{}
	var mnetList []net.IPNet
	var cnetList []net.IPNet

	if computeNet != "" {
		_, cnet, _ := net.ParseCIDR(computeNet)
		if cnet == nil {
			return fmt.Errorf("Unable to Parse CIDR :" + computeNet)
		}
		cnetList = []net.IPNet{*cnet}
	}

	if mgmtNet != "" {
		_, mnet, _ := net.ParseCIDR(mgmtNet)
		if mnet == nil {
			return fmt.Errorf("Unable to Parse CIDR :" + mgmtNet)
		}
		mnetList = []net.IPNet{*mnet}
	}

	cn.NetworkConfig = &libsnnet.NetworkConfig{
		ManagementNet: mnetList,
		ComputeNet:    cnetList,
		Mode:          libsnnet.GreTunnel,
	}

	libsnnet.CnMaxAPIConcurrency = 1
	if err := cn.Init(); err != nil {
		return err
	}

	cnNet = cn

	return nil
}

func initDockerNetworking(ctx context.Context) error {
	dockerPlugin := libsnnet.NewDockerPlugin()
	if err := dockerPlugin.Init(); err != nil {
		glog.Warningf("Docker Init failed: %v", err)
		return err
	}

	if err := dockerPlugin.Start(); err != nil {
		dockerPlugin.Close()
		glog.Warningf("Docker start failed: %v ", err)
		return err
	}

	dockerNet = dockerPlugin

	return nil
}

func shutdownNetwork() {
	if dockerNet == nil {
		return
	}

	if err := dockerNet.Stop(); err != nil {
		glog.Warningf("Docker stop failed: %v", err)
	}

	if err := dockerNet.Close(); err != nil {
		glog.Warningf("Docker close failed: %v", err)
	}

	glog.Infof("Docker networking shutdown successfully")
}

func initNetwork(ctx context.Context) error {

	if err := initNetworkPhase1(); err != nil {
		return err
	}

	if err := initDockerNetworking(ctx); err != nil {
		glog.Warning("Unable to initialise docker networking")
	}

	if err := cnNet.DbRebuild(nil); err != nil {
		return err
	}

	limit := len(cnNet.ComputeAddr)
	if len(cnNet.ComputeLink) < limit {
		limit = len(cnNet.ComputeLink)
	}

	for i := 0; i < limit; i++ {
		nicInfo = append(nicInfo, &payloads.NetworkStat{
			NodeIP:  cnNet.ComputeAddr[i].IP.String(),
			NodeMAC: cnNet.ComputeLink[i].Attrs().HardwareAddr.String(),
		})
		glog.Infof("Network card %d Info", i)
		glog.Infof("  IP address of node is %s", nicInfo[i].NodeIP)
		glog.Infof("  MAC address of node is %s", nicInfo[i].NodeMAC)
	}

	if len(nicInfo) == 0 {
		glog.Warning("Unable to determine IP address. Should not happen")
	}

	var err error
	hostname, err = os.Hostname()
	if err == nil {
		glog.Infof("Hostname of node is %s", hostname)
	} else {
		glog.Warning("Unable to determine hostname %s", err)
	}

	return nil
}

func initNetworking(ctx context.Context) chan error {
	ch := make(chan error)
	go func() {
		err := initNetwork(ctx)
		ch <- err
	}()
	return ch
}

func createCNVnicCfg(cfg *vmConfig) (*libsnnet.VnicConfig, error) {

	glog.Info("Creating CN Vnic CFG")

	mac, err := net.ParseMAC(cfg.VnicMAC)
	if err != nil {
		return nil, fmt.Errorf("Invalid mac address %v", err)
	}

	_, vnet, err := net.ParseCIDR(cfg.SubnetIP)
	if err != nil {
		return nil, fmt.Errorf("Invalid vnic subnet %v", err)
	}

	concIP := net.ParseIP(cfg.ConcIP)
	if concIP == nil {
		return nil, fmt.Errorf("Invalid concentrator ip %s", cfg.ConcIP)
	}

	vnicIP := net.ParseIP(cfg.VnicIP)
	if vnicIP == nil {
		return nil, fmt.Errorf("Invalid vnicIP ip %s", cfg.VnicIP)
	}

	subnetKey := binary.LittleEndian.Uint32(vnet.IP)
	var role libsnnet.VnicRole
	if cfg.Container {
		role = libsnnet.TenantContainer
	} else {
		role = libsnnet.TenantVM
	}

	return &libsnnet.VnicConfig{
		VnicRole:   role,
		VnicIP:     vnicIP,
		ConcIP:     concIP,
		VnicMAC:    mac,
		Subnet:     *vnet,
		SubnetKey:  int(subnetKey),
		VnicID:     cfg.VnicUUID,
		InstanceID: cfg.Instance,
		TenantID:   cfg.TennantUUID,
		SubnetID:   cfg.SubnetIP,
		ConcID:     cfg.ConcUUID}, nil
}

func createCNCIVnicCfg(cfg *vmConfig) (*libsnnet.VnicConfig, error) {

	glog.Info("Creating CNCI Vnic CFG")

	mac, err := net.ParseMAC(cfg.VnicMAC)
	if err != nil {
		return nil, fmt.Errorf("Invalid mac address %v", err)
	}

	return &libsnnet.VnicConfig{
		VnicRole:   libsnnet.DataCenter,
		VnicMAC:    mac,
		VnicID:     cfg.VnicUUID,
		InstanceID: cfg.Instance,
		TenantID:   cfg.TennantUUID}, nil
}

func createVnicCfg(cfg *vmConfig) (*libsnnet.VnicConfig, error) {
	if cfg.NetworkNode {
		return createCNCIVnicCfg(cfg)
	}

	return createCNVnicCfg(cfg)
}

func sendNetworkEvent(client *ssntpConn, eventType ssntp.Event,
	event *libsnnet.SsntpEventInfo) {

	if event == nil || !client.isConnected() {
		return
	}

	payload, err := generateNetEventPayload(event, client.UUID())
	if err != nil {
		glog.Warningf("Unable parse ssntpEvent %s", err)
		return
	}

	_, err = client.SendEvent(eventType, payload)
	if err != nil {
		glog.Warningf("Unable to send %s", event)
	}
}

func createVnic(client *ssntpConn, vnicCfg *libsnnet.VnicConfig) (string, string, error) {
	var name string
	var bridge string

	//BUG(markus): This function needs a context parameter

	if vnicCfg.VnicRole != libsnnet.DataCenter {
		var vnic *libsnnet.Vnic
		var event *libsnnet.SsntpEventInfo
		var info *libsnnet.ContainerInfo
		var err error
		if vnicCfg.VnicRole == libsnnet.TenantContainer {
			vnic, event, info, err = createDockerVnicV2(vnicCfg)
			if err != nil {
				glog.Errorf("cn.CreateVnic failed %v", err)
				return "", "", err
			}
			bridge = info.SubnetID
		} else {
			vnic, event, info, err = cnNet.CreateVnicV2(vnicCfg)
			if err != nil {
				glog.Errorf("cn.CreateVnic failed %v", err)
				return "", "", err
			}
		}
		sendNetworkEvent(client, ssntp.TenantAdded, event)
		name = vnic.LinkName
		glog.Infoln("CN VNIC created =", name, info, event)
	} else {
		vnic, err := cnNet.CreateCnciVnic(vnicCfg)
		if err != nil {
			glog.Errorf("cn.CreateCnciVnic failed %v", err)
			return "", "", err
		}
		name = vnic.LinkName
		glog.Infoln("CNCI VNIC created =", name)
	}

	return name, bridge, nil
}

func destroyVnic(client *ssntpConn, vnicCfg *libsnnet.VnicConfig) error {
	if vnicCfg.VnicRole != libsnnet.DataCenter {
		var event *libsnnet.SsntpEventInfo
		var err error

		if vnicCfg.VnicRole == libsnnet.TenantContainer {
			event, err = destroyDockerVnicV2(vnicCfg)
		} else {
			event, _, err = cnNet.DestroyVnicV2(vnicCfg)
		}
		if err != nil {
			glog.Errorf("cn.DestroyVnic failed %v", err)
			return err
		}

		sendNetworkEvent(client, ssntp.TenantRemoved, event)

		glog.Infoln("CN VNIC Destroyed =", vnicCfg.VnicIP, event)
	} else {
		err := cnNet.DestroyCnciVnic(vnicCfg)
		if err != nil {
			glog.Errorf("cn.DestroyCnciVnic failed %v", err)
			return err
		}

		glog.Infoln("CNCI VNIC Destroyed =", vnicCfg.VnicIP)
	}

	return nil
}

func getNodeIPAddress() string {
	if len(nicInfo) == 0 {
		return "127.0.0.1"
	}

	return nicInfo[0].NodeIP
}
<|endoftext|>


<commit_before>package itchio

// User represents an itch.io account, with basic profile info
type User struct {
	// Site-wide unique identifier generated by itch.io
	ID int64 `json:"id"`

	// The user's username (used for login)
	Username string `json:"username"`
	// The user's display name: human-friendly, may contain spaces, unicode etc.
	DisplayName string `json:"displayName"`

	// Has the user opted into creating games?
	Developer bool `json:"developer"`
	// Is the user part of itch.io's press program?
	PressUser bool `json:"pressUser"`

	// The address of the user's page on itch.io
	URL string `json:"url"`
	// User's avatar, may be a GIF
	CoverURL string `json:"coverUrl"`
	// Static version of user's avatar, only set if the main cover URL is a GIF
	StillCoverURL string `json:"stillCoverUrl"`
}

// Game represents a page on itch.io, it could be a game,
// a tool, a comic, etc.
type Game struct {
	// Site-wide unique identifier generated by itch.io
	ID int64 `json:"id"`
	// Canonical address of the game's page on itch.io
	URL string `json:"url"`

	// Human-friendly title (may contain any character)
	Title string `json:"title"`
	// Human-friendly short description
	ShortText string `json:"shortText"`
	// Downloadable game, html game, etc.
	Type string `json:"type"`
	// Classification: game, tool, comic, etc.
	Classification string `json:"classification"`

	// Cover url (might be a GIF)
	CoverURL string `json:"coverUrl"`
	// Non-gif cover url, only set if main cover url is a GIF
	StillCoverURL string `json:"stillCoverUrl"`

	// Date the game was created
	CreatedAt string `json:"createdAt"`
	// Date the game was published, empty if not currently published
	PublishedAt string `json:"publishedAt"`

	// Price in cents of a dollar
	MinPrice int64 `json:"minPrice"`
	// Is this game downloadable by press users for free?
	InPressSystem bool `json:"inPressSystem"`
	// Does this game have a demo that can be downloaded for free?
	HasDemo bool `json:"hasDemo"`

	// Does this game have an upload tagged with 'macOS compatible'? (creator-controlled)
	OSX bool `json:"pOsx"`
	// Does this game have an upload tagged with 'Linux compatible'? (creator-controlled)
	Linux bool `json:"pLinux"`
	// Does this game have an upload tagged with 'Windows compatible'? (creator-controlled)
	Windows bool `json:"pWindows"`
	// Does this game have an upload tagged with 'Android compatible'? (creator-controlled)
	Android bool `json:"pAndroid"`
}

// An Upload is a downloadable file. Some are wharf-enabled, which means
// they're actually a "channel" that may contain multiple builds, pushed
// with <https://github.com/itchio/butler>
type Upload struct {
	// Site-wide unique identifier generated by itch.io
	ID int64 `json:"id"`
	// Original file name (example: `Overland_x64.zip`)
	Filename string `json:"filename"`
	// Human-friendly name set by developer (example: `Overland for Windows 64-bit`)
	DisplayName string `json:"displayName"`
	// Size of upload in bytes. For wharf-enabled uploads, it's the archive size.
	Size int64 `json:"size"`
	// Name of the wharf channel for this upload, if it's a wharf-enabled upload
	ChannelName string `json:"channelName"`
	// Latest build for this upload, if it's a wharf-enabled upload
	Build *Build `json:"build"`
	// Is this upload a demo that can be downloaded for free?
	Demo bool `json:"demo"`
	// Is this upload a pre-order placeholder?
	Preorder bool `json:"preorder"`

	// Upload type: default, soundtrack, etc.
	Type string `json:"type"`

	// Is this upload tagged with 'macOS compatible'? (creator-controlled)
	OSX bool `json:"pOsx"`
	// Is this upload tagged with 'Linux compatible'? (creator-controlled)
	Linux bool `json:"pLinux"`
	// Is this upload tagged with 'Windows compatible'? (creator-controlled)
	Windows bool `json:"pWindows"`
	// Is this upload tagged with 'Android compatible'? (creator-controlled)
	Android bool `json:"pAndroid"`

	// Date this upload was created at
	CreatedAt string `json:"createdAt"`
	// Date this upload was last updated at (order changed, display name set, etc.)
	UpdatedAt string `json:"updatedAt"`
}

// A Collection is a set of games, curated by humans.
type Collection struct {
	// Site-wide unique identifier generated by itch.io
	ID int64 `json:"id"`

	// Human-friendly title for collection, for example `Couch coop games`
	Title string `json:"title"`

	// Date this collection was created at
	CreatedAt string `json:"createdAt"`
	// Date this collection was last updated at (item added, title set, etc.)
	UpdatedAt string `json:"updatedAt"`

	// Number of games in the collection. This might not be accurate
	// as some games might not be accessible to whoever is asking (project
	// page deleted, visibility level changed, etc.)
	GamesCount int64 `json:"gamesCount"`
}

// A download key is often generated when a purchase is made, it
// allows downloading uploads for a game that are not available
// for free.
type DownloadKey struct {
	// Site-wide unique identifier generated by itch.io
	ID int64 `json:"id"`

	// Identifier of the game to which this download key grants access
	GameID int64 `json:"gameId"`
	Game   *Game `json:"game,omitempty" gorm:"-"`

	// Date this key was created at (often coincides with purchase time)
	CreatedAt string `json:"createdAt"`
	// Date this key was last updated at
	UpdatedAt string `json:"updatedAt"`

	// Identifier of the itch.io user to which this key belongs
	OwnerID int64 `json:"ownerId"`
}

// Build contains information about a specific build
type Build struct {
	// Site-wide unique identifier generated by itch.io
	ID int64 `json:"id"`
	// Identifier of the build before this one on the same channel,
	// or 0 if this is the initial build.
	ParentBuildID int64 `json:"parentBuildId"`
	// State of the build: started, processing, etc.
	State BuildState `json:"state"`

	// Automatically-incremented version number, starting with 1
	Version int64 `json:"version"`
	// Value specified by developer with `--userversion` when pushing a build
	// Might not be unique across builds of a given channel.
	UserVersion string `json:"userVersion"`

	// Files associated with this build - often at least an archive,
	// a signature, and a patch. Some might be missing while the build
	// is still processing or if processing has failed.
	Files []*BuildFile `json:"files"`

	User      User   `json:"user"`
	CreatedAt string `json:"createdAt"`
	UpdatedAt string `json:"updatedAt"`
}
<commit_msg>More comments<commit_after>package itchio

// User represents an itch.io account, with basic profile info
type User struct {
	// Site-wide unique identifier generated by itch.io
	ID int64 `json:"id"`

	// The user's username (used for login)
	Username string `json:"username"`
	// The user's display name: human-friendly, may contain spaces, unicode etc.
	DisplayName string `json:"displayName"`

	// Has the user opted into creating games?
	Developer bool `json:"developer"`
	// Is the user part of itch.io's press program?
	PressUser bool `json:"pressUser"`

	// The address of the user's page on itch.io
	URL string `json:"url"`
	// User's avatar, may be a GIF
	CoverURL string `json:"coverUrl"`
	// Static version of user's avatar, only set if the main cover URL is a GIF
	StillCoverURL string `json:"stillCoverUrl"`
}

// Game represents a page on itch.io, it could be a game,
// a tool, a comic, etc.
type Game struct {
	// Site-wide unique identifier generated by itch.io
	ID int64 `json:"id"`
	// Canonical address of the game's page on itch.io
	URL string `json:"url"`

	// Human-friendly title (may contain any character)
	Title string `json:"title"`
	// Human-friendly short description
	ShortText string `json:"shortText"`
	// Downloadable game, html game, etc.
	Type string `json:"type"`
	// Classification: game, tool, comic, etc.
	Classification string `json:"classification"`

	// Cover url (might be a GIF)
	CoverURL string `json:"coverUrl"`
	// Non-gif cover url, only set if main cover url is a GIF
	StillCoverURL string `json:"stillCoverUrl"`

	// Date the game was created
	CreatedAt string `json:"createdAt"`
	// Date the game was published, empty if not currently published
	PublishedAt string `json:"publishedAt"`

	// Price in cents of a dollar
	MinPrice int64 `json:"minPrice"`
	// Is this game downloadable by press users for free?
	InPressSystem bool `json:"inPressSystem"`
	// Does this game have a demo that can be downloaded for free?
	HasDemo bool `json:"hasDemo"`

	// Does this game have an upload tagged with 'macOS compatible'? (creator-controlled)
	OSX bool `json:"pOsx"`
	// Does this game have an upload tagged with 'Linux compatible'? (creator-controlled)
	Linux bool `json:"pLinux"`
	// Does this game have an upload tagged with 'Windows compatible'? (creator-controlled)
	Windows bool `json:"pWindows"`
	// Does this game have an upload tagged with 'Android compatible'? (creator-controlled)
	Android bool `json:"pAndroid"`
}

// An Upload is a downloadable file. Some are wharf-enabled, which means
// they're actually a "channel" that may contain multiple builds, pushed
// with <https://github.com/itchio/butler>
type Upload struct {
	// Site-wide unique identifier generated by itch.io
	ID int64 `json:"id"`
	// Original file name (example: `Overland_x64.zip`)
	Filename string `json:"filename"`
	// Human-friendly name set by developer (example: `Overland for Windows 64-bit`)
	DisplayName string `json:"displayName"`
	// Size of upload in bytes. For wharf-enabled uploads, it's the archive size.
	Size int64 `json:"size"`
	// Name of the wharf channel for this upload, if it's a wharf-enabled upload
	ChannelName string `json:"channelName"`
	// Latest build for this upload, if it's a wharf-enabled upload
	Build *Build `json:"build"`
	// Is this upload a demo that can be downloaded for free?
	Demo bool `json:"demo"`
	// Is this upload a pre-order placeholder?
	Preorder bool `json:"preorder"`

	// Upload type: default, soundtrack, etc.
	Type string `json:"type"`

	// Is this upload tagged with 'macOS compatible'? (creator-controlled)
	OSX bool `json:"pOsx"`
	// Is this upload tagged with 'Linux compatible'? (creator-controlled)
	Linux bool `json:"pLinux"`
	// Is this upload tagged with 'Windows compatible'? (creator-controlled)
	Windows bool `json:"pWindows"`
	// Is this upload tagged with 'Android compatible'? (creator-controlled)
	Android bool `json:"pAndroid"`

	// Date this upload was created at
	CreatedAt string `json:"createdAt"`
	// Date this upload was last updated at (order changed, display name set, etc.)
	UpdatedAt string `json:"updatedAt"`
}

// A Collection is a set of games, curated by humans.
type Collection struct {
	// Site-wide unique identifier generated by itch.io
	ID int64 `json:"id"`

	// Human-friendly title for collection, for example `Couch coop games`
	Title string `json:"title"`

	// Date this collection was created at
	CreatedAt string `json:"createdAt"`
	// Date this collection was last updated at (item added, title set, etc.)
	UpdatedAt string `json:"updatedAt"`

	// Number of games in the collection. This might not be accurate
	// as some games might not be accessible to whoever is asking (project
	// page deleted, visibility level changed, etc.)
	GamesCount int64 `json:"gamesCount"`
}

// A download key is often generated when a purchase is made, it
// allows downloading uploads for a game that are not available
// for free.
type DownloadKey struct {
	// Site-wide unique identifier generated by itch.io
	ID int64 `json:"id"`

	// Identifier of the game to which this download key grants access
	GameID int64 `json:"gameId"`

	// Game to which this download key grants access
	Game *Game `json:"game,omitempty" gorm:"-"`

	// Date this key was created at (often coincides with purchase time)
	CreatedAt string `json:"createdAt"`
	// Date this key was last updated at
	UpdatedAt string `json:"updatedAt"`

	// Identifier of the itch.io user to which this key belongs
	OwnerID int64 `json:"ownerId"`
}

// Build contains information about a specific build
type Build struct {
	// Site-wide unique identifier generated by itch.io
	ID int64 `json:"id"`
	// Identifier of the build before this one on the same channel,
	// or 0 if this is the initial build.
	ParentBuildID int64 `json:"parentBuildId"`
	// State of the build: started, processing, etc.
	State BuildState `json:"state"`

	// Automatically-incremented version number, starting with 1
	Version int64 `json:"version"`
	// Value specified by developer with `--userversion` when pushing a build
	// Might not be unique across builds of a given channel.
	UserVersion string `json:"userVersion"`

	// Files associated with this build - often at least an archive,
	// a signature, and a patch. Some might be missing while the build
	// is still processing or if processing has failed.
	Files []*BuildFile `json:"files"`

	// User who pushed the build
	User User `json:"user"`
	// Timestamp the build was created at
	CreatedAt string `json:"createdAt"`
	// Timestamp the build was last updated at
	UpdatedAt string `json:"updatedAt"`
}
<|endoftext|>


<commit_before>package gondole

import "time"

type Gondole struct {
	Name string
    RedirectURI string
}

type Account struct {
	ID         int
	Acct       string
	Avatar     string
	Followers  int
	Followings int
	Header     string
	Note       string
	Statuses   int
	URL        string
	Username   string
}

type Client struct {
	BaseURL     string
	BearerToken string
}

type Status struct {
	ID         int
	Account    *Account
	Content    string
	CreatedAT  time.Time
	Favourited bool
	Favourites int
	InReplyTo  int
	Reblog     *Status
	Reblogged  bool
	Reblogs    int
	URI        string
	URL        string
}
<commit_msg>Add all types documented.<commit_after>package gondole

import (
	"github.com/urfave/cli"
	"gopkg.in/asn1-ber.v1"
	"net/textproto"
	"time"
)

type Gondole struct {
	Name        string
	RedirectURI string
}

type Client struct {
	BaseURL     string
	BearerToken string
}

/*

Entities:

Everything manipulated/returned by the API
*/

type Account struct {
	ID          int
	Username    string
	Acct        string
	DisplayName string
	Note        string
	URL         string
	Avatar      string
	Header      string
	Locked      bool
	Followers   int
	Followings  int
	Statuses    int
}

type Application struct {
	Name    string
	Website string
}

type Attachement struct {
	ID         int
	Type       string
	URL        string
	RemoteURL  string
	PreviewURL string
	TextURL    string
}

type Card struct {
	URL         string
	Title       string
	Description string
	Image       string
}

type Context struct {
	Ancestors   []Status
	Descendents []Status
}

type Error struct {
	Text string
}

type Instance struct {
	URI         string
	Title       string
	Description string
	Email       string
}

type Mention struct {
	ID       int
	URL      string
	Username string
	Acct     string
}

type Notification struct {
	ID        int
	Type      string
	CreatedAt time.Time
	Account   *Account
	Status    *Status
}

type Relationship struct {
	Following  bool
	FollowedBy bool
	Blocking   bool
	Muting     bool
	Requested  bool
}
type Report struct {
	ID          int
	ActionTaken string
}

type Result struct {
	Accounts []Account
	Statutes []Status
	Hashtags []Tag
}

type Status struct {
	ID                 int
	URI                string
	URL                string
	Account            *Account
	InReplyToId        int
	InReplyToAccountID int
	Reblog             *Status
	Content            string
	CreatedAT          time.Time
	Reblogs            int
	Favourites         int
	Reblogged          bool
	Favourited         bool
	Sensitive          bool
	SpoilerText        string
	Visibility         string
	MediaAttachments   []Attachement
	Mentions           []Mention
	Tags               []Tag
	App                Application
}

type Tag struct {
	Name string
	URL  string
}
<|endoftext|>


<commit_before>package form

import (
	"regexp"
	"strconv"
	"strings"
	"time"
)

// Bool is a bool that implements Parser
type Bool struct {
	Data *bool
}

// Parse is an implementation of Parser
func (b Bool) Parse(d []string) error {
	switch strings.ToLower(d[0]) {
	case "on", "yes", "y":
		*b.Data = true
	case "off", "no", "n":
		*b.Data = false
	default:
		c, err := strconv.ParseBool(d[0])
		*b.Data = c
		return err
	}
	return nil
}

// Int is an int that implements Parser
type Int struct {
	Data *int
}

// Parse is an implementation of Parser
func (i Int) Parse(d []string) error {
	n, err := strconv.ParseInt(d[0], 10, 0)
	*i.Data = int(n)
	return err
}

// Int8 is an int8 that implements Parser
type Int8 struct {
	Data *int8
}

// Parse is an implementation of Parser
func (i Int8) Parse(d []string) error {
	n, err := strconv.ParseInt(d[0], 10, 8)
	*i.Data = int8(n)
	return err
}

// Int16 is an int16 that implements Parser
type Int16 struct {
	Data *int16
}

// Parse is an implementation of Parser
func (i Int16) Parse(d []string) error {
	n, err := strconv.ParseInt(d[0], 10, 16)
	*i.Data = int16(n)
	return err
}

// Int32 is an int32 that implements Parser
type Int32 struct {
	Data *int32
}

// Parse is an implementation of Parser
func (i Int32) Parse(d []string) error {
	n, err := strconv.ParseInt(d[0], 10, 32)
	*i.Data = int32(n)
	return err
}

// Int64 is an int64 that implements Parser
type Int64 struct {
	Data *int64
}

// Parse is an implementation of Parser
func (i Int64) Parse(d []string) error {
	n, err := strconv.ParseInt(d[0], 10, 64)
	*i.Data = n
	return err
}

// IntBetween is an implementation of Parser that allows a signed integer
// between the Min and Max (inclusively)
type IntBetween struct {
	Parser
	Min, Max int64
}

// Parse is an implementation of Parser
func (i IntBetween) Parse(d []string) error {
	n, err := strconv.ParseInt(d[0], 10, 64)
	if err != nil {
		return err
	}
	if n >= i.Min && n <= i.Max {
		return i.Parser.Parse(d)
	}
	return OutsideBounds(d[0])
}

// Uint is a uint that implements Parser
type Uint struct {
	Data *uint
}

// Parse is an implementation of Parser
func (u Uint) Parse(d []string) error {
	n, err := strconv.ParseUint(d[0], 10, 0)
	*u.Data = uint(n)
	return err
}

// Uint8 is a uint8 that implements Parser
type Uint8 struct {
	Data *uint8
}

// Parse is an implementation of Parser
func (u Uint8) Parse(d []string) error {
	n, err := strconv.ParseUint(d[0], 10, 8)
	*u.Data = uint8(n)
	return err
}

// Uint16 is a uint16 that implements Parser
type Uint16 struct {
	Data *uint16
}

// Parse is an implementation of Parser
func (u Uint16) Parse(d []string) error {
	n, err := strconv.ParseUint(d[0], 10, 16)
	*u.Data = uint16(n)
	return err
}

// Uint32 is a uint32 that implements Parser
type Uint32 struct {
	Data *uint32
}

// Parse is an implementation of Parser
func (u Uint32) Parse(d []string) error {
	n, err := strconv.ParseUint(d[0], 10, 32)
	*u.Data = uint32(n)
	return err
}

// Uint64 is a uint64 that implements Parser
type Uint64 struct {
	Data *uint64
}

// Parse is an implementation of Parser
func (u Uint64) Parse(d []string) error {
	n, err := strconv.ParseUint(d[0], 10, 64)
	*u.Data = n
	return err
}

// UintBetween is an implementation of Parser that allows an unsigned integer
// between the Min and Max (inclusively)
type UintBetween struct {
	Parser
	Min, Max uint64
}

// Parse is an implementation of Parser
func (u UintBetween) Parse(d []string) error {
	n, err := strconv.ParseUint(d[0], 10, 64)
	if err != nil {
		return err
	}
	if n >= u.Min && n <= u.Max {
		return u.Parser.Parse(d)
	}
	return OutsideBounds(d[0])
}

// Float32 is a float32 that implements Parser
type Float32 struct {
	Data *float32
}

// Parse is an implementation of Parser
func (f Float32) Parse(d []string) error {
	n, err := strconv.ParseFloat(d[0], 32)
	*f.Data = float32(n)
	return err
}

// Float64 is a float64 that implements Parser
type Float64 struct {
	Data *float64
}

// Parse is an implementation of Parser
func (f Float64) Parse(d []string) error {
	n, err := strconv.ParseFloat(d[0], 64)
	*f.Data = n
	return err
}

// FloatBetween is an implementation of Parser that allows a float between the
// Min and Max (inclusively)
type FloatBetween struct {
	Parser
	Min, Max float64
}

// Parse is an implementation of Parser
func (f FloatBetween) Parse(d []string) error {
	n, err := strconv.ParseFloat(d[0], 64)
	if err != nil {
		return err
	}
	if n >= f.Min && n <= f.Max {
		return f.Parser.Parse(d)
	}
	return OutsideBounds(d[0])
}

// String is a string that implements Parser
type String struct {
	Data *string
}

// Parse is an implementation of Parser
func (s String) Parse(d []string) error {
	*s.Data = d[0]
	return nil
}

// RegexString is an implementation of Parser that matches a string again the
// given regular expression
type RegexString struct {
	Data  *string
	Regex *regexp.Regexp
}

// Parse is an implementation of Parser
func (r RegexString) Parse(d []string) error {
	if r.Regex.MatchString(d[0]) {
		*s.Data = d[0]
		return nil
	}
	return NoRegexMatch(d[0])
}

var formats = [...]string{
	time.ANSIC,
	time.Kitchen,
	time.RFC1123,
	time.RFC1123Z,
	time.RFC3339,
	time.RFC3339Nano,
	time.RFC822,
	time.RFC822Z,
	time.RFC850,
	time.RubyDate,
	time.Stamp,
	time.StampNano,
	time.StampMicro,
	time.StampMilli,
	time.UnixDate,
	"2/1/06 15:04:05",
	"2/1/2006 15:04:05",
	"02/01/06 15:04:05",
	"02/01/2006 15:04:05",
	"2/1/06 15:04",
	"2/1/2006 15:04",
	"02/01/06 15:04",
	"02/01/2006 15:04",
	"15:04:05 2/1/06",
	"15:04:05 2/1/2006",
	"15:04:05 02/01/06",
	"15:04:05 02/01/2006",
	"15:04 2/1/06",
	"15:04 2/1/2006",
	"15:04 02/01/06",
	"15:04 02/01/2006",
	"2-1-06 15:04:05",
	"2-1-2006 15:04:05",
	"02-01-06 15:04:05",
	"02-01-2006 15:04:05",
	"2-1-06 15:04",
	"2-1-2006 15:04",
	"02-01-06 15:04",
	"02-01-2006 15:04",
	"15:04:05 2-1-06",
	"15:04:05 2-1-2006",
	"15:04:05 02-01-06",
	"15:04:05 02-01-2006",
	"15:04 2-1-06",
	"15:04 2-1-2006",
	"15:04 02-01-06",
	"15:04 02-01-2006",
}

// Time is a time.Time that implements Parser
type Time struct {
	Data *time.Time
}

// Parse is an implementation of Parser
func (t Time) Parse(d []string) error {
	for _, format := range formats {
		pt, err := time.Parse(format, d[0])
		if err == nil {
			*t.Data = pt
			return nil
		}
	}
	return UnknownFormat(d[0])
}

// TimeFormat is like a Time except that it allows a specific format to be
// specified
type TimeFormat struct {
	Data   *time.Time
	Format string
}

// Parse is an implementation of Parser
func (t TimeFormat) Parse(d []string) error {
	pt, err := time.Parse(t.Format, d[0])
	if err != nil {
		*t.Data = pt
	}
	return err
}

// Errors

// OutsideBounds is an error returned from a Parser when the parsed value falls
// outside of the range given as an acceptable value
type OutsideBounds string

func (OutsideBounds) Error() string {
	return "value received was outside of specified bounds"
}

// NoRegexMatch is an error returned from RegexString.Parse when the given
// string does not match the given regular expression
type NoRegexMatch string

func (NoRegexMatch) Error() string {
	return "string did not match given regular expression"
}

// UnknownFormat is an error returned from Time.Parse when it cannot determine
// the time format of the given string
type UnknownFormat string

func (UnknownFormat) Error() string {
	return "unknown time format"
}
<commit_msg>Added RequiredString<commit_after>package form

import (
	"regexp"
	"strconv"
	"strings"
	"time"
)

// Bool is a bool that implements Parser
type Bool struct {
	Data *bool
}

// Parse is an implementation of Parser
func (b Bool) Parse(d []string) error {
	switch strings.ToLower(d[0]) {
	case "on", "yes", "y":
		*b.Data = true
	case "off", "no", "n":
		*b.Data = false
	default:
		c, err := strconv.ParseBool(d[0])
		*b.Data = c
		return err
	}
	return nil
}

// Int is an int that implements Parser
type Int struct {
	Data *int
}

// Parse is an implementation of Parser
func (i Int) Parse(d []string) error {
	n, err := strconv.ParseInt(d[0], 10, 0)
	*i.Data = int(n)
	return err
}

// Int8 is an int8 that implements Parser
type Int8 struct {
	Data *int8
}

// Parse is an implementation of Parser
func (i Int8) Parse(d []string) error {
	n, err := strconv.ParseInt(d[0], 10, 8)
	*i.Data = int8(n)
	return err
}

// Int16 is an int16 that implements Parser
type Int16 struct {
	Data *int16
}

// Parse is an implementation of Parser
func (i Int16) Parse(d []string) error {
	n, err := strconv.ParseInt(d[0], 10, 16)
	*i.Data = int16(n)
	return err
}

// Int32 is an int32 that implements Parser
type Int32 struct {
	Data *int32
}

// Parse is an implementation of Parser
func (i Int32) Parse(d []string) error {
	n, err := strconv.ParseInt(d[0], 10, 32)
	*i.Data = int32(n)
	return err
}

// Int64 is an int64 that implements Parser
type Int64 struct {
	Data *int64
}

// Parse is an implementation of Parser
func (i Int64) Parse(d []string) error {
	n, err := strconv.ParseInt(d[0], 10, 64)
	*i.Data = n
	return err
}

// IntBetween is an implementation of Parser that allows a signed integer
// between the Min and Max (inclusively)
type IntBetween struct {
	Parser
	Min, Max int64
}

// Parse is an implementation of Parser
func (i IntBetween) Parse(d []string) error {
	n, err := strconv.ParseInt(d[0], 10, 64)
	if err != nil {
		return err
	}
	if n >= i.Min && n <= i.Max {
		return i.Parser.Parse(d)
	}
	return OutsideBounds(d[0])
}

// Uint is a uint that implements Parser
type Uint struct {
	Data *uint
}

// Parse is an implementation of Parser
func (u Uint) Parse(d []string) error {
	n, err := strconv.ParseUint(d[0], 10, 0)
	*u.Data = uint(n)
	return err
}

// Uint8 is a uint8 that implements Parser
type Uint8 struct {
	Data *uint8
}

// Parse is an implementation of Parser
func (u Uint8) Parse(d []string) error {
	n, err := strconv.ParseUint(d[0], 10, 8)
	*u.Data = uint8(n)
	return err
}

// Uint16 is a uint16 that implements Parser
type Uint16 struct {
	Data *uint16
}

// Parse is an implementation of Parser
func (u Uint16) Parse(d []string) error {
	n, err := strconv.ParseUint(d[0], 10, 16)
	*u.Data = uint16(n)
	return err
}

// Uint32 is a uint32 that implements Parser
type Uint32 struct {
	Data *uint32
}

// Parse is an implementation of Parser
func (u Uint32) Parse(d []string) error {
	n, err := strconv.ParseUint(d[0], 10, 32)
	*u.Data = uint32(n)
	return err
}

// Uint64 is a uint64 that implements Parser
type Uint64 struct {
	Data *uint64
}

// Parse is an implementation of Parser
func (u Uint64) Parse(d []string) error {
	n, err := strconv.ParseUint(d[0], 10, 64)
	*u.Data = n
	return err
}

// UintBetween is an implementation of Parser that allows an unsigned integer
// between the Min and Max (inclusively)
type UintBetween struct {
	Parser
	Min, Max uint64
}

// Parse is an implementation of Parser
func (u UintBetween) Parse(d []string) error {
	n, err := strconv.ParseUint(d[0], 10, 64)
	if err != nil {
		return err
	}
	if n >= u.Min && n <= u.Max {
		return u.Parser.Parse(d)
	}
	return OutsideBounds(d[0])
}

// Float32 is a float32 that implements Parser
type Float32 struct {
	Data *float32
}

// Parse is an implementation of Parser
func (f Float32) Parse(d []string) error {
	n, err := strconv.ParseFloat(d[0], 32)
	*f.Data = float32(n)
	return err
}

// Float64 is a float64 that implements Parser
type Float64 struct {
	Data *float64
}

// Parse is an implementation of Parser
func (f Float64) Parse(d []string) error {
	n, err := strconv.ParseFloat(d[0], 64)
	*f.Data = n
	return err
}

// FloatBetween is an implementation of Parser that allows a float between the
// Min and Max (inclusively)
type FloatBetween struct {
	Parser
	Min, Max float64
}

// Parse is an implementation of Parser
func (f FloatBetween) Parse(d []string) error {
	n, err := strconv.ParseFloat(d[0], 64)
	if err != nil {
		return err
	}
	if n >= f.Min && n <= f.Max {
		return f.Parser.Parse(d)
	}
	return OutsideBounds(d[0])
}

// String is a string that implements Parser
type String struct {
	Data *string
}

// Parse is an implementation of Parser
func (s String) Parse(d []string) error {
	*s.Data = d[0]
	return nil
}

// RegexString is an implementation of Parser that matches a string again the
// given regular expression
type RegexString struct {
	Data  *string
	Regex *regexp.Regexp
}

// Parse is an implementation of Parser
func (r RegexString) Parse(d []string) error {
	if r.Regex.MatchString(d[0]) {
		*s.Data = d[0]
		return nil
	}
	return NoRegexMatch(d[0])
}

type RequiredString String

func (r RequiredString) Parse(d []string) error {
	if d[0] == "" {
		return Empty{}
	}
	*s.Data = d[0]
}

var formats = [...]string{
	time.ANSIC,
	time.Kitchen,
	time.RFC1123,
	time.RFC1123Z,
	time.RFC3339,
	time.RFC3339Nano,
	time.RFC822,
	time.RFC822Z,
	time.RFC850,
	time.RubyDate,
	time.Stamp,
	time.StampNano,
	time.StampMicro,
	time.StampMilli,
	time.UnixDate,
	"2/1/06 15:04:05",
	"2/1/2006 15:04:05",
	"02/01/06 15:04:05",
	"02/01/2006 15:04:05",
	"2/1/06 15:04",
	"2/1/2006 15:04",
	"02/01/06 15:04",
	"02/01/2006 15:04",
	"15:04:05 2/1/06",
	"15:04:05 2/1/2006",
	"15:04:05 02/01/06",
	"15:04:05 02/01/2006",
	"15:04 2/1/06",
	"15:04 2/1/2006",
	"15:04 02/01/06",
	"15:04 02/01/2006",
	"2-1-06 15:04:05",
	"2-1-2006 15:04:05",
	"02-01-06 15:04:05",
	"02-01-2006 15:04:05",
	"2-1-06 15:04",
	"2-1-2006 15:04",
	"02-01-06 15:04",
	"02-01-2006 15:04",
	"15:04:05 2-1-06",
	"15:04:05 2-1-2006",
	"15:04:05 02-01-06",
	"15:04:05 02-01-2006",
	"15:04 2-1-06",
	"15:04 2-1-2006",
	"15:04 02-01-06",
	"15:04 02-01-2006",
}

// Time is a time.Time that implements Parser
type Time struct {
	Data *time.Time
}

// Parse is an implementation of Parser
func (t Time) Parse(d []string) error {
	for _, format := range formats {
		pt, err := time.Parse(format, d[0])
		if err == nil {
			*t.Data = pt
			return nil
		}
	}
	return UnknownFormat(d[0])
}

// TimeFormat is like a Time except that it allows a specific format to be
// specified
type TimeFormat struct {
	Data   *time.Time
	Format string
}

// Parse is an implementation of Parser
func (t TimeFormat) Parse(d []string) error {
	pt, err := time.Parse(t.Format, d[0])
	if err != nil {
		*t.Data = pt
	}
	return err
}

// Errors

// OutsideBounds is an error returned from a Parser when the parsed value falls
// outside of the range given as an acceptable value
type OutsideBounds string

func (OutsideBounds) Error() string {
	return "value received was outside of specified bounds"
}

// NoRegexMatch is an error returned from RegexString.Parse when the given
// string does not match the given regular expression
type NoRegexMatch string

func (NoRegexMatch) Error() string {
	return "string did not match given regular expression"
}

// Empty is returned when a field contains only an empty string and that is not
// allowed
type Empty struct{}

func (Empty) Error() string {
	return "field is empty"
}

// UnknownFormat is an error returned from Time.Parse when it cannot determine
// the time format of the given string
type UnknownFormat string

func (UnknownFormat) Error() string {
	return "unknown time format"
}
<|endoftext|>


<commit_before>package gotetra

type Particle struct {
	Xs [3]float64
	Vs [3]float64
	Id int64
}

type Header struct {
	Cosmo CosmologyHeader
	Count, TotalCount int64
	Mass, BoxSize float64
}

type CosmologyHeader struct {
	Z float64
	OmegaM float64
	OmegaL float64
	H100 float64
}
<commit_msg>Changes to Header fields.<commit_after>package gotetra

type Particle struct {
	Xs [3]float64
	Vs [3]float64
	Id int64
}

type Header struct {
	Cosmo CosmologyHeader
	// particle info
	Mass float64
	Count, TotalCount int64
	// binning info
	Idx, GridWidth int64
	Width, TotalWidth float64
}

type CosmologyHeader struct {
	Z float64
	OmegaM float64
	OmegaL float64
	H100 float64
}
<|endoftext|>


<commit_before>// Functions for the last mile of a fiddle, i.e. writing out
// draw.cpp and then calling fiddle_run to compile and execute
// the code.
package runner

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

	"go.skia.org/infra/go/sklog"

	"go.skia.org/infra/fiddle/go/linenumbers"
	"go.skia.org/infra/fiddle/go/types"
	"go.skia.org/infra/go/exec"
	"go.skia.org/infra/go/git/gitinfo"
	"go.skia.org/infra/go/util"
)

const (
	// PREFIX is a format string for the code that makes it compilable.
	PREFIX = `#include "fiddle_main.h"
DrawOptions GetDrawOptions() {
  static const char *path = %s; // Either a string, or 0.
  return DrawOptions(%d, %d, true, true, %v, %v, %v, %v, %v, path);
}

%s
`
)

// prepCodeToCompile adds the line numbers and the right prefix code
// to the fiddle so it compiles and links correctly.
//
//    fiddleRoot - The root of the fiddle working directory. See DESIGN.md.
//    code - The code to compile.
//    opts - The user's options about how to run that code.
//
// Returns the prepped code.
func prepCodeToCompile(fiddleRoot, code string, opts *types.Options) string {
	code = linenumbers.LineNumbers(code)
	sourceImage := "0"
	if opts.Source != 0 {
		filename := fmt.Sprintf("%d.png", opts.Source)
		sourceImage = fmt.Sprintf("%q", filepath.Join(fiddleRoot, "images", filename))
	}
	pdf := true
	skp := true
	if opts.Animated {
		pdf = false
		skp = false
	}
	return fmt.Sprintf(PREFIX, sourceImage, opts.Width, opts.Height, pdf, skp, opts.SRGB, opts.F16, opts.TextOnly, code)
}

// ValidateOptions validates that the options make sense.
func ValidateOptions(opts *types.Options) error {
	if opts.Animated {
		if opts.Duration <= 0 {
			return fmt.Errorf("Animation duration must be > 0.")
		}
		if opts.Duration > 60 {
			return fmt.Errorf("Animation duration must be < 60s.")
		}
	} else {
		opts.Duration = 0
	}
	return nil
}

// WriteDrawCpp takes the given code, modifies it so that it can be compiled
// and then writes the "draw.cpp" file to the correct location, based on
// 'local'.
//
//    fiddleRoot - The root of the fiddle working directory. See DESIGN.md.
//    code - The code to compile.
//    opts - The user's options about how to run that code.
//    local - If true then we are running locally, so write the code to
//        fiddleRoot/src/draw.cpp.
//
// Returns a temp directory. Depending on 'local' this is where the 'draw.cpp' file was written.
func WriteDrawCpp(checkout, fiddleRoot, code string, opts *types.Options) (string, error) {
	code = prepCodeToCompile(fiddleRoot, code, opts)
	dstDir := filepath.Join(fiddleRoot, "src")
	var err error
	tmpDir := filepath.Join(fiddleRoot, "tmp")
	if err := os.MkdirAll(tmpDir, os.ModePerm); err != nil && err != os.ErrExist {
		return "", fmt.Errorf("Failed to create temp dir for draw.cpp: %s", err)
	}
	dstDir, err = ioutil.TempDir(tmpDir, "code")
	sklog.Infof("Created tmp dir: %s %s", dstDir, err)
	if err != nil {
		return "", fmt.Errorf("Failed to create temp dir for draw.cpp: %s", err)
	}

	drawPath := filepath.Join(dstDir, "upper", "skia", "tools", "fiddle")
	if err := os.MkdirAll(drawPath, 0755); err != nil {
		return dstDir, fmt.Errorf("failed to create dir %q: %s", drawPath, err)
	}

	sklog.Infof("About to write to: %s", drawPath)
	w, err := os.Create(filepath.Join(drawPath, "draw.cpp"))
	sklog.Infof("Create: %v %v", *w, err)
	if err != nil {
		return dstDir, fmt.Errorf("Failed to open destination: %s", err)
	}
	defer util.Close(w)
	_, err = w.Write([]byte(code))
	if err != nil {
		return dstDir, fmt.Errorf("Failed to write draw.cpp file: %s", err)
	}
	return dstDir, nil
}

// GitHashTimeStamp finds the timestamp, in UTC, of the given checkout of Skia under fiddleRoot.
//
//    fiddleRoot - The root of the fiddle working directory. See DESIGN.md.
//    gitHash - The git hash of the version of Skia we have checked out.
//
// Returns the timestamp of the git commit in UTC.
func GitHashTimeStamp(fiddleRoot, gitHash string) (time.Time, error) {
	g, err := gitinfo.NewGitInfo(filepath.Join(fiddleRoot, "versions", gitHash), false, false)
	if err != nil {
		return time.Time{}, fmt.Errorf("Failed to create gitinfo: %s", err)
	}
	commit, err := g.Details(gitHash, false)
	if err != nil {
		return time.Time{}, fmt.Errorf("Failed to retrieve info on the git commit %s: %s", gitHash, err)
	}
	return commit.Timestamp.In(time.UTC), nil
}

// Run executes fiddle_run and then parses the JSON output into types.Results.
//
//    fiddleRoot - The root of the fiddle working directory. See DESIGN.md.
//    gitHash - The git hash of the version of Skia we have checked out.
//    local - Boolean, true if we are running locally, else we should execute
//        fiddle_run under fiddle_secwrap.
//    tmpDir - The directory outside the container to mount as FIDDLE_ROOT/src
//        that contains the user's draw.cpp file. Only used if local is false.
//
// Returns the parsed JSON that fiddle_run emits to stdout.
//
// If non-local this should run something like:
//
// sudo systemd-nspawn -D /mnt/pd0/container/ --read-only --private-network
//  --machine foo
//  --overlay=/mnt/pd0/fiddle:/tmp:/mnt/pd0/fiddle
//  --bind-ro /tmp/draw.cpp:/mnt/pd0/fiddle/versions/d6dd44140d8dd6d18aba1dfe9edc5582dcd73d2f/tools/fiddle/draw.cpp
//  xargs --arg-file=/dev/null \
//    /mnt/pd0/fiddle/bin/fiddle_run \
//    --fiddle_root /mnt/pd0/fiddle \
//    --git_hash 5280dcbae3affd73be5d5e0ff3db8823e26901e6 \
//    --alsologtostderr
//
// OVERLAY
//    The use of --overlay=/mnt/pd0/fiddle:/tmp:/mnt/pd0/fiddle sets up an interesting directory
//    /mnt/pd0/fiddle in the container, where the entire contents of the host's
//    /mnt/pd0/fiddle is available read-only, and if the container tries to write
//    to any files there, or create new files, they end up in /tmp and the first
//    directory stays untouched. See https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt
//    and the documentation for the --overlay flag of systemd-nspawn.
//
// Why xargs?
//    When trying to run a binary that exists on a mounted directory under nspawn, it will fail with:
//
//    $ sudo systemd-nspawn -D /mnt/pd0/container/ --bind=/mnt/pd0/fiddle /mnt/pd0/fiddle/bin/fiddle_run
//    Directory /mnt/pd0/container lacks the binary to execute or doesn't look like a binary tree. Refusing.
//
// That's because nspawn is looking for the exe before doing the bindings. The
// fix? A pure hack, insert "xargs --arg-file=/dev/null " before the command
// you want to run. Since xargs exists in the container this will proceed to
// the point of making the bindings and then xargs will be able to execute the
// exe within the container.
//
func Run(checkout, fiddleRoot, depotTools, gitHash string, local bool, tmpDir string, opts *types.Options) (*types.Result, error) {
	/*
		Do the equivalent of the following bash script that creates the overlayfs
		mount.

			#!/bin/bash

			set -e -x

			RUNID=runid2222
			GITHASH=c34a946d5a975ba8b8cd51f79b55174a5ec0f99f
			FIDDLE_ROOT=/usr/local/google/home/jcgregorio/projects/temp
			TMP_DIR=${FIDDLE_ROOT}/tmp/${RUNID}

			mkdir --parents ${TMP_DIR}/upper/skia/tools/fiddle
			mkdir ${TMP_DIR}/work
			mkdir ${TMP_DIR}/overlay
			cp ${TMP_DIR}/draw.cpp ${TMP_DIR}/upper/skia/tools/fiddle/draw.cpp

			LOWER=${FIDDLE_ROOT}/versions/${GITHASH}
			UPPER=${TMP_DIR}/upper
			WORK=${TMP_DIR}/work
			OVERLAY=${TMP_DIR}/overlay

			sudo mount -t overlay -o lowerdir=$LOWER,upperdir=$UPPER,workdir=$WORK none ${OVERLAY}

	*/
	upper := filepath.Join(tmpDir, "upper")
	work := filepath.Join(tmpDir, "work")
	overlay := filepath.Join(tmpDir, "overlay")
	lower := filepath.Join(fiddleRoot, "versions", gitHash)
	if err := os.MkdirAll(upper, 0755); err != nil {
		return nil, fmt.Errorf("fiddle_run failed to create dir %q: %s", upper, err)
	}
	if err := os.MkdirAll(work, 0755); err != nil {
		return nil, fmt.Errorf("fiddle_run failed to create dir %q: %s", work, err)
	}
	if err := os.MkdirAll(overlay, 0755); err != nil {
		return nil, fmt.Errorf("fiddle_run failed to create dir %q: %s", overlay, err)
	}
	mounttype := "overlay"
	if local {
		mounttype = "overlayfs"
	}
	name := "sudo"
	args := []string{
		"mount", "-t", mounttype,
		"-o",
		fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lower, upper, work),
		"none",
		overlay,
	}
	output := &bytes.Buffer{}
	mountCmd := &exec.Command{
		Name:      name,
		Args:      args,
		LogStderr: true,
		Stdout:    output,
	}
	if err := exec.Run(mountCmd); err != nil {
		return nil, fmt.Errorf("mount failed to run %#v: %s", *mountCmd, err)
	}

	// Queue up the umount in a defer.
	defer func() {
		name = "sudo"
		args = []string{
			"umount", overlay,
		}
		output = &bytes.Buffer{}
		umountCmd := &exec.Command{
			Name:      name,
			Args:      args,
			LogStderr: true,
			Stdout:    output,
		}

		if err := exec.Run(umountCmd); err != nil {
			sklog.Errorf("umount failed to run %#v: %s", *umountCmd, err)
		}
	}()

	// Run fiddle_run.
	name = filepath.Join(fiddleRoot, "bin", "fiddle_run")
	if local {
		name = "fiddle_run"
	}
	args = []string{"--fiddle_root", fiddleRoot, "--checkout", overlay, "--git_hash", gitHash, "--alsologtostderr"}
	args = append(args, "--duration", fmt.Sprintf("%f", opts.Duration))
	if local {
		args = append(args, "--local")
	}
	output = &bytes.Buffer{}
	runCmd := &exec.Command{
		Name:      name,
		Args:      args,
		LogStderr: true,
		Stdout:    output,
	}
	if err := exec.Run(runCmd); err != nil {
		return nil, fmt.Errorf("fiddle_run failed to run %#v: %s", *runCmd, err)
	}

	// Parse the output into types.Result.
	res := &types.Result{}
	if err := json.Unmarshal(output.Bytes(), res); err != nil {
		sklog.Errorf("Received erroneous output: %q", output.String())
		return nil, fmt.Errorf("Failed to decode results from run: %s", err)
	}
	return res, nil
}
<commit_msg>[fiddle] Track the run failures.<commit_after>// Functions for the last mile of a fiddle, i.e. writing out
// draw.cpp and then calling fiddle_run to compile and execute
// the code.
package runner

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

	"go.skia.org/infra/go/metrics2"
	"go.skia.org/infra/go/sklog"

	"go.skia.org/infra/fiddle/go/linenumbers"
	"go.skia.org/infra/fiddle/go/types"
	"go.skia.org/infra/go/exec"
	"go.skia.org/infra/go/git/gitinfo"
	"go.skia.org/infra/go/util"
)

const (
	// PREFIX is a format string for the code that makes it compilable.
	PREFIX = `#include "fiddle_main.h"
DrawOptions GetDrawOptions() {
  static const char *path = %s; // Either a string, or 0.
  return DrawOptions(%d, %d, true, true, %v, %v, %v, %v, %v, path);
}

%s
`
)

var (
	runTotal    = metrics2.GetCounter("run-total", nil)
	runFailures = metrics2.GetCounter("run-failures", nil)
)

// prepCodeToCompile adds the line numbers and the right prefix code
// to the fiddle so it compiles and links correctly.
//
//    fiddleRoot - The root of the fiddle working directory. See DESIGN.md.
//    code - The code to compile.
//    opts - The user's options about how to run that code.
//
// Returns the prepped code.
func prepCodeToCompile(fiddleRoot, code string, opts *types.Options) string {
	code = linenumbers.LineNumbers(code)
	sourceImage := "0"
	if opts.Source != 0 {
		filename := fmt.Sprintf("%d.png", opts.Source)
		sourceImage = fmt.Sprintf("%q", filepath.Join(fiddleRoot, "images", filename))
	}
	pdf := true
	skp := true
	if opts.Animated {
		pdf = false
		skp = false
	}
	return fmt.Sprintf(PREFIX, sourceImage, opts.Width, opts.Height, pdf, skp, opts.SRGB, opts.F16, opts.TextOnly, code)
}

// ValidateOptions validates that the options make sense.
func ValidateOptions(opts *types.Options) error {
	if opts.Animated {
		if opts.Duration <= 0 {
			return fmt.Errorf("Animation duration must be > 0.")
		}
		if opts.Duration > 60 {
			return fmt.Errorf("Animation duration must be < 60s.")
		}
	} else {
		opts.Duration = 0
	}
	return nil
}

// WriteDrawCpp takes the given code, modifies it so that it can be compiled
// and then writes the "draw.cpp" file to the correct location, based on
// 'local'.
//
//    fiddleRoot - The root of the fiddle working directory. See DESIGN.md.
//    code - The code to compile.
//    opts - The user's options about how to run that code.
//    local - If true then we are running locally, so write the code to
//        fiddleRoot/src/draw.cpp.
//
// Returns a temp directory. Depending on 'local' this is where the 'draw.cpp' file was written.
func WriteDrawCpp(checkout, fiddleRoot, code string, opts *types.Options) (string, error) {
	code = prepCodeToCompile(fiddleRoot, code, opts)
	dstDir := filepath.Join(fiddleRoot, "src")
	var err error
	tmpDir := filepath.Join(fiddleRoot, "tmp")
	if err := os.MkdirAll(tmpDir, os.ModePerm); err != nil && err != os.ErrExist {
		return "", fmt.Errorf("Failed to create temp dir for draw.cpp: %s", err)
	}
	dstDir, err = ioutil.TempDir(tmpDir, "code")
	sklog.Infof("Created tmp dir: %s %s", dstDir, err)
	if err != nil {
		return "", fmt.Errorf("Failed to create temp dir for draw.cpp: %s", err)
	}

	drawPath := filepath.Join(dstDir, "upper", "skia", "tools", "fiddle")
	if err := os.MkdirAll(drawPath, 0755); err != nil {
		return dstDir, fmt.Errorf("failed to create dir %q: %s", drawPath, err)
	}

	sklog.Infof("About to write to: %s", drawPath)
	w, err := os.Create(filepath.Join(drawPath, "draw.cpp"))
	sklog.Infof("Create: %v %v", *w, err)
	if err != nil {
		return dstDir, fmt.Errorf("Failed to open destination: %s", err)
	}
	defer util.Close(w)
	_, err = w.Write([]byte(code))
	if err != nil {
		return dstDir, fmt.Errorf("Failed to write draw.cpp file: %s", err)
	}
	return dstDir, nil
}

// GitHashTimeStamp finds the timestamp, in UTC, of the given checkout of Skia under fiddleRoot.
//
//    fiddleRoot - The root of the fiddle working directory. See DESIGN.md.
//    gitHash - The git hash of the version of Skia we have checked out.
//
// Returns the timestamp of the git commit in UTC.
func GitHashTimeStamp(fiddleRoot, gitHash string) (time.Time, error) {
	g, err := gitinfo.NewGitInfo(filepath.Join(fiddleRoot, "versions", gitHash), false, false)
	if err != nil {
		return time.Time{}, fmt.Errorf("Failed to create gitinfo: %s", err)
	}
	commit, err := g.Details(gitHash, false)
	if err != nil {
		return time.Time{}, fmt.Errorf("Failed to retrieve info on the git commit %s: %s", gitHash, err)
	}
	return commit.Timestamp.In(time.UTC), nil
}

// Run executes fiddle_run and then parses the JSON output into types.Results.
//
//    fiddleRoot - The root of the fiddle working directory. See DESIGN.md.
//    gitHash - The git hash of the version of Skia we have checked out.
//    local - Boolean, true if we are running locally, else we should execute
//        fiddle_run under fiddle_secwrap.
//    tmpDir - The directory outside the container to mount as FIDDLE_ROOT/src
//        that contains the user's draw.cpp file. Only used if local is false.
//
// Returns the parsed JSON that fiddle_run emits to stdout.
//
// If non-local this should run something like:
//
// sudo systemd-nspawn -D /mnt/pd0/container/ --read-only --private-network
//  --machine foo
//  --overlay=/mnt/pd0/fiddle:/tmp:/mnt/pd0/fiddle
//  --bind-ro /tmp/draw.cpp:/mnt/pd0/fiddle/versions/d6dd44140d8dd6d18aba1dfe9edc5582dcd73d2f/tools/fiddle/draw.cpp
//  xargs --arg-file=/dev/null \
//    /mnt/pd0/fiddle/bin/fiddle_run \
//    --fiddle_root /mnt/pd0/fiddle \
//    --git_hash 5280dcbae3affd73be5d5e0ff3db8823e26901e6 \
//    --alsologtostderr
//
// OVERLAY
//    The use of --overlay=/mnt/pd0/fiddle:/tmp:/mnt/pd0/fiddle sets up an interesting directory
//    /mnt/pd0/fiddle in the container, where the entire contents of the host's
//    /mnt/pd0/fiddle is available read-only, and if the container tries to write
//    to any files there, or create new files, they end up in /tmp and the first
//    directory stays untouched. See https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt
//    and the documentation for the --overlay flag of systemd-nspawn.
//
// Why xargs?
//    When trying to run a binary that exists on a mounted directory under nspawn, it will fail with:
//
//    $ sudo systemd-nspawn -D /mnt/pd0/container/ --bind=/mnt/pd0/fiddle /mnt/pd0/fiddle/bin/fiddle_run
//    Directory /mnt/pd0/container lacks the binary to execute or doesn't look like a binary tree. Refusing.
//
// That's because nspawn is looking for the exe before doing the bindings. The
// fix? A pure hack, insert "xargs --arg-file=/dev/null " before the command
// you want to run. Since xargs exists in the container this will proceed to
// the point of making the bindings and then xargs will be able to execute the
// exe within the container.
//
func Run(checkout, fiddleRoot, depotTools, gitHash string, local bool, tmpDir string, opts *types.Options) (*types.Result, error) {
	/*
		Do the equivalent of the following bash script that creates the overlayfs
		mount.

			#!/bin/bash

			set -e -x

			RUNID=runid2222
			GITHASH=c34a946d5a975ba8b8cd51f79b55174a5ec0f99f
			FIDDLE_ROOT=/usr/local/google/home/jcgregorio/projects/temp
			TMP_DIR=${FIDDLE_ROOT}/tmp/${RUNID}

			mkdir --parents ${TMP_DIR}/upper/skia/tools/fiddle
			mkdir ${TMP_DIR}/work
			mkdir ${TMP_DIR}/overlay
			cp ${TMP_DIR}/draw.cpp ${TMP_DIR}/upper/skia/tools/fiddle/draw.cpp

			LOWER=${FIDDLE_ROOT}/versions/${GITHASH}
			UPPER=${TMP_DIR}/upper
			WORK=${TMP_DIR}/work
			OVERLAY=${TMP_DIR}/overlay

			sudo mount -t overlay -o lowerdir=$LOWER,upperdir=$UPPER,workdir=$WORK none ${OVERLAY}

	*/
	runTotal.Inc(1)
	upper := filepath.Join(tmpDir, "upper")
	work := filepath.Join(tmpDir, "work")
	overlay := filepath.Join(tmpDir, "overlay")
	lower := filepath.Join(fiddleRoot, "versions", gitHash)
	if err := os.MkdirAll(upper, 0755); err != nil {
		return nil, fmt.Errorf("fiddle_run failed to create dir %q: %s", upper, err)
	}
	if err := os.MkdirAll(work, 0755); err != nil {
		return nil, fmt.Errorf("fiddle_run failed to create dir %q: %s", work, err)
	}
	if err := os.MkdirAll(overlay, 0755); err != nil {
		return nil, fmt.Errorf("fiddle_run failed to create dir %q: %s", overlay, err)
	}
	mounttype := "overlay"
	if local {
		mounttype = "overlayfs"
	}
	name := "sudo"
	args := []string{
		"mount", "-t", mounttype,
		"-o",
		fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lower, upper, work),
		"none",
		overlay,
	}
	output := &bytes.Buffer{}
	mountCmd := &exec.Command{
		Name:      name,
		Args:      args,
		LogStderr: true,
		Stdout:    output,
	}
	if err := exec.Run(mountCmd); err != nil {
		return nil, fmt.Errorf("mount failed to run %#v: %s", *mountCmd, err)
	}

	// Queue up the umount in a defer.
	defer func() {
		name = "sudo"
		args = []string{
			"umount", overlay,
		}
		output = &bytes.Buffer{}
		umountCmd := &exec.Command{
			Name:      name,
			Args:      args,
			LogStderr: true,
			Stdout:    output,
		}

		if err := exec.Run(umountCmd); err != nil {
			sklog.Errorf("umount failed to run %#v: %s", *umountCmd, err)
		}
	}()

	// Run fiddle_run.
	name = filepath.Join(fiddleRoot, "bin", "fiddle_run")
	if local {
		name = "fiddle_run"
	}
	args = []string{"--fiddle_root", fiddleRoot, "--checkout", overlay, "--git_hash", gitHash, "--alsologtostderr"}
	args = append(args, "--duration", fmt.Sprintf("%f", opts.Duration))
	if local {
		args = append(args, "--local")
	}
	output = &bytes.Buffer{}
	runCmd := &exec.Command{
		Name:      name,
		Args:      args,
		LogStderr: true,
		Stdout:    output,
	}
	if err := exec.Run(runCmd); err != nil {
		runFailures.Inc(1)
		return nil, fmt.Errorf("fiddle_run failed to run %#v: %s", *runCmd, err)
	}

	// Parse the output into types.Result.
	res := &types.Result{}
	if err := json.Unmarshal(output.Bytes(), res); err != nil {
		sklog.Errorf("Received erroneous output: %q", output.String())
		return nil, fmt.Errorf("Failed to decode results from run: %s", err)
	}
	return res, nil
}
<|endoftext|>


<commit_before>package ebpf

//go:generate stringer -output types_string.go -type=MapType,ProgramType

// MapType indicates the type map structure
// that will be initialized in the kernel.
type MapType uint32

// All the various map types that can be created
const (
	UnspecifiedMap MapType = iota
	// Hash is a hash map
	Hash
	// Array is an array map
	Array
	// ProgramArray - A program array map is a special kind of array map whose map
	// values contain only file descriptors referring to other eBPF
	// programs.  Thus, both the key_size and value_size must be
	// exactly four bytes.  This map is used in conjunction with the
	// TailCall helper.
	ProgramArray
	// PerfEventArray - A perf event array is used in conjunction with PerfEventRead
	// and PerfEventOutput calls, to read the raw bpf_perf_data from the registers.
	PerfEventArray
	// PerCPUHash - This data structure is useful for people who have high performance
	// network needs and can reconcile adds at the end of some cycle, so that
	// hashes can be lock free without the use of XAdd, which can be costly.
	PerCPUHash
	// PerCPUArray - This data structure is useful for people who have high performance
	// network needs and can reconcile adds at the end of some cycle, so that
	// hashes can be lock free without the use of XAdd, which can be costly.
	// Each CPU gets a copy of this hash, the contents of all of which can be reconciled
	// later.
	PerCPUArray
	// StackTrace - This holds whole user and kernel stack traces, it can be retrieved with
	// GetStackID
	StackTrace
	// CGroupArray - This is a very niche structure used to help SKBInCGroup determine
	// if an skb is from a socket belonging to a specific cgroup
	CGroupArray
	// LRUHash - This allows you to create a small hash structure that will purge the
	// least recently used items rather than thow an error when you run out of memory
	LRUHash
	// LRUCPUHash - This is NOT like PerCPUHash, this structure is shared among the CPUs,
	// it has more to do with including the CPU id with the LRU calculation so that if a
	// particular CPU is using a value over-and-over again, then it will be saved, but if
	// a value is being retrieved a lot but sparsely across CPUs it is not as important, basically
	// giving weight to CPU locality over overall usage.
	LRUCPUHash
	// LPMTrie - This is an implementation of Longest-Prefix-Match Trie structure. It is useful,
	// for storing things like IP addresses which can be bit masked allowing for keys of differing
	// values to refer to the same reference based on their masks. See wikipedia for more details.
	LPMTrie
	// ArrayOfMaps - Each item in the array is another map. The inner map mustn't be a map of maps
	// itself.
	ArrayOfMaps
	// HashOfMaps - Each item in the hash map is another map. The inner map mustn't be a map of maps
	// itself.
	HashOfMaps
)

// hasPerCPUValue returns true if the Map stores a value per CPU.
func (mt MapType) hasPerCPUValue() bool {
	if mt == PerCPUHash || mt == PerCPUArray {
		return true
	}
	return false
}

const (
	_MapCreate = iota
	_MapLookupElem
	_MapUpdateElem
	_MapDeleteElem
	_MapGetNextKey
	_ProgLoad
	_ObjPin
	_ObjGet
	_ProgAttach
	_ProgDetach
	_ProgTestRun
	_ProgGetNextID
	_MapGetNextID
	_ProgGetFDByID
	_MapGetFDByID
	_ObjGetInfoByFD
	_ProgQuery
	_RawTracepointOpen
	_BTFLoad
	_BTFGetFDByID
	_TaskFDQuery
	_MapLookupAndDeleteElem
	_MapFreeze
)

const (
	_Any = iota
	_NoExist
	_Exist
)

// ProgramType of the eBPF program
type ProgramType uint32

// eBPF program types
const (
	// Unrecognized program type
	UnspecifiedProgram ProgramType = iota
	// SocketFilter socket or seccomp filter
	SocketFilter
	// Kprobe program
	Kprobe
	// SchedCLS traffic control shaper
	SchedCLS
	// SchedACT routing control shaper
	SchedACT
	// TracePoint program
	TracePoint
	// XDP program
	XDP
	// PerfEvent program
	PerfEvent
	// CGroupSKB program
	CGroupSKB
	// CGroupSock program
	CGroupSock
	// LWTIn program
	LWTIn
	// LWTOut program
	LWTOut
	// LWTXmit program
	LWTXmit
	// SockOps program
	SockOps
	// SkSKB program
	SkSKB
	// CGroupDevice program
	CGroupDevice
	// SkMsg program
	SkMsg
	// RawTracepoint program
	RawTracepoint
	// CGroupSockAddr program
	CGroupSockAddr
	// LWTSeg6Local program
	LWTSeg6Local
	// LircMode2 program
	LircMode2
	// SkReuseport program
	SkReuseport
	// FlowDissector program
	FlowDissector
	// CGroupSysctl program
	CGroupSysctl
	// RawTracepointWritable program
	RawTracepointWritable
	// CGroupSockopt program
	CGroupSockopt
	// Tracing program
	Tracing
)

// AttachType of the eBPF program, needed to differentiate allowed context accesses in
// some newer program types like CGroupSockAddr. Should be set to AttachNone if not required.
// Will cause invalid argument (EINVAL) at program load time if set incorrectly.
type AttachType uint32

// AttachNone is an alias for AttachCGroupInetIngress for readability reasons
const AttachNone AttachType = 0

const (
	AttachCGroupInetIngress AttachType = iota
	AttachCGroupInetEgress
	AttachCGroupInetSockCreate
	AttachCGroupSockOps
	AttachSkSKBStreamParser
	AttachSkSKBStreamVerdict
	AttachCGroupDevice
	AttachSkMsgVerdict
	AttachCGroupInet4Bind
	AttachCGroupInet6Bind
	AttachCGroupInet4Connect
	AttachCGroupInet6Connect
	AttachCGroupInet4PostBind
	AttachCGroupInet6PostBind
	AttachCGroupUDP4Sendmsg
	AttachCGroupUDP6Sendmsg
	AttachLircMode2
	AttachFlowDissector
	AttachCGroupSysctl
	AttachCGroupUDP4Recvmsg
	AttachCGroupUDP6Recvmsg
	AttachCGroupGetsockopt
	AttachCGroupSetsockopt
	AttachTraceRawTp
	AttachTraceFEntry
	AttachTraceFExit
)

// AttachFlags of the eBPF program used in BPF_PROG_ATTACH command
type AttachFlags uint32
<commit_msg>ebpf: add map types<commit_after>package ebpf

//go:generate stringer -output types_string.go -type=MapType,ProgramType

// MapType indicates the type map structure
// that will be initialized in the kernel.
type MapType uint32

// All the various map types that can be created
const (
	UnspecifiedMap MapType = iota
	// Hash is a hash map
	Hash
	// Array is an array map
	Array
	// ProgramArray - A program array map is a special kind of array map whose map
	// values contain only file descriptors referring to other eBPF
	// programs.  Thus, both the key_size and value_size must be
	// exactly four bytes.  This map is used in conjunction with the
	// TailCall helper.
	ProgramArray
	// PerfEventArray - A perf event array is used in conjunction with PerfEventRead
	// and PerfEventOutput calls, to read the raw bpf_perf_data from the registers.
	PerfEventArray
	// PerCPUHash - This data structure is useful for people who have high performance
	// network needs and can reconcile adds at the end of some cycle, so that
	// hashes can be lock free without the use of XAdd, which can be costly.
	PerCPUHash
	// PerCPUArray - This data structure is useful for people who have high performance
	// network needs and can reconcile adds at the end of some cycle, so that
	// hashes can be lock free without the use of XAdd, which can be costly.
	// Each CPU gets a copy of this hash, the contents of all of which can be reconciled
	// later.
	PerCPUArray
	// StackTrace - This holds whole user and kernel stack traces, it can be retrieved with
	// GetStackID
	StackTrace
	// CGroupArray - This is a very niche structure used to help SKBInCGroup determine
	// if an skb is from a socket belonging to a specific cgroup
	CGroupArray
	// LRUHash - This allows you to create a small hash structure that will purge the
	// least recently used items rather than thow an error when you run out of memory
	LRUHash
	// LRUCPUHash - This is NOT like PerCPUHash, this structure is shared among the CPUs,
	// it has more to do with including the CPU id with the LRU calculation so that if a
	// particular CPU is using a value over-and-over again, then it will be saved, but if
	// a value is being retrieved a lot but sparsely across CPUs it is not as important, basically
	// giving weight to CPU locality over overall usage.
	LRUCPUHash
	// LPMTrie - This is an implementation of Longest-Prefix-Match Trie structure. It is useful,
	// for storing things like IP addresses which can be bit masked allowing for keys of differing
	// values to refer to the same reference based on their masks. See wikipedia for more details.
	LPMTrie
	// ArrayOfMaps - Each item in the array is another map. The inner map mustn't be a map of maps
	// itself.
	ArrayOfMaps
	// HashOfMaps - Each item in the hash map is another map. The inner map mustn't be a map of maps
	// itself.
	HashOfMaps
	// DevMap - Specialized map to store references to network devices.
	DevMap
	// SockMap - Specialized map to store references to sockets.
	SockMap
	// CPUMap - Specialized map to store references to CPUs.
	CPUMap
	// XSKMap - Specialized map for XDP programs to store references to open sockets.
	XSKMap
	// SockHash - Specialized hash to store references to sockets.
	SockHash
	// CGroupStorage - Special map for CGroups.
	CGroupStorage
	// ReusePortSockArray - Specialized map to store references to sockets that can be reused.
	ReusePortSockArray
	// PerCPUCGroupStorage - Special per CPU map for CGroups.
	PerCPUCGroupStorage
	// Queue - FIFO storage for BPF programs.
	Queue
	// Stack - LIFO storage for BPF programs.
	Stack
	// SkStorage - Specialized map for local storage at SK for BPF programs.
	SkStorage
	// DevMapHash - Hash-based indexing scheme for references to network devices.
	DevMapHash
)

// hasPerCPUValue returns true if the Map stores a value per CPU.
func (mt MapType) hasPerCPUValue() bool {
	if mt == PerCPUHash || mt == PerCPUArray {
		return true
	}
	return false
}

const (
	_MapCreate = iota
	_MapLookupElem
	_MapUpdateElem
	_MapDeleteElem
	_MapGetNextKey
	_ProgLoad
	_ObjPin
	_ObjGet
	_ProgAttach
	_ProgDetach
	_ProgTestRun
	_ProgGetNextID
	_MapGetNextID
	_ProgGetFDByID
	_MapGetFDByID
	_ObjGetInfoByFD
	_ProgQuery
	_RawTracepointOpen
	_BTFLoad
	_BTFGetFDByID
	_TaskFDQuery
	_MapLookupAndDeleteElem
	_MapFreeze
)

const (
	_Any = iota
	_NoExist
	_Exist
)

// ProgramType of the eBPF program
type ProgramType uint32

// eBPF program types
const (
	// Unrecognized program type
	UnspecifiedProgram ProgramType = iota
	// SocketFilter socket or seccomp filter
	SocketFilter
	// Kprobe program
	Kprobe
	// SchedCLS traffic control shaper
	SchedCLS
	// SchedACT routing control shaper
	SchedACT
	// TracePoint program
	TracePoint
	// XDP program
	XDP
	// PerfEvent program
	PerfEvent
	// CGroupSKB program
	CGroupSKB
	// CGroupSock program
	CGroupSock
	// LWTIn program
	LWTIn
	// LWTOut program
	LWTOut
	// LWTXmit program
	LWTXmit
	// SockOps program
	SockOps
	// SkSKB program
	SkSKB
	// CGroupDevice program
	CGroupDevice
	// SkMsg program
	SkMsg
	// RawTracepoint program
	RawTracepoint
	// CGroupSockAddr program
	CGroupSockAddr
	// LWTSeg6Local program
	LWTSeg6Local
	// LircMode2 program
	LircMode2
	// SkReuseport program
	SkReuseport
	// FlowDissector program
	FlowDissector
	// CGroupSysctl program
	CGroupSysctl
	// RawTracepointWritable program
	RawTracepointWritable
	// CGroupSockopt program
	CGroupSockopt
	// Tracing program
	Tracing
)

// AttachType of the eBPF program, needed to differentiate allowed context accesses in
// some newer program types like CGroupSockAddr. Should be set to AttachNone if not required.
// Will cause invalid argument (EINVAL) at program load time if set incorrectly.
type AttachType uint32

// AttachNone is an alias for AttachCGroupInetIngress for readability reasons
const AttachNone AttachType = 0

const (
	AttachCGroupInetIngress AttachType = iota
	AttachCGroupInetEgress
	AttachCGroupInetSockCreate
	AttachCGroupSockOps
	AttachSkSKBStreamParser
	AttachSkSKBStreamVerdict
	AttachCGroupDevice
	AttachSkMsgVerdict
	AttachCGroupInet4Bind
	AttachCGroupInet6Bind
	AttachCGroupInet4Connect
	AttachCGroupInet6Connect
	AttachCGroupInet4PostBind
	AttachCGroupInet6PostBind
	AttachCGroupUDP4Sendmsg
	AttachCGroupUDP6Sendmsg
	AttachLircMode2
	AttachFlowDissector
	AttachCGroupSysctl
	AttachCGroupUDP4Recvmsg
	AttachCGroupUDP6Recvmsg
	AttachCGroupGetsockopt
	AttachCGroupSetsockopt
	AttachTraceRawTp
	AttachTraceFEntry
	AttachTraceFExit
)

// AttachFlags of the eBPF program used in BPF_PROG_ATTACH command
type AttachFlags uint32
<|endoftext|>