<commit_before>package main

import (
	"encoding/xml"
	"fmt"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/Symantec/Dominator/lib/errors"
	"github.com/Symantec/Dominator/lib/json"
	"github.com/Symantec/Dominator/lib/log"
	"github.com/Symantec/Dominator/lib/srpc"
	proto "github.com/Symantec/Dominator/proto/hypervisor"
)

type devicesInfo struct {
	Interfaces []interfaceType `xml:"interface"`
	Volumes    []volumeType    `xml:"disk"`
}

type driverType struct {
	Name string `xml:"name,attr"`
	Type string `xml:"type,attr"`
}

type interfaceType struct {
	Mac  macType `xml:"mac"`
	Type string  `xml:"type,attr"`
}

type macType struct {
	Address string `xml:"address,attr"`
}

type memoryInfo struct {
	Value uint64 `xml:",chardata"`
	Unit  string `xml:"unit,attr"`
}

type sourceType struct {
	File string `xml:"file,attr"`
}

type vCpuInfo struct {
	Num       uint   `xml:",chardata"`
	Placement string `xml:"placement,attr"`
}

type virshInfoType struct {
	Devices devicesInfo `xml:"devices"`
	Memory  memoryInfo  `xml:"memory"`
	Name    string      `xml:"name"`
	VCpu    vCpuInfo    `xml:"vcpu"`
}

type volumeType struct {
	Device string     `xml:"device,attr"`
	Driver driverType `xml:"driver"`
	Source sourceType `xml:"source"`
	Type   string     `xml:"type,attr"`
}

func importVirshVmSubcommand(args []string, logger log.DebugLogger) error {
	if err := importVirshVm(args[0], args[1], logger); err != nil {
		return fmt.Errorf("Error importing VM: %s", err)
	}
	return nil
}

func ensureDomainIsStopped(domainName string) error {
	state, err := getDomainState(domainName)
	if err != nil {
		return err
	}
	if state == "shut off" {
		return nil
	}
	if state != "running" {
		return fmt.Errorf("domain is in unsupported state \"%s\"", state)
	}
	response, err := askForInputChoice("Cannot import running VM",
		[]string{"shutdown", "quit"})
	if err != nil {
		return err
	}
	if response == "quit" {
		return fmt.Errorf("domain must be shut off but is \"%s\"", state)
	}
	err = exec.Command("virsh", []string{"shutdown", domainName}...).Run()
	if err != nil {
		return fmt.Errorf("error shutting down VM: %s", err)
	}
	for ; ; time.Sleep(time.Second) {
		state, err := getDomainState(domainName)
		if err != nil {
			return err
		}
		if state == "shut off" {
			return nil
		}
	}
}

func getDomainState(domainName string) (string, error) {
	cmd := exec.Command("virsh", []string{"domstate", domainName}...)
	stdout, err := cmd.Output()
	if err != nil {
		return "", fmt.Errorf("error getting VM status: %s", err)
	}
	return strings.TrimSpace(string(stdout)), nil
}

func importVirshVm(macAddr, domainName string, logger log.DebugLogger) error {
	ipList, err := net.LookupIP(domainName)
	if err != nil {
		return err
	}
	if len(ipList) != 1 {
		return fmt.Errorf("number of IPs %d != 1", len(ipList))
	}
	tags := vmTags.Copy()
	if _, ok := tags["Name"]; !ok {
		tags["Name"] = domainName
	}
	request := proto.ImportLocalVmRequest{VmInfo: proto.VmInfo{
		Hostname:    domainName,
		OwnerGroups: ownerGroups,<commit_msg>Support importing libvirt VMs which disappear when stopped.<commit_after>package main

import (
	"encoding/xml"
	"fmt"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/Symantec/Dominator/lib/errors"
	"github.com/Symantec/Dominator/lib/json"
	"github.com/Symantec/Dominator/lib/log"
	"github.com/Symantec/Dominator/lib/srpc"
	proto "github.com/Symantec/Dominator/proto/hypervisor"
)

type devicesInfo struct {
	Interfaces []interfaceType `xml:"interface"`
	Volumes    []volumeType    `xml:"disk"`
}

type driverType struct {
	Name string `xml:"name,attr"`
	Type string `xml:"type,attr"`
}

type interfaceType struct {
	Mac  macType `xml:"mac"`
	Type string  `xml:"type,attr"`
}

type macType struct {
	Address string `xml:"address,attr"`
}

type memoryInfo struct {
	Value uint64 `xml:",chardata"`
	Unit  string `xml:"unit,attr"`
}

type sourceType struct {
	File string `xml:"file,attr"`
}

type vCpuInfo struct {
	Num       uint   `xml:",chardata"`
	Placement string `xml:"placement,attr"`
}

type virshInfoType struct {
	Devices devicesInfo `xml:"devices"`
	Memory  memoryInfo  `xml:"memory"`
	Name    string      `xml:"name"`
	VCpu    vCpuInfo    `xml:"vcpu"`
}

type volumeType struct {
	Device string     `xml:"device,attr"`
	Driver driverType `xml:"driver"`
	Source sourceType `xml:"source"`
	Type   string     `xml:"type,attr"`
}

func importVirshVmSubcommand(args []string, logger log.DebugLogger) error {
	if err := importVirshVm(args[0], args[1], logger); err != nil {
		return fmt.Errorf("Error importing VM: %s", err)
	}
	return nil
}

func ensureDomainIsStopped(domainName string) error {
	state, err := getDomainState(domainName)
	if err != nil {
		return err
	}
	if state == "shut off" {
		return nil
	}
	if state != "running" {
		return fmt.Errorf("domain is in unsupported state \"%s\"", state)
	}
	response, err := askForInputChoice("Cannot import running VM",
		[]string{"shutdown", "quit"})
	if err != nil {
		return err
	}
	if response == "quit" {
		return fmt.Errorf("domain must be shut off but is \"%s\"", state)
	}
	err = exec.Command("virsh", []string{"shutdown", domainName}...).Run()
	if err != nil {
		return fmt.Errorf("error shutting down VM: %s", err)
	}
	for ; ; time.Sleep(time.Second) {
		state, err := getDomainState(domainName)
		if err != nil {
			if strings.Contains(err.Error(), "Domain not found") {
				return nil
			}
			return err
		}
		if state == "shut off" {
			return nil
		}
	}
}

func getDomainState(domainName string) (string, error) {
	cmd := exec.Command("virsh", []string{"domstate", domainName}...)
	stdout, err := cmd.Output()
	if err != nil {
		return "", fmt.Errorf("error getting VM status: %s",
			err.(*exec.ExitError).Stderr)
	}
	return strings.TrimSpace(string(stdout)), nil
}

func importVirshVm(macAddr, domainName string, logger log.DebugLogger) error {
	ipList, err := net.LookupIP(domainName)
	if err != nil {
		return err
	}
	if len(ipList) != 1 {
		return fmt.Errorf("number of IPs %d != 1", len(ipList))
	}
	tags := vmTags.Copy()
	if _, ok := tags["Name"]; !ok {
		tags["Name"] = domainName
	}
	request := proto.ImportLocalVmRequest{VmInfo: proto.VmInfo{
		Hostname:    domainName,
		OwnerGroups: ownerGroups,
{'fraction_non_alphanumeric': 0.15286624203821655, 'fraction_numerical': 0.001910828025477707, 'mean_word_length': 4.173805601317957, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 42}, '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': '6177709', 'n_tokens_mistral': 2309, 'n_tokens_neox': 2224, 'n_words': 565}