<commit_before># openstack_dashboard.local.dashboards.project_nci.instances.workflows.create_instance
#
# Copyright (c) 2015, NCI, Australian National University.
# All Rights Reserved.
#
#    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.
#

import copy
import itertools
import json
import logging
import netaddr
import operator
import os.path
#import pdb ## DEBUG
import re
import socket
import time
import types

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.debug import sensitive_variables
from django.template.defaultfilters import filesizeformat

from horizon import exceptions
from horizon import forms
from horizon import messages
from horizon import workflows

from openstack_dashboard import api
from openstack_dashboard.dashboards.project.instances.workflows import create_instance as base_mod

from openstack_dashboard.local.nci import crypto as ncicrypto
from openstack_dashboard.local.nci import utils as nciutils
from openstack_dashboard.local.nci.constants import *


LOG = logging.getLogger(__name__)


class SetInstanceDetailsAction(base_mod.SetInstanceDetailsAction):
    Meta = nciutils.subclass_meta_type(base_mod.SetInstanceDetailsAction)

    def populate_image_id_choices(self, request, context):
        choices = super(SetInstanceDetailsAction, self).populate_image_id_choices(request, context)

        # Find the latest VL image for each unique series tag and add an
        # alias item to the top of the images list with a more friendly name
        # so that the user doesn't have to hunt through the entire list
        # looking for the correct image to use.
        self.vl_tags = {}
        for id, image in choices:
            if not id:
                continue

            parts = image.name.split("-")
            if parts[0] == "vl":
                if not image.is_public:
                    LOG.debug("Ignoring non-public VL image: {0}".format(image.name))
                    continue

                # VL images have the following name format:
                #   vl-<tag_base>[-<tag_variant>-...]-<timestamp>
                if len(parts) < 3:
                    LOG.warning("Invalid VL image name format: {0}".format(image.name))
                    continue

                tag = "-".join(parts[1:-1])

                if re.match(r"2[0-9]{7}", parts[-1]):
                    image._vl_ts = parts[-1]
                else:
                    LOG.warning("Invalid or missing timestamp in VL image name: {0}".format(image.name))
                    continue

                if (tag not in self.vl_tags) or (image._vl_ts > self.vl_tags[tag]._vl_ts):
                    self.vl_tags[tag] = image
            else:
                image.name += " [non-VL]"

        def clone_image(tag):
            if "-" in tag:
                (base, variant) = tag.split("-", 1)
            else:
                base = tag
                variant = ""

            if base.startswith("centos"):
                title = "CentOS"
                base = base[6:]
            elif base.startswith("ubuntu"):
                title = "Ubuntu"
                base = base[6:]
            else:
                title = tag
                base = ""
                variant = ""

            if base:
                title += " " + base

            if variant:
                title += " " + variant

            image = copy.copy(self.vl_tags[tag])
            image._real_id = image.id
            image.id = "vltag:" + tag
            image.name = title
            self.vl_tags[tag] = image

            return image

        if self.vl_tags:
            choices.insert(1, ("---", "---------------"))
            for tag in reversed(sorted(self.vl_tags.keys())):
                image = clone_image(tag)
                choices.insert(1, (image.id, image))

        return choices

    def clean_name(self):
        if hasattr(super(SetInstanceDetailsAction, self), "clean_name"):
            val = super(SetInstanceDetailsAction, self).clean_name()
        else:
            val = self.cleaned_data.get("name")

        val = val.strip()
        if val and ("." in val):
            valid_fqdn = r"^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)*[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?$"
            if not re.search(valid_fqdn, val):
                msg = _("The specified FQDN doesn't satisfy the requirements of a valid DNS hostname.")
                raise forms.ValidationError(msg)

        return val

    def clean_image_id(self):
        if hasattr(super(SetInstanceDetailsAction, self), "clean_image_id"):
            val = super(SetInstanceDetailsAction, self).clean_image_id()
        else:
            val = self.cleaned_data.get("image_id")

        if val:
            if val == "---":
                val = ""
            elif val.startswith("vltag:"):
                # Convert the VL image tag back into the real image ID.
                tag = val[6:]
                if tag not in self.vl_tags:
                    msg = _("Image tag doesn't exist")
                    raise forms.ValidationError(msg)

                val = self.vl_tags[tag]._real_id

        return val

    def get_help_text(self):
        saved = self._images_cache
        try:
            # Add our VL image aliases to the image cache temporarily so
            # that they are included in the list passed to "initWithImages()"
            # in "horizon/static/horizon/js/horizon.quota.js" (via the
            # "_flavors_and_quotas.html" template).  The result will be
            # that any flavours which are too small will be disabled when<commit_msg>Use a divider instead of marking all other images as non-VL<commit_after># openstack_dashboard.local.dashboards.project_nci.instances.workflows.create_instance
#
# Copyright (c) 2015, NCI, Australian National University.
# All Rights Reserved.
#
#    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.
#

import copy
import itertools
import json
import logging
import netaddr
import operator
import os.path
#import pdb ## DEBUG
import re
import socket
import time
import types

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.debug import sensitive_variables
from django.template.defaultfilters import filesizeformat

from horizon import exceptions
from horizon import forms
from horizon import messages
from horizon import workflows

from openstack_dashboard import api
from openstack_dashboard.dashboards.project.instances.workflows import create_instance as base_mod

from openstack_dashboard.local.nci import crypto as ncicrypto
from openstack_dashboard.local.nci import utils as nciutils
from openstack_dashboard.local.nci.constants import *


LOG = logging.getLogger(__name__)


class SetInstanceDetailsAction(base_mod.SetInstanceDetailsAction):
    Meta = nciutils.subclass_meta_type(base_mod.SetInstanceDetailsAction)

    def populate_image_id_choices(self, request, context):
        choices = super(SetInstanceDetailsAction, self).populate_image_id_choices(request, context)

        # Find the latest VL image for each unique series tag and add an
        # alias item to the top of the images list with a more friendly name
        # so that the user doesn't have to hunt through the entire list
        # looking for the correct image to use.
        self.vl_tags = {}
        for id, image in choices:
            if not id:
                continue

            parts = image.name.split("-")
            if parts[0] == "vl":
                if not image.is_public:
                    LOG.debug("Ignoring non-public VL image: {0}".format(image.name))
                    continue

                # VL images have the following name format:
                #   vl-<tag_base>[-<tag_variant>-...]-<timestamp>
                if len(parts) < 3:
                    LOG.warning("Invalid VL image name format: {0}".format(image.name))
                    continue

                tag = "-".join(parts[1:-1])

                if re.match(r"2[0-9]{7}", parts[-1]):
                    image._vl_ts = parts[-1]
                else:
                    LOG.warning("Invalid or missing timestamp in VL image name: {0}".format(image.name))
                    continue

                if (tag not in self.vl_tags) or (image._vl_ts > self.vl_tags[tag]._vl_ts):
                    self.vl_tags[tag] = image

        def clone_image(tag):
            if "-" in tag:
                (base, variant) = tag.split("-", 1)
            else:
                base = tag
                variant = ""

            if base.startswith("centos"):
                title = "CentOS"
                base = base[6:]
            elif base.startswith("ubuntu"):
                title = "Ubuntu"
                base = base[6:]
            else:
                title = tag
                base = ""
                variant = ""

            if base:
                title += " " + base

            if variant:
                title += " " + variant

            image = copy.copy(self.vl_tags[tag])
            image._real_id = image.id
            image.id = "vltag:" + tag
            image.name = title
            self.vl_tags[tag] = image

            return image

        if self.vl_tags:
            choices.insert(1, ("---all", "----- All Images -----"))
            for tag in reversed(sorted(self.vl_tags.keys())):
                image = clone_image(tag)
                choices.insert(1, (image.id, image))
            choices.insert(1, ("---vl", "----- VL Images -----"))

        return choices

    def clean_name(self):
        if hasattr(super(SetInstanceDetailsAction, self), "clean_name"):
            val = super(SetInstanceDetailsAction, self).clean_name()
        else:
            val = self.cleaned_data.get("name")

        val = val.strip()
        if val and ("." in val):
            valid_fqdn = r"^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)*[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?$"
            if not re.search(valid_fqdn, val):
                msg = _("The specified FQDN doesn't satisfy the requirements of a valid DNS hostname.")
                raise forms.ValidationError(msg)

        return val

    def clean_image_id(self):
        if hasattr(super(SetInstanceDetailsAction, self), "clean_image_id"):
            val = super(SetInstanceDetailsAction, self).clean_image_id()
        else:
            val = self.cleaned_data.get("image_id")

        if val:
            if val.startswith("---"):
                val = ""
            elif val.startswith("vltag:"):
                # Convert the VL image tag back into the real image ID.
                tag = val[6:]
                if tag not in self.vl_tags:
                    msg = _("Image tag doesn't exist")
                    raise forms.ValidationError(msg)

                val = self.vl_tags[tag]._real_id

        return val

    def get_help_text(self):
        saved = self._images_cache
        try:
            # Add our VL image aliases to the image cache temporarily so
            # that they are included in the list passed to "initWithImages()"
            # in "horizon/static/horizon/js/horizon.quota.js" (via the
            # "_flavors_and_quotas.html" template).  The result will be
            # that any flavours which are too small will be disabled when
{'fraction_non_alphanumeric': 0.09653641911706427, 'fraction_numerical': 0.0072124910834588255, 'mean_word_length': 1.973138548539114, 'pattern_counts': {'":': 3, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '2501882', 'n_tokens_mistral': 3602, 'n_tokens_neox': 3431, 'n_words': 1045}