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

package common

import (
	"github.com/juju/errors"
	"github.com/juju/utils/clock"
	"gopkg.in/juju/names.v2"

	"github.com/juju/juju/apiserver/metricsender"
)

var sendMetrics = func(st metricsender.ModelBackend) error {
	cfg, err := st.ModelConfig()
	if err != nil {
		return errors.Annotatef(err, "failed to get model config for %s", st.ModelTag())
	}

	err = metricsender.SendMetrics(
		st,
		metricsender.DefaultMetricSender(),
		clock.WallClock,
		metricsender.DefaultMaxBatchesPerSend(),
		cfg.TransmitVendorMetrics(),
	)
	return errors.Trace(err)
}

// DestroyModelIncludingHosted sets the model to dying. Cleanup jobs then destroy
// all services and non-manager, non-manual machine instances in the specified
// model. This function assumes that all necessary authentication checks
// have been done. If the model is a controller hosting other
// models, they will also be destroyed.
func DestroyModelIncludingHosted(st ModelManagerBackend, systemTag names.ModelTag) error {
	return destroyModel(st, systemTag, true)
}

// DestroyModel sets the environment to dying. Cleanup jobs then destroy
// all services and non-manager, non-manual machine instances in the specified
// model. This function assumes that all necessary authentication checks
// have been done. An error will be returned if this model is a
// controller hosting other model.
func DestroyModel(st ModelManagerBackend, modelTag names.ModelTag) error {
	return destroyModel(st, modelTag, false)
}

func destroyModel(st ModelManagerBackend, modelTag names.ModelTag, destroyHostedModels bool) error {
	var err error
	if modelTag != st.ModelTag() {
		st, err = st.ForModel(modelTag)
		defer st.Close()
		if err != nil {
			return errors.Trace(err)
		}
	}

	if destroyHostedModels {
		// Check we are operating on the controller state.
		controllerModel, err := st.ControllerModel()
		if err != nil {
			return errors.Trace(err)
		}
		if modelTag != controllerModel.ModelTag() {
			return errors.Errorf("expected controller model UUID %v, got %v", modelTag.Id(), controllerModel.ModelTag().Id())
		}
		models, err := st.AllModels()
		if err != nil {
			return errors.Trace(err)
		}
		for _, model := range models {
			modelSt, err := st.ForModel(model.ModelTag())
			defer modelSt.Close()
			if err != nil {
				return errors.Trace(err)
			}
			check := NewBlockChecker(modelSt)
			if err = check.DestroyAllowed(); err != nil {
				return errors.Trace(err)
			}
			err = sendMetrics(modelSt)
			if err != nil {
				logger.Errorf("failed to send leftover metrics: %v", err)<commit_msg>oops - revert defer close to original order.<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package common

import (
	"github.com/juju/errors"
	"github.com/juju/utils/clock"
	"gopkg.in/juju/names.v2"

	"github.com/juju/juju/apiserver/metricsender"
)

var sendMetrics = func(st metricsender.ModelBackend) error {
	cfg, err := st.ModelConfig()
	if err != nil {
		return errors.Annotatef(err, "failed to get model config for %s", st.ModelTag())
	}

	err = metricsender.SendMetrics(
		st,
		metricsender.DefaultMetricSender(),
		clock.WallClock,
		metricsender.DefaultMaxBatchesPerSend(),
		cfg.TransmitVendorMetrics(),
	)
	return errors.Trace(err)
}

// DestroyModelIncludingHosted sets the model to dying. Cleanup jobs then destroy
// all services and non-manager, non-manual machine instances in the specified
// model. This function assumes that all necessary authentication checks
// have been done. If the model is a controller hosting other
// models, they will also be destroyed.
func DestroyModelIncludingHosted(st ModelManagerBackend, systemTag names.ModelTag) error {
	return destroyModel(st, systemTag, true)
}

// DestroyModel sets the environment to dying. Cleanup jobs then destroy
// all services and non-manager, non-manual machine instances in the specified
// model. This function assumes that all necessary authentication checks
// have been done. An error will be returned if this model is a
// controller hosting other model.
func DestroyModel(st ModelManagerBackend, modelTag names.ModelTag) error {
	return destroyModel(st, modelTag, false)
}

func destroyModel(st ModelManagerBackend, modelTag names.ModelTag, destroyHostedModels bool) error {
	var err error
	if modelTag != st.ModelTag() {
		if st, err = st.ForModel(modelTag); err != nil {
			return errors.Trace(err)
		}
		defer st.Close()
	}

	if destroyHostedModels {
		// Check we are operating on the controller state.
		controllerModel, err := st.ControllerModel()
		if err != nil {
			return errors.Trace(err)
		}
		if modelTag != controllerModel.ModelTag() {
			return errors.Errorf("expected controller model UUID %v, got %v", modelTag.Id(), controllerModel.ModelTag().Id())
		}
		models, err := st.AllModels()
		if err != nil {
			return errors.Trace(err)
		}
		for _, model := range models {
			modelSt, err := st.ForModel(model.ModelTag())
			defer modelSt.Close()
			if err != nil {
				return errors.Trace(err)
			}
			check := NewBlockChecker(modelSt)
			if err = check.DestroyAllowed(); err != nil {
				return errors.Trace(err)
			}
			err = sendMetrics(modelSt)
			if err != nil {
				logger.Errorf("failed to send leftover metrics: %v", err)
{'fraction_non_alphanumeric': 0.10399551904406273, 'fraction_numerical': 0.0022404779686333084, 'mean_word_length': 4.034774436090226, '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': '2247028', 'n_tokens_mistral': 1744, 'n_tokens_neox': 1605, 'n_words': 527}