<commit_before>package provisioning

import (
	"context"
	"log"
	"net"
	"net/url"
	"os"
	"path/filepath"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"

	"github.com/golang/protobuf/ptypes/empty"
	"github.com/n0stack/n0core/pkg/driver/iproute2"
	"github.com/n0stack/n0core/pkg/driver/qemu"
	"github.com/pkg/errors"
	uuid "github.com/satori/go.uuid"
)

var N0coreVirtualMachineNamespace uuid.UUID

const (
	QMPMonitorSocketFile   = "monitor.sock"
	VNCWebSocketPortOffset = 6900
)

func init() {
	N0coreVirtualMachineNamespace, _ = uuid.FromString("a015d18d-b2c3-4181-8028-6f707ef31c95")
}

type VirtualMachineAgentAPI struct {
	baseDirectory string
}

func CreateVirtualMachineAgentAPI(basedir string) (*VirtualMachineAgentAPI, error) {
	b, err := filepath.Abs(basedir)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to get absolute path")
	}

	if _, err := os.Stat(b); os.IsNotExist(err) {
		if err := os.MkdirAll(b, 0644); err != nil { // TODO: check permission
			return nil, errors.Wrapf(err, "Failed to mkdir '%s'", b)
		}
	}

	return &VirtualMachineAgentAPI{
		baseDirectory: b,
	}, nil
}

func (a VirtualMachineAgentAPI) GetWorkDirectory(name string) (string, error) {
	p := filepath.Join(a.baseDirectory, name)

	if _, err := os.Stat(p); os.IsNotExist(err) {
		if err := os.MkdirAll(p, 0644); err != nil { // TODO: check permission
			return p, errors.Wrapf(err, "Failed to mkdir '%s'", p)
		}
	}

	return p, nil
}

func (a VirtualMachineAgentAPI) CreateVirtualMachineAgent(ctx context.Context, req *CreateVirtualMachineAgentRequest) (*VirtualMachineAgent, error) {
	id := uuid.NewV5(N0coreVirtualMachineNamespace, req.Name)
	q, err := qemu.OpenQemu(&id)
	if err != nil {
		return nil, grpc.Errorf(codes.Internal, "Failed to open qemu process: %s", err.Error())
	}
	if q.IsRunning() {
		return nil, grpc.Errorf(codes.AlreadyExists, "")
	}

	wd, err := a.GetWorkDirectory(req.Name)
	if err != nil {
		return nil, grpc.Errorf(codes.Internal, "Failed to get working directory '%s'", wd)
	}
	websocket := qemu.GetNewListenPort(VNCWebSocketPortOffset)

	if err := q.Start(req.Name, filepath.Join(wd, QMPMonitorSocketFile), websocket, req.Vcpus, req.MemoryBytes); err != nil {
		log.Printf("Failed to start qemu process: err=%s", err.Error())
		return nil, grpc.Errorf(codes.Internal, "Failed to start qemu process")
	}

	for _, nd := range req.Netdev {
		b, err := iproute2.NewBridge(TrimNetdevName(nd.NetworkName))
		if err != nil {
			log.Printf("Failed to create bridge '%s': err='%s'", nd.NetworkName, err.Error())
			return nil, grpc.Errorf(codes.Internal, "") // TODO #89
		}

		t, err := iproute2.NewTap(TrimNetdevName(nd.Name))
		if err != nil {
			log.Printf("Failed to create tap '%s': err='%s'", nd.Name, err.Error())
			return nil, grpc.Errorf(codes.Internal, "") // TODO #89
		}
		if err := t.SetMaster(b); err != nil {
			log.Printf("Failed to set master of tap '%s' as '%s': err='%s'", t.Name(), b.Name(), err.Error())
			return nil, grpc.Errorf(codes.Internal, "") // TODO #89
		}

		hw, err := net.ParseMAC(nd.HardwareAddress)
		if err != nil {
			return nil, grpc.Errorf(codes.InvalidArgument, "Hardware address '%s' is invalid on netdev '%s'", nd.HardwareAddress, nd.Name)
		}

		if err := q.AttachTap(nd.Name, t.Name(), hw); err != nil {
			log.Printf("Failed to attach tap: err='%s'", err.Error())
			return nil, grpc.Errorf(codes.Internal, "Failed to attach tap")
		}
	}

	for _, bd := range req.Blockdev {
		u, err := url.Parse(bd.Url)
		if err != nil {
			return nil, grpc.Errorf(codes.InvalidArgument, "url '%s' is invalid url: '%s'", bd.Url, err.Error())
		}

		if err := q.AttachQcow2(bd.Name, u, uint(bd.BootIndex)); err != nil {
			log.Printf("Failed to attach image '%s': err='%s'", u.Path, err.Error())
			return nil, grpc.Errorf(codes.Internal, "") // TODO #89
		}<commit_msg>attach iso<commit_after>package provisioning

import (
	"context"
	"log"
	"net"
	"net/url"
	"os"
	"path/filepath"

	"github.com/n0stack/n0core/pkg/driver/qemu_img"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"

	"github.com/golang/protobuf/ptypes/empty"
	"github.com/n0stack/n0core/pkg/driver/iproute2"
	"github.com/n0stack/n0core/pkg/driver/qemu"
	"github.com/pkg/errors"
	uuid "github.com/satori/go.uuid"
)

var N0coreVirtualMachineNamespace uuid.UUID

const (
	QMPMonitorSocketFile   = "monitor.sock"
	VNCWebSocketPortOffset = 6900
)

func init() {
	N0coreVirtualMachineNamespace, _ = uuid.FromString("a015d18d-b2c3-4181-8028-6f707ef31c95")
}

type VirtualMachineAgentAPI struct {
	baseDirectory string
}

func CreateVirtualMachineAgentAPI(basedir string) (*VirtualMachineAgentAPI, error) {
	b, err := filepath.Abs(basedir)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to get absolute path")
	}

	if _, err := os.Stat(b); os.IsNotExist(err) {
		if err := os.MkdirAll(b, 0644); err != nil { // TODO: check permission
			return nil, errors.Wrapf(err, "Failed to mkdir '%s'", b)
		}
	}

	return &VirtualMachineAgentAPI{
		baseDirectory: b,
	}, nil
}

func (a VirtualMachineAgentAPI) GetWorkDirectory(name string) (string, error) {
	p := filepath.Join(a.baseDirectory, name)

	if _, err := os.Stat(p); os.IsNotExist(err) {
		if err := os.MkdirAll(p, 0644); err != nil { // TODO: check permission
			return p, errors.Wrapf(err, "Failed to mkdir '%s'", p)
		}
	}

	return p, nil
}

func (a VirtualMachineAgentAPI) CreateVirtualMachineAgent(ctx context.Context, req *CreateVirtualMachineAgentRequest) (*VirtualMachineAgent, error) {
	id := uuid.NewV5(N0coreVirtualMachineNamespace, req.Name)
	q, err := qemu.OpenQemu(&id)
	if err != nil {
		return nil, grpc.Errorf(codes.Internal, "Failed to open qemu process: %s", err.Error())
	}
	if q.IsRunning() {
		return nil, grpc.Errorf(codes.AlreadyExists, "")
	}

	wd, err := a.GetWorkDirectory(req.Name)
	if err != nil {
		return nil, grpc.Errorf(codes.Internal, "Failed to get working directory '%s'", wd)
	}
	websocket := qemu.GetNewListenPort(VNCWebSocketPortOffset)

	if err := q.Start(req.Name, filepath.Join(wd, QMPMonitorSocketFile), websocket, req.Vcpus, req.MemoryBytes); err != nil {
		log.Printf("Failed to start qemu process: err=%s", err.Error())
		return nil, grpc.Errorf(codes.Internal, "Failed to start qemu process")
	}

	for _, nd := range req.Netdev {
		b, err := iproute2.NewBridge(TrimNetdevName(nd.NetworkName))
		if err != nil {
			log.Printf("Failed to create bridge '%s': err='%s'", nd.NetworkName, err.Error())
			return nil, grpc.Errorf(codes.Internal, "") // TODO #89
		}

		t, err := iproute2.NewTap(TrimNetdevName(nd.Name))
		if err != nil {
			log.Printf("Failed to create tap '%s': err='%s'", nd.Name, err.Error())
			return nil, grpc.Errorf(codes.Internal, "") // TODO #89
		}
		if err := t.SetMaster(b); err != nil {
			log.Printf("Failed to set master of tap '%s' as '%s': err='%s'", t.Name(), b.Name(), err.Error())
			return nil, grpc.Errorf(codes.Internal, "") // TODO #89
		}

		hw, err := net.ParseMAC(nd.HardwareAddress)
		if err != nil {
			return nil, grpc.Errorf(codes.InvalidArgument, "Hardware address '%s' is invalid on netdev '%s'", nd.HardwareAddress, nd.Name)
		}

		if err := q.AttachTap(nd.Name, t.Name(), hw); err != nil {
			log.Printf("Failed to attach tap: err='%s'", err.Error())
			return nil, grpc.Errorf(codes.Internal, "Failed to attach tap")
		}
	}

	for _, bd := range req.Blockdev {
		u, err := url.Parse(bd.Url)
		if err != nil {
			return nil, grpc.Errorf(codes.InvalidArgument, "url '%s' is invalid url: '%s'", bd.Url, err.Error())
		}

		i, err := img.OpenQemuImg(u.Path)
		if err != nil {
			log.Printf("Failed to open qemu image: err='%s'", err.Error())
			return nil, grpc.Errorf(codes.Internal, "") // TODO #89
		}

		// この条件は雑
		if i.Info.Format == "raw" {
			if err := q.AttachISO(bd.Name, u, uint(bd.BootIndex)); err != nil {
				log.Printf("Failed to attach iso '%s': err='%s'", u.Path, err.Error())
				return nil, grpc.Errorf(codes.Internal, "") // TODO #89
			}
		} else {
			if err := q.AttachQcow2(bd.Name, u, uint(bd.BootIndex)); err != nil {
				log.Printf("Failed to attach image '%s': err='%s'", u.Path, err.Error())
				return nil, grpc.Errorf(codes.Internal, "") // TODO #89
			}
		}
{'fraction_non_alphanumeric': 0.16631965707287202, 'fraction_numerical': 0.014206981016533986, 'mean_word_length': 4.068901303538175, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2358352', 'n_tokens_mistral': 3226, 'n_tokens_neox': 3031, 'n_words': 713}