mirror of
https://github.com/ansible/awx.git
synced 2026-05-16 22:07:36 -02:30
Merge pull request #4611 from ryanpetrello/license-updates
update trial license enforcement logic Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
@@ -14,6 +14,7 @@ from awx.api.views import (
|
|||||||
ApiV2RootView,
|
ApiV2RootView,
|
||||||
ApiV2PingView,
|
ApiV2PingView,
|
||||||
ApiV2ConfigView,
|
ApiV2ConfigView,
|
||||||
|
ApiV2SubscriptionView,
|
||||||
AuthView,
|
AuthView,
|
||||||
UserMeList,
|
UserMeList,
|
||||||
DashboardView,
|
DashboardView,
|
||||||
@@ -94,6 +95,7 @@ v2_urls = [
|
|||||||
url(r'^metrics/$', MetricsView.as_view(), name='metrics_view'),
|
url(r'^metrics/$', MetricsView.as_view(), name='metrics_view'),
|
||||||
url(r'^ping/$', ApiV2PingView.as_view(), name='api_v2_ping_view'),
|
url(r'^ping/$', ApiV2PingView.as_view(), name='api_v2_ping_view'),
|
||||||
url(r'^config/$', ApiV2ConfigView.as_view(), name='api_v2_config_view'),
|
url(r'^config/$', ApiV2ConfigView.as_view(), name='api_v2_config_view'),
|
||||||
|
url(r'^config/subscriptions/$', ApiV2SubscriptionView.as_view(), name='api_v2_subscription_view'),
|
||||||
url(r'^auth/$', AuthView.as_view()),
|
url(r'^auth/$', AuthView.as_view()),
|
||||||
url(r'^me/$', UserMeList.as_view(), name='user_me_list'),
|
url(r'^me/$', UserMeList.as_view(), name='user_me_list'),
|
||||||
url(r'^dashboard/$', DashboardView.as_view(), name='dashboard_view'),
|
url(r'^dashboard/$', DashboardView.as_view(), name='dashboard_view'),
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ from awx.api.views.root import ( # noqa
|
|||||||
ApiV2RootView,
|
ApiV2RootView,
|
||||||
ApiV2PingView,
|
ApiV2PingView,
|
||||||
ApiV2ConfigView,
|
ApiV2ConfigView,
|
||||||
|
ApiV2SubscriptionView,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ from rest_framework.permissions import AllowAny, IsAuthenticated
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
from awx.api.generics import APIView
|
from awx.api.generics import APIView
|
||||||
from awx.main.ha import is_ha_environment
|
from awx.main.ha import is_ha_environment
|
||||||
from awx.main.utils import (
|
from awx.main.utils import (
|
||||||
@@ -169,6 +171,45 @@ class ApiV2PingView(APIView):
|
|||||||
return Response(response)
|
return Response(response)
|
||||||
|
|
||||||
|
|
||||||
|
class ApiV2SubscriptionView(APIView):
|
||||||
|
|
||||||
|
permission_classes = (IsAuthenticated,)
|
||||||
|
name = _('Configuration')
|
||||||
|
swagger_topic = 'System Configuration'
|
||||||
|
|
||||||
|
def check_permissions(self, request):
|
||||||
|
super(ApiV2SubscriptionView, self).check_permissions(request)
|
||||||
|
if not request.user.is_superuser and request.method.lower() not in {'options', 'head'}:
|
||||||
|
self.permission_denied(request) # Raises PermissionDenied exception.
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
from awx.main.utils.common import get_licenser
|
||||||
|
data = request.data.copy()
|
||||||
|
if data.get('rh_password') == '$encrypted$':
|
||||||
|
data['rh_password'] = settings.REDHAT_PASSWORD
|
||||||
|
try:
|
||||||
|
user, pw = data.get('rh_username'), data.get('rh_password')
|
||||||
|
validated = get_licenser().validate_rh(user, pw)
|
||||||
|
if user:
|
||||||
|
settings.REDHAT_USERNAME = data['rh_username']
|
||||||
|
if pw:
|
||||||
|
settings.REDHAT_PASSWORD = data['rh_password']
|
||||||
|
except Exception as exc:
|
||||||
|
msg = _("Invalid License")
|
||||||
|
if (
|
||||||
|
isinstance(exc, requests.exceptions.HTTPError) and
|
||||||
|
getattr(getattr(exc, 'response', None), 'status_code', None) == 401
|
||||||
|
):
|
||||||
|
msg = _("The provided credentials are invalid (HTTP 401).")
|
||||||
|
if isinstance(exc, (ValueError, OSError)) and exc.args:
|
||||||
|
msg = exc.args[0]
|
||||||
|
logger.exception(smart_text(u"Invalid license submitted."),
|
||||||
|
extra=dict(actor=request.user.username))
|
||||||
|
return Response({"error": msg}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
return Response(validated)
|
||||||
|
|
||||||
|
|
||||||
class ApiV2ConfigView(APIView):
|
class ApiV2ConfigView(APIView):
|
||||||
|
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
|
|||||||
@@ -317,10 +317,19 @@ class BaseAccess(object):
|
|||||||
validation_info['time_remaining'] = 99999999
|
validation_info['time_remaining'] = 99999999
|
||||||
validation_info['grace_period_remaining'] = 99999999
|
validation_info['grace_period_remaining'] = 99999999
|
||||||
|
|
||||||
|
report_violation = lambda message: logger.error(message)
|
||||||
|
|
||||||
|
if (
|
||||||
|
validation_info.get('trial', False) is True or
|
||||||
|
validation_info['instance_count'] == 10 # basic 10 license
|
||||||
|
):
|
||||||
|
def report_violation(message):
|
||||||
|
raise PermissionDenied(message)
|
||||||
|
|
||||||
if check_expiration and validation_info.get('time_remaining', None) is None:
|
if check_expiration and validation_info.get('time_remaining', None) is None:
|
||||||
raise PermissionDenied(_("License is missing."))
|
raise PermissionDenied(_("License is missing."))
|
||||||
if check_expiration and validation_info.get("grace_period_remaining") <= 0:
|
elif check_expiration and validation_info.get("grace_period_remaining") <= 0:
|
||||||
raise PermissionDenied(_("License has expired."))
|
report_violation(_("License has expired."))
|
||||||
|
|
||||||
free_instances = validation_info.get('free_instances', 0)
|
free_instances = validation_info.get('free_instances', 0)
|
||||||
available_instances = validation_info.get('available_instances', 0)
|
available_instances = validation_info.get('available_instances', 0)
|
||||||
@@ -328,11 +337,11 @@ class BaseAccess(object):
|
|||||||
if add_host_name:
|
if add_host_name:
|
||||||
host_exists = Host.objects.filter(name=add_host_name).exists()
|
host_exists = Host.objects.filter(name=add_host_name).exists()
|
||||||
if not host_exists and free_instances == 0:
|
if not host_exists and free_instances == 0:
|
||||||
raise PermissionDenied(_("License count of %s instances has been reached.") % available_instances)
|
report_violation(_("License count of %s instances has been reached.") % available_instances)
|
||||||
elif not host_exists and free_instances < 0:
|
elif not host_exists and free_instances < 0:
|
||||||
raise PermissionDenied(_("License count of %s instances has been exceeded.") % available_instances)
|
report_violation(_("License count of %s instances has been exceeded.") % available_instances)
|
||||||
elif not add_host_name and free_instances < 0:
|
elif not add_host_name and free_instances < 0:
|
||||||
raise PermissionDenied(_("Host count exceeds available instances."))
|
report_violation(_("Host count exceeds available instances."))
|
||||||
|
|
||||||
def check_org_host_limit(self, data, add_host_name=None):
|
def check_org_host_limit(self, data, add_host_name=None):
|
||||||
validation_info = get_licenser().validate()
|
validation_info = get_licenser().validate()
|
||||||
|
|||||||
@@ -919,7 +919,8 @@ class Command(BaseCommand):
|
|||||||
new_count = Host.objects.active_count()
|
new_count = Host.objects.active_count()
|
||||||
if time_remaining <= 0 and not license_info.get('demo', False):
|
if time_remaining <= 0 and not license_info.get('demo', False):
|
||||||
logger.error(LICENSE_EXPIRED_MESSAGE)
|
logger.error(LICENSE_EXPIRED_MESSAGE)
|
||||||
raise CommandError("License has expired!")
|
if license_info.get('trial', False) is True:
|
||||||
|
raise CommandError("License has expired!")
|
||||||
# special check for tower-type inventory sources
|
# special check for tower-type inventory sources
|
||||||
# but only if running the plugin
|
# but only if running the plugin
|
||||||
TOWER_SOURCE_FILES = ['tower.yml', 'tower.yaml']
|
TOWER_SOURCE_FILES = ['tower.yml', 'tower.yaml']
|
||||||
@@ -936,7 +937,11 @@ class Command(BaseCommand):
|
|||||||
logger.error(DEMO_LICENSE_MESSAGE % d)
|
logger.error(DEMO_LICENSE_MESSAGE % d)
|
||||||
else:
|
else:
|
||||||
logger.error(LICENSE_MESSAGE % d)
|
logger.error(LICENSE_MESSAGE % d)
|
||||||
raise CommandError('License count exceeded!')
|
if (
|
||||||
|
license_info.get('trial', False) is True or
|
||||||
|
license_info['instance_count'] == 10 # basic 10 license
|
||||||
|
):
|
||||||
|
raise CommandError('License count exceeded!')
|
||||||
|
|
||||||
def check_org_host_limit(self):
|
def check_org_host_limit(self):
|
||||||
license_info = get_licenser().validate()
|
license_info = get_licenser().validate()
|
||||||
|
|||||||
@@ -1595,7 +1595,7 @@ tr td button i {
|
|||||||
padding: 20px 0;
|
padding: 20px 0;
|
||||||
|
|
||||||
.alert {
|
.alert {
|
||||||
padding: 10px;
|
padding: 0px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,4 +53,24 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}],
|
}],
|
||||||
|
resolve: {
|
||||||
|
rhCreds: ['Rest', 'GetBasePath', function(Rest, GetBasePath) {
|
||||||
|
Rest.setUrl(`${GetBasePath('settings')}system/`);
|
||||||
|
return Rest.get()
|
||||||
|
.then(({data}) => {
|
||||||
|
const rhCreds = {};
|
||||||
|
if (data.REDHAT_USERNAME && data.REDHAT_USERNAME !== "") {
|
||||||
|
rhCreds.REDHAT_USERNAME = data.REDHAT_USERNAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.REDHAT_PASSWORD && data.REDHAT_PASSWORD !== "") {
|
||||||
|
rhCreds.REDHAT_PASSWORD = data.REDHAT_PASSWORD;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rhCreds;
|
||||||
|
}).catch(() => {
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
}]
|
||||||
|
}
|
||||||
};
|
};
|
||||||
@@ -5,29 +5,29 @@
|
|||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
||||||
export default
|
export default
|
||||||
['$state', '$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors',
|
['$state', '$rootScope', 'Rest', 'GetBasePath',
|
||||||
'ConfigService',
|
'ConfigService', '$q',
|
||||||
function($state, $rootScope, Rest, GetBasePath, ProcessErrors,
|
function($state, $rootScope, Rest, GetBasePath,
|
||||||
ConfigService){
|
ConfigService, $q){
|
||||||
return {
|
return {
|
||||||
get: function() {
|
get: function() {
|
||||||
var config = ConfigService.get();
|
var config = ConfigService.get();
|
||||||
return config.license_info;
|
return config.license_info;
|
||||||
},
|
},
|
||||||
|
|
||||||
post: function(license, eula){
|
post: function(payload, eula){
|
||||||
var defaultUrl = GetBasePath('config');
|
var defaultUrl = GetBasePath('config');
|
||||||
Rest.setUrl(defaultUrl);
|
Rest.setUrl(defaultUrl);
|
||||||
var data = license;
|
var data = payload;
|
||||||
data.eula_accepted = eula;
|
data.eula_accepted = eula;
|
||||||
|
|
||||||
return Rest.post(JSON.stringify(data))
|
return Rest.post(JSON.stringify(data))
|
||||||
.then((response) =>{
|
.then((response) =>{
|
||||||
return response.data;
|
return response.data;
|
||||||
})
|
})
|
||||||
.catch(({res, status}) => {
|
.catch(({data}) => {
|
||||||
ProcessErrors($rootScope, res, status, null, {hdr: 'Error!',
|
return $q.reject(data);
|
||||||
msg: 'Call to '+ defaultUrl + ' failed. Return status: '+ status});
|
});
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
valid: function(license) {
|
valid: function(license) {
|
||||||
|
|||||||
@@ -26,6 +26,21 @@
|
|||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
.License-file--left {
|
||||||
|
display: flex;
|
||||||
|
flex:1;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.License-file--middle {
|
||||||
|
display: flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
padding: 0px 20px;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.License-file--right {
|
||||||
|
display: flex;
|
||||||
|
flex:1;
|
||||||
|
}
|
||||||
.License-submit--success.ng-hide-add, .License-submit--success.ng-hide-remove {
|
.License-submit--success.ng-hide-add, .License-submit--success.ng-hide-remove {
|
||||||
transition: all ease-in-out 0.5s;
|
transition: all ease-in-out 0.5s;
|
||||||
}
|
}
|
||||||
@@ -109,10 +124,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.License-submit--success{
|
.License-submit--success, .License-submit--failure {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.License-file--container {
|
.License-file--container {
|
||||||
|
display: flex;
|
||||||
input[type=file] {
|
input[type=file] {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -148,3 +164,127 @@
|
|||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.License-separator {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
background: linear-gradient(#d7d7d7, #d7d7d7) no-repeat center/2px 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-licenseStepHelp {
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: italic;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-filePicker {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-rhCredField {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-label {
|
||||||
|
color: @field-label;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-action {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-content:flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-actionError {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-subSelectorModal {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
z-index: 1040;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-modal {
|
||||||
|
width: 750px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-modalBody {
|
||||||
|
border: 1px solid @b7grey;
|
||||||
|
max-height: 550px;
|
||||||
|
overflow: scroll;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-modalRow {
|
||||||
|
display: flex;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-modalRow:not(:last-of-type) {
|
||||||
|
border-bottom: 1px solid @b7grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-modalRowRadio {
|
||||||
|
flex: 0 0 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-trialTag {
|
||||||
|
font-weight: 100;
|
||||||
|
background-color: #ebebeb;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: #606060;
|
||||||
|
font-size: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
padding: 3px 9px;
|
||||||
|
line-height: 14px;
|
||||||
|
word-break: keep-all;
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-introText {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-getLicensesButton {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-checkboxLabel {
|
||||||
|
margin-left: 5px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-modalRowDetails {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-modalRowDetailsLabel {
|
||||||
|
font-weight: normal;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-modalRowDetailsRow {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.License-modalRowDetails--50 {
|
||||||
|
display: flex;
|
||||||
|
flex-basis: 50%;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 21px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,11 +7,10 @@
|
|||||||
import {N_} from "../i18n";
|
import {N_} from "../i18n";
|
||||||
|
|
||||||
export default
|
export default
|
||||||
['Wait', '$state', '$scope', '$rootScope',
|
['Wait', '$state', '$scope', '$rootScope', 'ProcessErrors', 'CheckLicense', 'moment', '$timeout', 'Rest',
|
||||||
'ProcessErrors', 'CheckLicense', 'moment','$window',
|
'$window', 'ConfigService', 'pendoService', 'insightsEnablementService', 'i18n', 'config', 'rhCreds', 'GetBasePath',
|
||||||
'ConfigService', 'pendoService', 'insightsEnablementService', 'i18n', 'config',
|
function(Wait, $state, $scope, $rootScope, ProcessErrors, CheckLicense, moment, $timeout, Rest,
|
||||||
function(Wait, $state, $scope, $rootScope, ProcessErrors, CheckLicense, moment,
|
$window, ConfigService, pendoService, insightsEnablementService, i18n, config, rhCreds, GetBasePath) {
|
||||||
$window, ConfigService, pendoService, insightsEnablementService, i18n, config) {
|
|
||||||
|
|
||||||
const calcDaysRemaining = function(seconds) {
|
const calcDaysRemaining = function(seconds) {
|
||||||
// calculate the number of days remaining on the license
|
// calculate the number of days remaining on the license
|
||||||
@@ -33,10 +32,12 @@ export default
|
|||||||
};
|
};
|
||||||
|
|
||||||
const reset = function() {
|
const reset = function() {
|
||||||
document.getElementById('License-form').reset();
|
$scope.newLicense.eula = undefined;
|
||||||
|
$scope.rhCreds = {};
|
||||||
|
$scope.selectedLicense = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
const init = function(config) {
|
const initVars = (config) => {
|
||||||
// license/license.partial.html compares fileName
|
// license/license.partial.html compares fileName
|
||||||
$scope.fileName = N_("No file selected.");
|
$scope.fileName = N_("No file selected.");
|
||||||
|
|
||||||
@@ -53,13 +54,44 @@ export default
|
|||||||
$scope.time.expiresOn = calcExpiresOn($scope.license.license_info.license_date);
|
$scope.time.expiresOn = calcExpiresOn($scope.license.license_info.license_date);
|
||||||
$scope.valid = CheckLicense.valid($scope.license.license_info);
|
$scope.valid = CheckLicense.valid($scope.license.license_info);
|
||||||
$scope.compliant = $scope.license.license_info.compliant;
|
$scope.compliant = $scope.license.license_info.compliant;
|
||||||
|
$scope.selectedLicense = {};
|
||||||
$scope.newLicense = {
|
$scope.newLicense = {
|
||||||
pendo: true,
|
pendo: true,
|
||||||
insights: true
|
insights: true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.rhCreds = {};
|
||||||
|
|
||||||
|
if (rhCreds.REDHAT_USERNAME && rhCreds.REDHAT_USERNAME !== "") {
|
||||||
|
$scope.rhCreds.username = rhCreds.REDHAT_USERNAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rhCreds.REDHAT_PASSWORD && rhCreds.REDHAT_PASSWORD !== "") {
|
||||||
|
$scope.rhCreds.password = rhCreds.REDHAT_PASSWORD;
|
||||||
|
$scope.showPlaceholderPassword = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
init(config);
|
const updateRHCreds = (config) => {
|
||||||
|
Rest.setUrl(`${GetBasePath('settings')}system/`);
|
||||||
|
Rest.get()
|
||||||
|
.then(({data}) => {
|
||||||
|
initVars(config);
|
||||||
|
|
||||||
|
if (data.REDHAT_USERNAME && data.REDHAT_USERNAME !== "") {
|
||||||
|
$scope.rhCreds.username = data.REDHAT_USERNAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.REDHAT_PASSWORD && data.REDHAT_PASSWORD !== "") {
|
||||||
|
$scope.rhCreds.password = data.REDHAT_PASSWORD;
|
||||||
|
$scope.showPlaceholderPassword = true;
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
initVars(config);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
initVars(config);
|
||||||
|
|
||||||
$scope.getKey = function(event) {
|
$scope.getKey = function(event) {
|
||||||
// Mimic HTML5 spec, show filename
|
// Mimic HTML5 spec, show filename
|
||||||
@@ -87,7 +119,7 @@ export default
|
|||||||
// HTML5 spec doesn't provide a way to customize file input css
|
// HTML5 spec doesn't provide a way to customize file input css
|
||||||
// So we hide the default input, show our own, and simulate clicks to the hidden input
|
// So we hide the default input, show our own, and simulate clicks to the hidden input
|
||||||
$scope.fakeClick = function() {
|
$scope.fakeClick = function() {
|
||||||
if($scope.user_is_superuser) {
|
if($scope.user_is_superuser && (!$scope.rhCreds.username || $scope.rhCreds.username === '') && (!$scope.rhCreds.password || $scope.rhCreds.password === '')) {
|
||||||
$('#License-file').click();
|
$('#License-file').click();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -96,44 +128,112 @@ export default
|
|||||||
$window.open('https://www.ansible.com/license', '_blank');
|
$window.open('https://www.ansible.com/license', '_blank');
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.submit = function() {
|
$scope.replacePassword = () => {
|
||||||
Wait('start');
|
if ($scope.user_is_superuser && !$scope.newLicense.file) {
|
||||||
CheckLicense.post($scope.newLicense.file, $scope.newLicense.eula)
|
$scope.showPlaceholderPassword = false;
|
||||||
.then((licenseInfo) => {
|
$scope.rhCreds.password = "";
|
||||||
reset();
|
$timeout(() => {
|
||||||
|
$('.tooltip').remove();
|
||||||
|
$('#rh-password').focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ConfigService.delete();
|
$scope.lookupLicenses = () => {
|
||||||
ConfigService.getConfig(licenseInfo)
|
if ($scope.rhCreds.username && $scope.rhCreds.password) {
|
||||||
.then(function(config) {
|
Wait('start');
|
||||||
|
ConfigService.getSubscriptions($scope.rhCreds.username, $scope.rhCreds.password)
|
||||||
if ($rootScope.licenseMissing === true) {
|
.then(({data}) => {
|
||||||
if ($scope.newLicense.pendo) {
|
Wait('stop');
|
||||||
pendoService.updatePendoTrackingState('detailed');
|
if (data && data.length > 0) {
|
||||||
pendoService.issuePendoIdentity();
|
$scope.rhLicenses = data;
|
||||||
} else {
|
if ($scope.selectedLicense.fullLicense) {
|
||||||
pendoService.updatePendoTrackingState('off');
|
$scope.selectedLicense.modalKey = $scope.selectedLicense.fullLicense.license_key;
|
||||||
}
|
}
|
||||||
|
$scope.showLicenseModal = true;
|
||||||
if ($scope.newLicense.insights) {
|
} else {
|
||||||
insightsEnablementService.updateInsightsTrackingState(true);
|
ProcessErrors($scope, data, status, null, {
|
||||||
} else {
|
hdr: i18n._('No Licenses Found'),
|
||||||
insightsEnablementService.updateInsightsTrackingState(false);
|
msg: i18n._('We were unable to locate licenses associated with this account')
|
||||||
}
|
});
|
||||||
|
}
|
||||||
$state.go('dashboard', {
|
})
|
||||||
licenseMissing: false
|
.catch(({data, status}) => {
|
||||||
});
|
Wait('stop');
|
||||||
} else {
|
ProcessErrors($scope, data, status, null, {
|
||||||
init(config);
|
hdr: i18n._('Error Fetching Licenses')
|
||||||
$scope.success = true;
|
|
||||||
$rootScope.licenseMissing = false;
|
|
||||||
// for animation purposes
|
|
||||||
const successTimeout = setTimeout(function() {
|
|
||||||
$scope.success = false;
|
|
||||||
clearTimeout(successTimeout);
|
|
||||||
}, 4000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.confirmLicenseSelection = () => {
|
||||||
|
$scope.showLicenseModal = false;
|
||||||
|
$scope.selectedLicense.fullLicense = $scope.rhLicenses.find((license) => {
|
||||||
|
return license.license_key === $scope.selectedLicense.modalKey;
|
||||||
|
});
|
||||||
|
$scope.selectedLicense.modalKey = undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.cancelLicenseLookup = () => {
|
||||||
|
$scope.showLicenseModal = false;
|
||||||
|
$scope.selectedLicense.modalKey = undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.submit = function() {
|
||||||
|
Wait('start');
|
||||||
|
let payload = {};
|
||||||
|
if ($scope.newLicense.file) {
|
||||||
|
payload = $scope.newLicense.file;
|
||||||
|
} else if ($scope.selectedLicense.fullLicense) {
|
||||||
|
payload = $scope.selectedLicense.fullLicense;
|
||||||
|
if ($scope.rhCreds.username && $scope.rhCreds.password) {
|
||||||
|
payload.rh_password = $scope.rhCreds.password;
|
||||||
|
payload.rh_username = $scope.rhCreds.username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckLicense.post(payload, $scope.newLicense.eula)
|
||||||
|
.then((licenseInfo) => {
|
||||||
|
reset();
|
||||||
|
|
||||||
|
ConfigService.delete();
|
||||||
|
ConfigService.getConfig(licenseInfo)
|
||||||
|
.then(function(config) {
|
||||||
|
|
||||||
|
if ($rootScope.licenseMissing === true) {
|
||||||
|
if ($scope.newLicense.pendo) {
|
||||||
|
pendoService.updatePendoTrackingState('detailed');
|
||||||
|
pendoService.issuePendoIdentity();
|
||||||
|
} else {
|
||||||
|
pendoService.updatePendoTrackingState('off');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($scope.newLicense.insights) {
|
||||||
|
insightsEnablementService.updateInsightsTrackingState(true);
|
||||||
|
} else {
|
||||||
|
insightsEnablementService.updateInsightsTrackingState(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
$state.go('dashboard', {
|
||||||
|
licenseMissing: false
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateRHCreds(config);
|
||||||
|
$scope.success = true;
|
||||||
|
$rootScope.licenseMissing = false;
|
||||||
|
// for animation purposes
|
||||||
|
const successTimeout = setTimeout(function() {
|
||||||
|
$scope.success = false;
|
||||||
|
clearTimeout(successTimeout);
|
||||||
|
}, 4000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(({data, status}) => {
|
||||||
|
Wait('stop');
|
||||||
|
ProcessErrors($scope, data, status, null, {
|
||||||
|
hdr: i18n._('Error Applying License')
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
}];
|
}];
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<div class="License-field--label" translate>License</div>
|
<div class="License-field--label" translate>License</div>
|
||||||
<div class="License-field--content">
|
<div class="License-field--content">
|
||||||
<span class="License-greenText" ng-show='compliant'><i class="fa fa-circle License-greenText"></i><translate>Valid License</translate></span>
|
<span class="License-greenText" ng-show='compliant'><i class="fa fa-circle License-greenText"></i><translate>Valid License</translate></span>
|
||||||
<span class="License-redText" ng-show='!compliant'><i class="fa fa-circle License-redText"></i><translate>Invalid License</translate></span>
|
<span class="License-redText" ng-show='compliant !== undefined && !compliant'><i class="fa fa-circle License-redText"></i><translate>Invalid License</translate></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="License-field">
|
<div class="License-field">
|
||||||
@@ -75,78 +75,193 @@
|
|||||||
<div class="card at-Panel">
|
<div class="card at-Panel">
|
||||||
<div class="List-titleText">{{title}}</div>
|
<div class="List-titleText">{{title}}</div>
|
||||||
<div class="License-body">
|
<div class="License-body">
|
||||||
<div class="License-helperText" ng-if="licenseMissing" translate>Welcome to Ansible Tower! Please complete the steps below to acquire a license.</div>
|
<div class="License-helperText License-introText" ng-if="licenseMissing" translate>Welcome to Ansible Tower! Please complete the steps below to acquire a license.</div>
|
||||||
<div class="AddPermissions-directions" ng-if="licenseMissing">
|
<div class="input-group License-file--container">
|
||||||
<span class="AddPermissions-directionNumber">
|
<div class="License-file--left">
|
||||||
1
|
<div class="d-block w-100">
|
||||||
</span>
|
<div class="AddPermissions-directions" ng-if="licenseMissing">
|
||||||
<span class="License-helperText">
|
<span class="AddPermissions-directionNumber">
|
||||||
<translate>Please click the button below to visit Ansible's website to get a Tower license key.</translate>
|
1
|
||||||
</span>
|
</span>
|
||||||
|
<span class="License-helperText">
|
||||||
|
<translate>Please click the button below to visit Ansible's website to get a Tower license key.</translate>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="License-downloadLicenseButton btn btn-primary" ng-if="licenseMissing" ng-click="downloadLicense()">
|
||||||
|
<translate>Request License</translate>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="AddPermissions-directions">
|
||||||
|
<span class="AddPermissions-directionNumber" ng-if="licenseMissing">
|
||||||
|
2
|
||||||
|
</span>
|
||||||
|
<span class="License-helperText">
|
||||||
|
<translate>Choose your license file, agree to the End User License Agreement, and click submit.</translate>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="License-subTitleText">
|
||||||
|
<span class="Form-requiredAsterisk">*</span>
|
||||||
|
<translate>License</translate>
|
||||||
|
</div>
|
||||||
|
<div class="License-helperText License-licenseStepHelp" translate>Upload a license file</div>
|
||||||
|
<div class="License-filePicker">
|
||||||
|
<span class="btn btn-primary" ng-click="fakeClick()" ng-disabled="!user_is_superuser || (rhCreds.username && rhCreds.username.length > 0) || (rhCreds.password && rhCreds.password.length > 0)" translate>Browse</span>
|
||||||
|
<span class="License-fileName" ng-class="{'License-helperText' : fileName == 'No file selected.'}">{{fileName|translate}}</span>
|
||||||
|
<input id="License-file" class="form-control" type="file" file-on-change="getKey"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="License-file--middle License-helperText" translate>
|
||||||
|
<div class="License-separator"></div>
|
||||||
|
<div translate>OR</div>
|
||||||
|
<div class="License-separator"></div>
|
||||||
|
</div>
|
||||||
|
<div class="License-file--right">
|
||||||
|
<div class="d-block w-100">
|
||||||
|
<div class="AddPermissions-directions">
|
||||||
|
<span class="License-helperText">
|
||||||
|
<translate>Provide your Red Hat customer credentials and you can choose from a list of your available licenses. The credentials you use will be stored for future use in retrieving renewal or expanded licenses. You can update or remove them in SETTINGS > SYSTEM.</translate>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="License-rhCredField">
|
||||||
|
<label class="License-label d-block" translate>USERNAME</label>
|
||||||
|
<input class="form-control Form-textInput" type="text" ng-model="rhCreds.username" ng-disabled="!user_is_superuser || newLicense.file" />
|
||||||
|
</div>
|
||||||
|
<div class="License-rhCredField">
|
||||||
|
<label class="License-label d-block" translate>PASSWORD</label>
|
||||||
|
<div class="input-group Form-mixedInputGroup" ng-if="showPlaceholderPassword">
|
||||||
|
<input class="form-control Form-textInput" type="text" value="ENCRYPTED" disabled />
|
||||||
|
<span class="input-group-btn input-group-append">
|
||||||
|
<button class="btn at-ButtonHollow--default at-Input-button" ng-disabled="!user_is_superuser || newLicense.file" ng-click="replacePassword()" aw-tool-tip="Replace" data-placement="top" data-original-title="Replace">
|
||||||
|
<i class="fa fa-undo"></i>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="input-group" ng-if="!showPlaceholderPassword">
|
||||||
|
<input id="rh-password" class="form-control Form-textInput" type="password" ng-model="rhCreds.password" ng-disabled="!user_is_superuser || newLicense.file" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="License-getLicensesButton">
|
||||||
|
<span ng-click="lookupLicenses()" class="btn btn-primary" ng-disabled="!rhCreds.username || !rhCreds.password" translate>GET LICENSES</button>
|
||||||
|
</div>
|
||||||
|
<div ng-if="selectedLicense.fullLicense">
|
||||||
|
<div class="at-RowItem-label" translate>
|
||||||
|
Selected
|
||||||
|
</div>
|
||||||
|
{{selectedLicense.fullLicense.subscription_name}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="License-subTitleText">
|
||||||
<button class="License-downloadLicenseButton btn btn-primary" ng-if="licenseMissing" ng-click="downloadLicense()">
|
<span class="Form-requiredAsterisk">*</span>
|
||||||
<translate>Request License</translate>
|
<translate>End User License Agreement</translate>
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="AddPermissions-directions">
|
|
||||||
<span class="AddPermissions-directionNumber" ng-if="licenseMissing">
|
|
||||||
2
|
|
||||||
</span>
|
|
||||||
<span class="License-helperText">
|
|
||||||
<translate>Choose your license file, agree to the End User License Agreement, and click submit.</translate>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div id="eula_notice"
|
||||||
<form id="License-form" name="uploadlicense">
|
class="License-eulaNotice">{{ license.eula }}</div>
|
||||||
<div class="License-subTitleText">
|
<div class="form-group License-detailsGroup">
|
||||||
<span class="Form-requiredAsterisk">*</span>
|
<div class="License-analyticsCheckbox checkbox">
|
||||||
<translate>License File</translate>
|
<label class="License-details--label">
|
||||||
|
<input type="checkbox" ng-model="newLicense.eula" ng-disabled="!user_is_superuser" required>
|
||||||
|
<span class="License-checkboxLabel" translate><b>I agree to the End User License Agreement</b></span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group License-file--container">
|
</div>
|
||||||
<span class="btn btn-primary" ng-click="fakeClick()" ng-disabled="!user_is_superuser" translate>Browse</span>
|
<div class="License-subTitleText" ng-if="licenseMissing">
|
||||||
<span class="License-fileName" ng-class="{'License-helperText' : fileName == 'No file selected.'}">{{fileName|translate}}</span>
|
<translate>Tracking and Analytics</translate>
|
||||||
<input id="License-file" class="form-control" type="file" file-on-change="getKey"/>
|
</div>
|
||||||
</div>
|
<div class="form-group License-detailsGroup" ng-if="licenseMissing">
|
||||||
<div class="License-subTitleText">
|
<span class="License-helperText">
|
||||||
<span class="Form-requiredAsterisk">*</span>
|
<translate>
|
||||||
<translate>End User License Agreement</translate>
|
By default, Tower collects and transmits analytics data on Tower usage to Red Hat. There are two categories of data collected by Tower. For more information, see <a target="_blank" href="http://docs.ansible.com/ansible-tower/latest/html/installandreference/user-data.html#index-0">this Tower documentation page</a>. Uncheck the following boxes to disable this feature.</translate>
|
||||||
</div>
|
</span>
|
||||||
<div id="eula_notice"
|
<div class="License-analyticsCheckboxGroup">
|
||||||
class="License-eulaNotice">{{ license.eula }}</div>
|
|
||||||
<div class="form-group License-detailsGroup">
|
|
||||||
<div class="License-analyticsCheckbox checkbox">
|
<div class="License-analyticsCheckbox checkbox">
|
||||||
<label class="License-details--label">
|
<label class="License-details--label">
|
||||||
<input type="checkbox" ng-model="newLicense.eula" ng-disabled="!user_is_superuser" required>
|
<input type="checkbox" ng-model="newLicense.pendo" ng-disabled="!user_is_superuser">
|
||||||
<translate>I agree to the End User License Agreement</translate>
|
<span class="License-checkboxLabel" translate><b>User analytics</b>: This data is used to enhance future releases of the Tower Software and help streamline customer experience and success.</span>
|
||||||
</label>
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="License-analyticsCheckbox checkbox">
|
||||||
|
<label class="License-details--label">
|
||||||
|
<input id="license-insights" type="checkbox" ng-model="newLicense.insights" ng-disabled="!user_is_superuser">
|
||||||
|
<span class="License-checkboxLabel" translate><b>Automation analytics</b>: This data is used to enhance future releases of the Tower Software and to provide Automation Insights to Tower subscribers.</span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="License-subTitleText" ng-if="licenseMissing">
|
</div>
|
||||||
<translate>Tracking and Analytics</translate>
|
<div class="License-action">
|
||||||
</div>
|
<div class="License-actionError">
|
||||||
<div class="form-group License-detailsGroup" ng-if="licenseMissing">
|
|
||||||
<span class="License-helperText">
|
|
||||||
<translate>
|
|
||||||
By default, Tower collects and transmits analytics data on Tower usage to Red Hat. There are two categories of data collected by Tower. For more information, see <a target="_blank" href="http://docs.ansible.com/ansible-tower/latest/html/installandreference/user-data.html#index-0">this Tower documentation page</a>. Uncheck the following boxes to disable this feature.</translate>
|
|
||||||
</span>
|
|
||||||
<div class="License-analyticsCheckboxGroup">
|
|
||||||
<div class="License-analyticsCheckbox checkbox">
|
|
||||||
<input type="checkbox" ng-model="newLicense.pendo" ng-disabled="!user_is_superuser" required>
|
|
||||||
<translate>User analytics: This data is used to enhance future releases of the Tower Software and help streamline customer experience and success.</translate>
|
|
||||||
</div>
|
|
||||||
<div class="License-analyticsCheckbox checkbox">
|
|
||||||
<input type="checkbox" ng-model="newLicense.insights" ng-disabled="!user_is_superuser" required>
|
|
||||||
<translate>Automation analytics: This data is used to enhance future releases of the Tower Software and to provide Automation Insights to Tower subscribers.</translate>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button ng-click="submit()" class="btn btn-success pull-right" ng-disabled="newLicense.file.license_key == null || newLicense.eula == null || !user_is_superuser" translate>Submit</button>
|
|
||||||
<span ng-show="success == true" class="License-greenText License-submit--success pull-right" translate>Save successful!</span>
|
<span ng-show="success == true" class="License-greenText License-submit--success pull-right" translate>Save successful!</span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
<div>
|
||||||
|
<button ng-click="submit()" class="btn btn-success pull-right" ng-disabled="(!newLicense.file && !selectedLicense.fullLicense) || (newLicense.file && newLicense.file.license_key == null) || newLicense.eula == null || !user_is_superuser" translate>Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="License-subSelectorModal" ng-show="showLicenseModal">
|
||||||
|
<div class="modal-dialog License-modal">
|
||||||
|
<div class="Modal-content modal-content">
|
||||||
|
<div class="Modal-header">
|
||||||
|
<div class="Modal-title" translate>
|
||||||
|
Select a license
|
||||||
|
</div>
|
||||||
|
<div class="Modal-exitHolder">
|
||||||
|
<button class="close Modal-exit" ng-click="cancelLicenseLookup()">
|
||||||
|
<i class="fa fa-times-circle"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="Modal-body ng-binding">
|
||||||
|
<div class="License-modalBody">
|
||||||
|
<form>
|
||||||
|
<div class="License-modalRow" ng-repeat="license in rhLicenses track by license.license_key">
|
||||||
|
<div class="License-modalRowRadio">
|
||||||
|
<input type="radio" id="license-{{license.license_key}}" ng-model="selectedLicense.modalKey" value="{{license.license_key}}" />
|
||||||
|
</div>
|
||||||
|
<div class="License-modalRowDetails">
|
||||||
|
<label for="license-{{license.license_key}}" class="License-modalRowDetailsLabel">
|
||||||
|
<div class="License-modalRowDetailsRow">
|
||||||
|
<div class="License-trialTag" ng-if="license.trial" translate>
|
||||||
|
Trial
|
||||||
|
</div>
|
||||||
|
<b>{{license.subscription_name}}</b>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="License-modalRowDetails--50">
|
||||||
|
<div class="at-RowItem-label" translate>
|
||||||
|
Managed Nodes
|
||||||
|
</div>
|
||||||
|
{{license.instance_count}}
|
||||||
|
</div>
|
||||||
|
<div class="License-modalRowDetails--50">
|
||||||
|
<div class="at-RowItem-label" translate>
|
||||||
|
Expires
|
||||||
|
</div>
|
||||||
|
{{license.license_date | formatEpoch}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="Modal-footer">
|
||||||
|
<button ng-click="cancelLicenseLookup()" class="btn Modal-footerButton Modal-defaultButton">CANCEL</button>
|
||||||
|
<button
|
||||||
|
ng-click="confirmLicenseSelection()"
|
||||||
|
class="btn Modal-footerButton btn-success"
|
||||||
|
ng-disabled="!selectedLicense.modalKey"
|
||||||
|
translate
|
||||||
|
>
|
||||||
|
SELECT
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -17,30 +17,49 @@ export default {
|
|||||||
ncyBreadcrumb: {
|
ncyBreadcrumb: {
|
||||||
label: N_('LICENSE')
|
label: N_('LICENSE')
|
||||||
},
|
},
|
||||||
onEnter: ['$state', 'ConfigService', (state, configService) => {
|
onEnter: ['$state', 'ConfigService', (state, configService) => {
|
||||||
return configService.getConfig()
|
return configService.getConfig()
|
||||||
.then(config => {
|
.then(config => {
|
||||||
if (_.get(config, 'license_info.license_type') === 'open') {
|
if (_.get(config, 'license_info.license_type') === 'open') {
|
||||||
return state.go('setup');
|
return state.go('setup');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}],
|
}],
|
||||||
resolve: {
|
resolve: {
|
||||||
features: ['CheckLicense', '$rootScope',
|
features: ['CheckLicense', '$rootScope',
|
||||||
function(CheckLicense, $rootScope) {
|
function(CheckLicense, $rootScope) {
|
||||||
if($rootScope.licenseMissing === undefined){
|
if($rootScope.licenseMissing === undefined){
|
||||||
return CheckLicense.notify();
|
return CheckLicense.notify();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}],
|
],
|
||||||
config: ['ConfigService', 'CheckLicense', '$rootScope',
|
config: ['ConfigService', 'CheckLicense', '$rootScope',
|
||||||
function(ConfigService, CheckLicense, $rootScope) {
|
function(ConfigService, CheckLicense, $rootScope) {
|
||||||
ConfigService.delete();
|
ConfigService.delete();
|
||||||
return ConfigService.getConfig()
|
return ConfigService.getConfig()
|
||||||
.then(function(config){
|
.then(function(config){
|
||||||
$rootScope.licenseMissing = (CheckLicense.valid(config.license_info) === false) ? true : false;
|
$rootScope.licenseMissing = (CheckLicense.valid(config.license_info) === false) ? true : false;
|
||||||
return config;
|
return config;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
],
|
||||||
|
rhCreds: ['Rest', 'GetBasePath', function(Rest, GetBasePath) {
|
||||||
|
Rest.setUrl(`${GetBasePath('settings')}system/`);
|
||||||
|
return Rest.get()
|
||||||
|
.then(({data}) => {
|
||||||
|
const rhCreds = {};
|
||||||
|
if (data.REDHAT_USERNAME && data.REDHAT_USERNAME !== "") {
|
||||||
|
rhCreds.REDHAT_USERNAME = data.REDHAT_USERNAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.REDHAT_PASSWORD && data.REDHAT_PASSWORD !== "") {
|
||||||
|
rhCreds.REDHAT_PASSWORD = data.REDHAT_PASSWORD;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rhCreds;
|
||||||
|
}).catch(() => {
|
||||||
|
return {};
|
||||||
});
|
});
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -238,9 +238,9 @@ angular.module('Utilities', ['RestServices', 'Utilities'])
|
|||||||
msg = "";
|
msg = "";
|
||||||
_.forOwn(data, function(value, key) {
|
_.forOwn(data, function(value, key) {
|
||||||
if (Array.isArray(data[key])) {
|
if (Array.isArray(data[key])) {
|
||||||
msg += `${key}: ${data[key][0]}`;
|
msg += `${key.toUpperCase()}: ${data[key][0]}`;
|
||||||
} else {
|
} else {
|
||||||
msg += `${key} : ${value} `;
|
msg += `${key.toUpperCase()}: ${value} `;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Alert(defaultMsg.hdr, msg);
|
Alert(defaultMsg.hdr, msg);
|
||||||
|
|||||||
@@ -58,6 +58,11 @@ export default
|
|||||||
deferred.reject('Config not found.');
|
deferred.reject('Config not found.');
|
||||||
}
|
}
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
|
},
|
||||||
|
|
||||||
|
getSubscriptions: function(username, password) {
|
||||||
|
Rest.setUrl(`${GetBasePath('config')}subscriptions`);
|
||||||
|
return Rest.post({ rh_username: username, rh_password: password} );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ describe('Controller: LicenseController', () => {
|
|||||||
LicenseController,
|
LicenseController,
|
||||||
ConfigService,
|
ConfigService,
|
||||||
ProcessErrors,
|
ProcessErrors,
|
||||||
config;
|
config,
|
||||||
|
rhCreds;
|
||||||
|
|
||||||
beforeEach(angular.mock.module('awApp'));
|
beforeEach(angular.mock.module('awApp'));
|
||||||
beforeEach(angular.mock.module('license', ($provide) => {
|
beforeEach(angular.mock.module('license', ($provide) => {
|
||||||
@@ -22,23 +23,31 @@ describe('Controller: LicenseController', () => {
|
|||||||
version: '3.1.0-devel'
|
version: '3.1.0-devel'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
rhCreds = {
|
||||||
|
password: '$encrypted$',
|
||||||
|
username: 'foo',
|
||||||
|
}
|
||||||
|
|
||||||
ProcessErrors = jasmine.createSpy('ProcessErrors');
|
ProcessErrors = jasmine.createSpy('ProcessErrors');
|
||||||
|
|
||||||
$provide.value('ConfigService', ConfigService);
|
$provide.value('ConfigService', ConfigService);
|
||||||
$provide.value('ProcessErrors', ProcessErrors);
|
$provide.value('ProcessErrors', ProcessErrors);
|
||||||
$provide.value('config', config);
|
$provide.value('config', config);
|
||||||
|
$provide.value('rhCreds', rhCreds);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(angular.mock.inject( ($rootScope, $controller, _ConfigService_, _ProcessErrors_, _config_) => {
|
beforeEach(angular.mock.inject( ($rootScope, $controller, _ConfigService_, _ProcessErrors_, _config_, _rhCreds_) => {
|
||||||
scope = $rootScope.$new();
|
scope = $rootScope.$new();
|
||||||
ConfigService = _ConfigService_;
|
ConfigService = _ConfigService_;
|
||||||
ProcessErrors = _ProcessErrors_;
|
ProcessErrors = _ProcessErrors_;
|
||||||
config = _config_;
|
config = _config_;
|
||||||
|
rhCreds = _rhCreds_;
|
||||||
LicenseController = $controller('licenseController', {
|
LicenseController = $controller('licenseController', {
|
||||||
$scope: scope,
|
$scope: scope,
|
||||||
ConfigService: ConfigService,
|
ConfigService: ConfigService,
|
||||||
ProcessErrors: ProcessErrors,
|
ProcessErrors: ProcessErrors,
|
||||||
config: config
|
config: config,
|
||||||
|
rhCreds: rhCreds
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -38,3 +38,4 @@ from .instances import * # NOQA
|
|||||||
from .instance_groups import * # NOQA
|
from .instance_groups import * # NOQA
|
||||||
from .credential_input_sources import * # NOQA
|
from .credential_input_sources import * # NOQA
|
||||||
from .metrics import * # NOQA
|
from .metrics import * # NOQA
|
||||||
|
from .subscriptions import * # NOQA
|
||||||
|
|||||||
11
awxkit/awxkit/api/pages/subscriptions.py
Normal file
11
awxkit/awxkit/api/pages/subscriptions.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from awxkit.api.resources import resources
|
||||||
|
from . import page
|
||||||
|
|
||||||
|
|
||||||
|
class Subscriptions(page.Page):
|
||||||
|
|
||||||
|
def get_possible_licenses(self, **kwargs):
|
||||||
|
return self.post(json=kwargs).json
|
||||||
|
|
||||||
|
|
||||||
|
page.register_page(resources.subscriptions, Subscriptions)
|
||||||
@@ -265,6 +265,7 @@ class Resources(object):
|
|||||||
_workflow_job_template_workflow_nodes = r'workflow_job_templates/\d+/workflow_nodes/'
|
_workflow_job_template_workflow_nodes = r'workflow_job_templates/\d+/workflow_nodes/'
|
||||||
_workflow_job_templates = 'workflow_job_templates/'
|
_workflow_job_templates = 'workflow_job_templates/'
|
||||||
_workflow_job_workflow_nodes = r'workflow_jobs/\d+/workflow_nodes/'
|
_workflow_job_workflow_nodes = r'workflow_jobs/\d+/workflow_nodes/'
|
||||||
|
_subscriptions = 'config/subscriptions/'
|
||||||
_workflow_jobs = 'workflow_jobs/'
|
_workflow_jobs = 'workflow_jobs/'
|
||||||
api = '/api/'
|
api = '/api/'
|
||||||
common = api + r'v\d+/'
|
common = api + r'v\d+/'
|
||||||
|
|||||||
Reference in New Issue
Block a user