<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package manual

import (
	"errors"
	"fmt"
	"net"
	"strings"

	"launchpad.net/loggo"

	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api"
	"launchpad.net/juju-core/tools"
	"launchpad.net/juju-core/utils"
	"launchpad.net/juju-core/worker/provisioner"
)

const manualInstancePrefix = "manual:"

var logger = loggo.GetLogger("juju.environs.manual")

type ProvisionMachineArgs struct {
	// Host is the SSH host: [user@]host
	Host string

	// DataDir is the root directory for juju data.
	// If left blank, the default location "/var/lib/juju" will be used.
	DataDir string

	// State is the *state.State object to register the machine with.
	State *state.State

	// Tools to install on the machine. If nil, tools will be automatically
	// chosen using environs/tools FindInstanceTools.
	Tools *tools.Tools
}

// ErrProvisioned is returned by ProvisionMachine if the target
// machine has an existing machine agent.
var ErrProvisioned = errors.New("machine is already provisioned")

// ProvisionMachine provisions a machine agent to an existing host, via
// an SSH connection to the specified host. The host may optionally be preceded
// with a login username, as in [user@]host.
//
// On successful completion, this function will return the state.Machine
// that was entered into state.
func ProvisionMachine(args ProvisionMachineArgs) (m *state.Machine, err error) {
	defer func() {
		if m != nil && err != nil {
			logger.Errorf("provisioning failed, removing machine %v: %v", m, err)
			m.EnsureDead()
			m.Remove()
			m = nil
		}
	}()

	var env environs.Environ
	if conn, err := juju.NewConnFromState(args.State); err != nil {
		return nil, err
	} else {
		env = conn.Environ
	}

	sshHostWithoutUser := args.Host
	if at := strings.Index(sshHostWithoutUser, "@"); at != -1 {
		sshHostWithoutUser = sshHostWithoutUser[at+1:]
	}
	if ip := net.ParseIP(sshHostWithoutUser); ip != nil {
		// Do a reverse-lookup on the IP. The IP may not have
		// a DNS entry, so just log a warning if this fails.
		names, err := net.LookupAddr(ip.String())
		if err != nil {
			logger.Warningf("failed to resolve %v: %v", ip, err)
		} else {
			logger.Infof("resolved %v to %v", ip, names)
			sshHostWithoutUser = names[0]
		}
	}
	addrs, err := instance.HostAddresses(sshHostWithoutUser)
	if err != nil {<commit_msg>environs/manual: INFO log on reverse lookup failure<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package manual

import (
	"errors"
	"fmt"
	"net"
	"strings"

	"launchpad.net/loggo"

	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api"
	"launchpad.net/juju-core/tools"
	"launchpad.net/juju-core/utils"
	"launchpad.net/juju-core/worker/provisioner"
)

const manualInstancePrefix = "manual:"

var logger = loggo.GetLogger("juju.environs.manual")

type ProvisionMachineArgs struct {
	// Host is the SSH host: [user@]host
	Host string

	// DataDir is the root directory for juju data.
	// If left blank, the default location "/var/lib/juju" will be used.
	DataDir string

	// State is the *state.State object to register the machine with.
	State *state.State

	// Tools to install on the machine. If nil, tools will be automatically
	// chosen using environs/tools FindInstanceTools.
	Tools *tools.Tools
}

// ErrProvisioned is returned by ProvisionMachine if the target
// machine has an existing machine agent.
var ErrProvisioned = errors.New("machine is already provisioned")

// ProvisionMachine provisions a machine agent to an existing host, via
// an SSH connection to the specified host. The host may optionally be preceded
// with a login username, as in [user@]host.
//
// On successful completion, this function will return the state.Machine
// that was entered into state.
func ProvisionMachine(args ProvisionMachineArgs) (m *state.Machine, err error) {
	defer func() {
		if m != nil && err != nil {
			logger.Errorf("provisioning failed, removing machine %v: %v", m, err)
			m.EnsureDead()
			m.Remove()
			m = nil
		}
	}()

	var env environs.Environ
	if conn, err := juju.NewConnFromState(args.State); err != nil {
		return nil, err
	} else {
		env = conn.Environ
	}

	sshHostWithoutUser := args.Host
	if at := strings.Index(sshHostWithoutUser, "@"); at != -1 {
		sshHostWithoutUser = sshHostWithoutUser[at+1:]
	}
	if ip := net.ParseIP(sshHostWithoutUser); ip != nil {
		// Do a reverse-lookup on the IP. The IP may not have
		// a DNS entry, so just log a warning if this fails.
		names, err := net.LookupAddr(ip.String())
		if err != nil {
			logger.Infof("failed to resolve %v: %v", ip, err)
		} else {
			logger.Infof("resolved %v to %v", ip, names)
			sshHostWithoutUser = names[0]
		}
	}
	addrs, err := instance.HostAddresses(sshHostWithoutUser)
	if err != nil {
{'fraction_non_alphanumeric': 0.11878072763028515, 'fraction_numerical': 0.003146509341199607, 'mean_word_length': 3.7267657992565058, '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': '6249879', 'n_tokens_mistral': 1817, 'n_tokens_neox': 1657, 'n_words': 538}