Merge pull request #10325 from wenottingham/count-von-count

Add a field for hosts automated across to the subscription info

SUMMARY
This is populated by the new table we've added.
Update the subs check to check against this, not imported hosts.

ISSUE TYPE

Feature Pull Request
Bugfix Pull Request

COMPONENT NAME

API
UI

Reviewed-by: Bill Nottingham <None>
Reviewed-by: Amol Gautam <amol_gautam25@yahoo.co.in>
Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Chris Meyers <None>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
This commit is contained in:
softwarefactory-project-zuul[bot] 2021-06-08 15:30:43 +00:00 committed by GitHub
commit df8ce801cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 7587 additions and 7195 deletions

View File

@ -36,20 +36,20 @@ from awx.main.utils.pglock import advisory_lock
logger = logging.getLogger('awx.main.commands.inventory_import')
LICENSE_EXPIRED_MESSAGE = '''\
License expired.
See http://www.ansible.com/renew for license extension information.'''
Subscription expired.
Contact us (https://www.redhat.com/contact) for subscription extension information.'''
LICENSE_NON_EXISTANT_MESSAGE = '''\
No license.
See http://www.ansible.com/renew for license information.'''
No subscription.
Contact us (https://www.redhat.com/contact) for subscription information.'''
LICENSE_MESSAGE = '''\
Number of licensed instances exceeded, would bring available instances to %(new_count)d, system is licensed for %(instance_count)d.
See http://www.ansible.com/renew for license extension information.'''
%(new_count)d instances have been automated, system is subscribed for %(instance_count)d.
Contact us (https://www.redhat.com/contact) for upgrade information.'''
DEMO_LICENSE_MESSAGE = '''\
Demo mode free license count exceeded, would bring available instances to %(new_count)d, demo mode allows %(instance_count)d.
See http://www.ansible.com/renew for licensing information.'''
Demo mode free subscription count exceeded. Current automated instances are %(new_count)d, demo mode allows %(instance_count)d.
Contact us (https://www.redhat.com/contact) for subscription information.'''
def functioning_dir(path):
@ -756,29 +756,22 @@ class Command(BaseCommand):
instance_count = license_info.get('instance_count', 0)
free_instances = license_info.get('free_instances', 0)
time_remaining = license_info.get('time_remaining', 0)
automated_count = license_info.get('automated_instances', 0)
hard_error = license_info.get('trial', False) is True or license_info['instance_count'] == 10
new_count = Host.objects.active_count()
if time_remaining <= 0:
if hard_error:
logger.error(LICENSE_EXPIRED_MESSAGE)
raise PermissionDenied("License has expired!")
raise PermissionDenied("Subscription has expired!")
else:
logger.warning(LICENSE_EXPIRED_MESSAGE)
# special check for tower-type inventory sources
# but only if running the plugin
TOWER_SOURCE_FILES = ['tower.yml', 'tower.yaml']
if self.inventory_source.source == 'tower' and any(f in self.inventory_source.source_path for f in TOWER_SOURCE_FILES):
# only if this is the 2nd call to license check, we cannot compare before running plugin
if hasattr(self, 'all_group'):
self.remote_tower_license_compare(local_license_type)
if free_instances < 0:
d = {
'new_count': new_count,
'new_count': automated_count,
'instance_count': instance_count,
}
if hard_error:
logger.error(LICENSE_MESSAGE % d)
raise PermissionDenied('License count exceeded!')
raise PermissionDenied('Subscription count exceeded!')
else:
logger.warning(LICENSE_MESSAGE % d)

View File

@ -552,7 +552,7 @@ class JobEvent(BasePlaybookEvent):
summaries = dict()
updated_hosts_list = list()
for host in hostnames:
updated_hosts_list.append(host)
updated_hosts_list.append(host.lower())
host_id = self.host_map.get(host, None)
if host_id not in existing_host_ids:
host_id = None

View File

@ -35,7 +35,7 @@ from django.conf import settings
from django.utils.translation import ugettext_lazy as _
# AWX
from awx.main.models import Host
from awx.main.models import Host, HostMetric, Instance
MAX_INSTANCES = 9999999
@ -383,12 +383,20 @@ class Licenser(object):
current_instances = Host.objects.active_count()
else:
current_instances = 0
license_date = int(attrs.get('license_date', 0) or 0)
automated_instances = HostMetric.objects.count()
first_host = HostMetric.objects.only('first_automation').order_by('first_automation').first()
if first_host:
automated_since = int(first_host.first_automation.timestamp())
else:
automated_since = int(Instance.objects.order_by('id').first().created.timestamp())
instance_count = int(attrs.get('instance_count', 0))
attrs['current_instances'] = current_instances
free_instances = instance_count - current_instances
attrs['automated_instances'] = automated_instances
attrs['automated_since'] = automated_since
free_instances = instance_count - automated_instances
attrs['free_instances'] = max(0, free_instances)
license_date = int(attrs.get('license_date', 0) or 0)
current_date = int(time.time())
time_remaining = license_date - current_date
attrs['time_remaining'] = time_remaining

View File

@ -0,0 +1,29 @@
import React from 'react';
import { node, string } from 'prop-types';
import { t } from '@lingui/macro';
import styled from 'styled-components';
import { formatDateString } from '../../util/dates';
import _Detail from './Detail';
const Detail = styled(_Detail)`
word-break: break-word;
`;
function NumberSinceDetail({ label, number, date, dataCy = null }) {
const dateStr = formatDateString(date);
return (
<Detail
label={label}
dataCy={dataCy}
value={t`${number} since ${dateStr}`}
/>
);
}
NumberSinceDetail.propTypes = {
label: node.isRequired,
number: string.isRequired,
date: string.isRequired,
};
export default NumberSinceDetail;

View File

@ -5,6 +5,7 @@ export { default as UserDateDetail } from './UserDateDetail';
export { default as DetailBadge } from './DetailBadge';
export { default as ArrayDetail } from './ArrayDetail';
export { default as LaunchedByDetail } from './LaunchedByDetail';
export { default as NumberSinceDetail } from './NumberSinceDetail';
/*
NOTE: CodeDetail cannot be imported here, as it causes circular
dependencies in testing environment. Import it directly from

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,11 @@ import {
} from '@patternfly/react-icons';
import RoutedTabs from '../../../../components/RoutedTabs';
import { CardBody, CardActionsRow } from '../../../../components/Card';
import { DetailList, Detail } from '../../../../components/DetailList';
import {
DetailList,
Detail,
NumberSinceDetail,
} from '../../../../components/DetailList';
import { useConfig } from '../../../../contexts/Config';
import {
formatDateString,
@ -126,10 +130,21 @@ function SubscriptionDetail() {
/>
)}
<Detail
dataCy="subscription-hosts-used"
label={t`Hosts used`}
dataCy="subscription-hosts-imported"
label={t`Hosts imported`}
value={license_info.current_instances}
/>
<NumberSinceDetail
dataCy="subscription-hosts-automated"
label={t`Hosts automated`}
number={license_info.automated_instances}
date={
license_info.automated_since &&
formatDateString(
new Date(license_info.automated_since * 1000).toISOString()
)
}
/>
<Detail
dataCy="subscription-hosts-remaining"
label={t`Hosts remaining`}

View File

@ -14,6 +14,8 @@ const config = {
date_expired: false,
date_warning: true,
free_instances: 1000,
automated_instances: '12',
automated_since: '1614714228',
grace_period_remaining: 2904229,
instance_count: 1001,
license_date: '1614401999',
@ -65,8 +67,9 @@ describe('<SubscriptionDetail />', () => {
assertDetail('Trial', 'False');
assertDetail('Expires on', '2/27/2021, 4:59:59 AM');
assertDetail('Days remaining', '3');
assertDetail('Hosts used', '1');
assertDetail('Hosts imported', '1');
assertDetail('Hosts remaining', '1000');
assertDetail('Hosts automated', '12 since 3/2/2021, 7:43:48 PM');
expect(wrapper.find('Button[aria-label="edit"]').length).toBe(1);
});