Merge pull request #7629 from ryanpetrello/k8s-creds

add the ability to specify K8S/OCP credentials on a Job Template

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
softwarefactory-project-zuul[bot]
2020-07-17 17:07:46 +00:00
committed by GitHub
16 changed files with 117 additions and 25 deletions

View File

@@ -4100,7 +4100,8 @@ class JobLaunchSerializer(BaseSerializer):
errors.setdefault('credentials', []).append(_( errors.setdefault('credentials', []).append(_(
'Cannot assign multiple {} credentials.' 'Cannot assign multiple {} credentials.'
).format(cred.unique_hash(display=True))) ).format(cred.unique_hash(display=True)))
if cred.credential_type.kind not in ('ssh', 'vault', 'cloud', 'net'): if cred.credential_type.kind not in ('ssh', 'vault', 'cloud',
'net', 'kubernetes'):
errors.setdefault('credentials', []).append(_( errors.setdefault('credentials', []).append(_(
'Cannot assign a Credential of kind `{}`' 'Cannot assign a Credential of kind `{}`'
).format(cred.credential_type.kind)) ).format(cred.credential_type.kind))

View File

@@ -2657,7 +2657,7 @@ class JobTemplateCredentialsList(SubListCreateAttachDetachAPIView):
return {"error": _("Cannot assign multiple {credential_type} credentials.").format( return {"error": _("Cannot assign multiple {credential_type} credentials.").format(
credential_type=sub.unique_hash(display=True))} credential_type=sub.unique_hash(display=True))}
kind = sub.credential_type.kind kind = sub.credential_type.kind
if kind not in ('ssh', 'vault', 'cloud', 'net'): if kind not in ('ssh', 'vault', 'cloud', 'net', 'kubernetes'):
return {'error': _('Cannot assign a Credential of kind `{}`.').format(kind)} return {'error': _('Cannot assign a Credential of kind `{}`.').format(kind)}
return super(JobTemplateCredentialsList, self).is_valid_relation(parent, sub, created) return super(JobTemplateCredentialsList, self).is_valid_relation(parent, sub, created)

View File

@@ -101,3 +101,17 @@ def openstack(cred, env, private_data_dir):
f.close() f.close()
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR) os.chmod(path, stat.S_IRUSR | stat.S_IWUSR)
env['OS_CLIENT_CONFIG_FILE'] = path env['OS_CLIENT_CONFIG_FILE'] = path
def kubernetes_bearer_token(cred, env, private_data_dir):
env['K8S_AUTH_HOST'] = cred.get_input('host', default='')
env['K8S_AUTH_API_KEY'] = cred.get_input('bearer_token', default='')
if cred.get_input('verify_ssl') and 'ssl_ca_cert' in cred.inputs:
env['K8S_AUTH_VERIFY_SSL'] = 'True'
handle, path = tempfile.mkstemp(dir=private_data_dir)
with os.fdopen(handle, 'w') as f:
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR)
f.write(cred.get_input('ssl_ca_cert'))
env['K8S_AUTH_SSL_CA_CERT'] = path
else:
env['K8S_AUTH_VERIFY_SSL'] = 'False'

View File

@@ -220,7 +220,7 @@ def test_create_valid_kind(kind, get, post, admin):
@pytest.mark.django_db @pytest.mark.django_db
@pytest.mark.parametrize('kind', ['ssh', 'vault', 'scm', 'insights']) @pytest.mark.parametrize('kind', ['ssh', 'vault', 'scm', 'insights', 'kubernetes'])
def test_create_invalid_kind(kind, get, post, admin): def test_create_invalid_kind(kind, get, post, admin):
response = post(reverse('api:credential_type_list'), { response = post(reverse('api:credential_type_list'), {
'kind': kind, 'kind': kind,

View File

@@ -483,25 +483,26 @@ def test_job_launch_pass_with_prompted_vault_password(machine_credential, vault_
@pytest.mark.django_db @pytest.mark.django_db
def test_job_launch_JT_with_credentials(machine_credential, credential, net_credential, deploy_jobtemplate): def test_job_launch_JT_with_credentials(machine_credential, credential, net_credential, kube_credential, deploy_jobtemplate):
deploy_jobtemplate.ask_credential_on_launch = True deploy_jobtemplate.ask_credential_on_launch = True
deploy_jobtemplate.save() deploy_jobtemplate.save()
kv = dict(credentials=[credential.pk, net_credential.pk, machine_credential.pk]) kv = dict(credentials=[credential.pk, net_credential.pk, machine_credential.pk, kube_credential.pk])
serializer = JobLaunchSerializer(data=kv, context={'template': deploy_jobtemplate}) serializer = JobLaunchSerializer(data=kv, context={'template': deploy_jobtemplate})
validated = serializer.is_valid() validated = serializer.is_valid()
assert validated, serializer.errors assert validated, serializer.errors
kv['credentials'] = [credential, net_credential, machine_credential] # convert to internal value kv['credentials'] = [credential, net_credential, machine_credential, kube_credential] # convert to internal value
prompted_fields, ignored_fields, errors = deploy_jobtemplate._accept_or_ignore_job_kwargs( prompted_fields, ignored_fields, errors = deploy_jobtemplate._accept_or_ignore_job_kwargs(
_exclude_errors=['required', 'prompts'], **kv) _exclude_errors=['required', 'prompts'], **kv)
job_obj = deploy_jobtemplate.create_unified_job(**prompted_fields) job_obj = deploy_jobtemplate.create_unified_job(**prompted_fields)
creds = job_obj.credentials.all() creds = job_obj.credentials.all()
assert len(creds) == 3 assert len(creds) == 4
assert credential in creds assert credential in creds
assert net_credential in creds assert net_credential in creds
assert machine_credential in creds assert machine_credential in creds
assert kube_credential in creds
@pytest.mark.django_db @pytest.mark.django_db

View File

@@ -1037,6 +1037,43 @@ class TestJobCredentials(TestJobExecution):
assert '--vault-id dev@prompt' in ' '.join(args) assert '--vault-id dev@prompt' in ' '.join(args)
assert '--vault-id prod@prompt' in ' '.join(args) assert '--vault-id prod@prompt' in ' '.join(args)
@pytest.mark.parametrize("verify", (True, False))
def test_k8s_credential(self, job, private_data_dir, verify):
k8s = CredentialType.defaults['kubernetes_bearer_token']()
inputs = {
'host': 'https://example.org/',
'bearer_token': 'token123',
}
if verify:
inputs['verify_ssl'] = True
inputs['ssl_ca_cert'] = 'CERTDATA'
credential = Credential(
pk=1,
credential_type=k8s,
inputs = inputs,
)
credential.inputs['bearer_token'] = encrypt_field(credential, 'bearer_token')
job.credentials.add(credential)
env = {}
safe_env = {}
credential.credential_type.inject_credential(
credential, env, safe_env, [], private_data_dir
)
assert env['K8S_AUTH_HOST'] == 'https://example.org/'
assert env['K8S_AUTH_API_KEY'] == 'token123'
if verify:
assert env['K8S_AUTH_VERIFY_SSL'] == 'True'
cert = open(env['K8S_AUTH_SSL_CA_CERT'], 'r').read()
assert cert == 'CERTDATA'
else:
assert env['K8S_AUTH_VERIFY_SSL'] == 'False'
assert 'K8S_AUTH_SSL_CA_CERT' not in env
assert safe_env['K8S_AUTH_API_KEY'] == tasks.HIDDEN_PASSWORD
def test_aws_cloud_credential(self, job, private_data_dir): def test_aws_cloud_credential(self, job, private_data_dir):
aws = CredentialType.defaults['aws']() aws = CredentialType.defaults['aws']()
credential = Credential( credential = Credential(

View File

@@ -67,6 +67,10 @@
&--external:before { &--external:before {
content: '\f14c' content: '\f14c'
} }
&--kubernetes:before, &--kubernetes_bearer_token:before {
content: '\f0c2';
}
} }
.TagComponent-button { .TagComponent-button {

View File

@@ -111,7 +111,7 @@ function multiCredentialModalController(GetBasePath, qs, MultiCredentialService)
scope.credentialTypes.forEach((credentialType => { scope.credentialTypes.forEach((credentialType => {
if(credentialType.kind if(credentialType.kind
.match(/^(machine|cloud|net|ssh|vault)$/)) { .match(/^(machine|cloud|net|ssh|vault|kubernetes)$/)) {
scope.displayedCredentialTypes.push(credentialType); scope.displayedCredentialTypes.push(credentialType);
} }
})); }));

View File

@@ -29,6 +29,7 @@
<i class="fa fa-code-fork MultiCredential-tagIcon" ng-switch-when="scm"></i> <i class="fa fa-code-fork MultiCredential-tagIcon" ng-switch-when="scm"></i>
<i class="fa fa-key MultiCredential-tagIcon" ng-switch-when="ssh"></i> <i class="fa fa-key MultiCredential-tagIcon" ng-switch-when="ssh"></i>
<i class="fa fa-archive MultiCredential-tagIcon" ng-switch-when="vault"></i> <i class="fa fa-archive MultiCredential-tagIcon" ng-switch-when="vault"></i>
<i class="fa fa-cloud MultiCredential-tagIcon" ng-switch-when="kubernetes"></i>
</div> </div>
<div class="MultiCredential-tag MultiCredential-tag--deletable"> <div class="MultiCredential-tag MultiCredential-tag--deletable">
<span ng-if="!tag.info" class="MultiCredential-name--label ng-binding"> <span ng-if="!tag.info" class="MultiCredential-name--label ng-binding">

View File

@@ -26,6 +26,7 @@
<i class="fa fa-code-fork MultiCredential-tagIcon" ng-switch-when="scm"></i> <i class="fa fa-code-fork MultiCredential-tagIcon" ng-switch-when="scm"></i>
<i class="fa fa-key MultiCredential-tagIcon" ng-switch-when="ssh"></i> <i class="fa fa-key MultiCredential-tagIcon" ng-switch-when="ssh"></i>
<i class="fa fa-archive MultiCredential-tagIcon" ng-switch-when="vault"></i> <i class="fa fa-archive MultiCredential-tagIcon" ng-switch-when="vault"></i>
<i class="fa fa-cloud MultiCredential-tagIcon" ng-switch-when="kubernetes"></i>
</div> </div>
<div class="MultiCredential-iconContainer" ng-switch="tag.kind" ng-if="!fieldIsDisabled"> <div class="MultiCredential-iconContainer" ng-switch="tag.kind" ng-if="!fieldIsDisabled">
<i class="fa fa-cloud MultiCredential-tagIcon" ng-switch-when="cloud"></i> <i class="fa fa-cloud MultiCredential-tagIcon" ng-switch-when="cloud"></i>
@@ -34,6 +35,7 @@
<i class="fa fa-code-fork MultiCredential-tagIcon" ng-switch-when="scm"></i> <i class="fa fa-code-fork MultiCredential-tagIcon" ng-switch-when="scm"></i>
<i class="fa fa-key MultiCredential-tagIcon" ng-switch-when="ssh"></i> <i class="fa fa-key MultiCredential-tagIcon" ng-switch-when="ssh"></i>
<i class="fa fa-archive MultiCredential-tagIcon" ng-switch-when="vault"></i> <i class="fa fa-archive MultiCredential-tagIcon" ng-switch-when="vault"></i>
<i class="fa fa-cloud MultiCredential-tagIcon" ng-switch-when="kubernetes"></i>
</div> </div>
<div class="MultiCredential-tag" <div class="MultiCredential-tag"
ng-class="{'MultiCredential-tag--deletable': !fieldIsDisabled, 'MultiCredential-tag--disabled': fieldIsDisabled}"> ng-class="{'MultiCredential-tag--deletable': !fieldIsDisabled, 'MultiCredential-tag--disabled': fieldIsDisabled}">

View File

@@ -55,7 +55,7 @@ export default [ 'ProcessErrors', 'CredentialTypeModel', 'TemplatesStrings', '$f
vm.promptDataClone.prompts.credentials.credentialTypeOptions = []; vm.promptDataClone.prompts.credentials.credentialTypeOptions = [];
response.data.results.forEach((credentialTypeRow => { response.data.results.forEach((credentialTypeRow => {
vm.promptDataClone.prompts.credentials.credentialTypes[credentialTypeRow.id] = credentialTypeRow.kind; vm.promptDataClone.prompts.credentials.credentialTypes[credentialTypeRow.id] = credentialTypeRow.kind;
if(credentialTypeRow.kind.match(/^(cloud|net|ssh|vault)$/)) { if(credentialTypeRow.kind.match(/^(cloud|net|ssh|vault|kubernetes)$/)) {
if(credentialTypeRow.kind === 'ssh') { if(credentialTypeRow.kind === 'ssh') {
vm.promptDataClone.prompts.credentials.credentialKind = credentialTypeRow.id.toString(); vm.promptDataClone.prompts.credentials.credentialKind = credentialTypeRow.id.toString();
} }

View File

@@ -7,7 +7,7 @@ class CredentialTypes extends Base {
} }
async loadAllTypes( async loadAllTypes(
acceptableKinds = ['machine', 'cloud', 'net', 'ssh', 'vault'] acceptableKinds = ['machine', 'cloud', 'net', 'ssh', 'vault', 'kubernetes']
) { ) {
const pageSize = 200; const pageSize = 200;
// The number of credential types a user can have is unlimited. In practice, it is unlikely for // The number of credential types a user can have is unlimited. In practice, it is unlikely for

View File

@@ -0,0 +1,23 @@
The MIT License (MIT)
Copyright (c) 2007-2017 Anthon van der Neut/Ruamel BVBA
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -32,8 +32,8 @@ django-oauth-toolkit==1.1.3 # via -r /awx_devel/requirements/requirements.in
django-pglocks==1.0.4 # via -r /awx_devel/requirements/requirements.in django-pglocks==1.0.4 # via -r /awx_devel/requirements/requirements.in
django-polymorphic==2.1.2 # via -r /awx_devel/requirements/requirements.in django-polymorphic==2.1.2 # via -r /awx_devel/requirements/requirements.in
django-qsstats-magic==1.1.0 # via -r /awx_devel/requirements/requirements.in django-qsstats-magic==1.1.0 # via -r /awx_devel/requirements/requirements.in
django-redis==4.5.0
django-radius==1.3.3 # via -r /awx_devel/requirements/requirements.in django-radius==1.3.3 # via -r /awx_devel/requirements/requirements.in
django-redis==4.5.0 # via -r /awx_devel/requirements/requirements.in
django-solo==1.1.3 # via -r /awx_devel/requirements/requirements.in django-solo==1.1.3 # via -r /awx_devel/requirements/requirements.in
django-split-settings==1.0.0 # via -r /awx_devel/requirements/requirements.in django-split-settings==1.0.0 # via -r /awx_devel/requirements/requirements.in
django-taggit==1.2.0 # via -r /awx_devel/requirements/requirements.in django-taggit==1.2.0 # via -r /awx_devel/requirements/requirements.in
@@ -100,7 +100,7 @@ python3-openid==3.1.0 # via social-auth-core
python3-saml==1.9.0 # via -r /awx_devel/requirements/requirements.in python3-saml==1.9.0 # via -r /awx_devel/requirements/requirements.in
pytz==2019.3 # via django, irc, tempora, twilio pytz==2019.3 # via django, irc, tempora, twilio
pyyaml==5.3.1 # via -r /awx_devel/requirements/requirements.in, ansible-runner, djangorestframework-yaml, kubernetes pyyaml==5.3.1 # via -r /awx_devel/requirements/requirements.in, ansible-runner, djangorestframework-yaml, kubernetes
redis==3.4.1 # via -r /awx_devel/requirements/requirements.in redis==3.4.1 # via -r /awx_devel/requirements/requirements.in, django-redis
requests-oauthlib==1.3.0 # via kubernetes, msrest, social-auth-core requests-oauthlib==1.3.0 # via kubernetes, msrest, social-auth-core
requests==2.23.0 # via -r /awx_devel/requirements/requirements.in, adal, azure-keyvault, django-oauth-toolkit, kubernetes, msrest, requests-oauthlib, slackclient, social-auth-core, twilio requests==2.23.0 # via -r /awx_devel/requirements/requirements.in, adal, azure-keyvault, django-oauth-toolkit, kubernetes, msrest, requests-oauthlib, slackclient, social-auth-core, twilio
rsa==4.0 # via google-auth rsa==4.0 # via google-auth

View File

@@ -62,5 +62,7 @@ requests
requests-credssp==1.0.2 # For windows authentication awx/issues/1144 requests-credssp==1.0.2 # For windows authentication awx/issues/1144
# OpenStack # OpenStack
openstacksdk==0.37.0 openstacksdk==0.37.0
# Openshift/k8s
openshift>=0.11.0 # minimum version to pull in new pyyaml for CVE-2017-18342
pip==19.3.1 # see upgrade blockers pip==19.3.1 # see upgrade blockers
setuptools==41.6.0 # see upgrade blockers setuptools==41.6.0 # see upgrade blockers

View File

@@ -26,7 +26,7 @@ azure-mgmt-loganalytics==0.2.0 # via -r /awx_devel/requirements/requirements_an
azure-mgmt-marketplaceordering==0.1.0 # via -r /awx_devel/requirements/requirements_ansible.in azure-mgmt-marketplaceordering==0.1.0 # via -r /awx_devel/requirements/requirements_ansible.in
azure-mgmt-monitor==0.5.2 # via -r /awx_devel/requirements/requirements_ansible.in azure-mgmt-monitor==0.5.2 # via -r /awx_devel/requirements/requirements_ansible.in
azure-mgmt-network==2.3.0 # via -r /awx_devel/requirements/requirements_ansible.in azure-mgmt-network==2.3.0 # via -r /awx_devel/requirements/requirements_ansible.in
azure-mgmt-nspkg==2.0.0 # via -r /awx_devel/requirements/requirements_ansible.in, azure-mgmt-authorization, azure-mgmt-automation, azure-mgmt-batch, azure-mgmt-cdn, azure-mgmt-compute, azure-mgmt-containerinstance, azure-mgmt-containerregistry, azure-mgmt-containerservice, azure-mgmt-cosmosdb, azure-mgmt-devtestlabs, azure-mgmt-dns, azure-mgmt-hdinsight, azure-mgmt-iothub, azure-mgmt-keyvault, azure-mgmt-loganalytics, azure-mgmt-marketplaceordering, azure-mgmt-monitor, azure-mgmt-network, azure-mgmt-rdbms, azure-mgmt-redis, azure-mgmt-resource, azure-mgmt-servicebus, azure-mgmt-sql, azure-mgmt-storage, azure-mgmt-trafficmanager, azure-mgmt-web azure-mgmt-nspkg==2.0.0; python_version < "3" # via -r /awx_devel/requirements/requirements_ansible.in, azure-mgmt-authorization, azure-mgmt-automation, azure-mgmt-batch, azure-mgmt-cdn, azure-mgmt-compute, azure-mgmt-containerinstance, azure-mgmt-containerregistry, azure-mgmt-containerservice, azure-mgmt-cosmosdb, azure-mgmt-devtestlabs, azure-mgmt-dns, azure-mgmt-hdinsight, azure-mgmt-iothub, azure-mgmt-keyvault, azure-mgmt-loganalytics, azure-mgmt-marketplaceordering, azure-mgmt-monitor, azure-mgmt-network, azure-mgmt-rdbms, azure-mgmt-redis, azure-mgmt-resource, azure-mgmt-servicebus, azure-mgmt-sql, azure-mgmt-storage, azure-mgmt-trafficmanager, azure-mgmt-web
azure-mgmt-rdbms==1.4.1 # via -r /awx_devel/requirements/requirements_ansible.in azure-mgmt-rdbms==1.4.1 # via -r /awx_devel/requirements/requirements_ansible.in
azure-mgmt-redis==5.0.0 # via -r /awx_devel/requirements/requirements_ansible.in azure-mgmt-redis==5.0.0 # via -r /awx_devel/requirements/requirements_ansible.in
azure-mgmt-resource==2.1.0 # via -r /awx_devel/requirements/requirements_ansible.in azure-mgmt-resource==2.1.0 # via -r /awx_devel/requirements/requirements_ansible.in
@@ -43,7 +43,7 @@ boto3==1.9.223 # via -r /awx_devel/requirements/requirements_ansible.
boto==2.47.0 # via -r /awx_devel/requirements/requirements_ansible.in boto==2.47.0 # via -r /awx_devel/requirements/requirements_ansible.in
botocore==1.12.253 # via boto3, s3transfer botocore==1.12.253 # via boto3, s3transfer
cachetools==3.1.1 # via google-auth cachetools==3.1.1 # via google-auth
certifi==2019.11.28 # via msrest, requests certifi==2019.11.28 # via kubernetes, msrest, requests
cffi==1.13.2 # via bcrypt, cryptography, pynacl cffi==1.13.2 # via bcrypt, cryptography, pynacl
chardet==3.0.4 # via requests chardet==3.0.4 # via requests
colorama==0.4.3 # via azure-cli-core, knack colorama==0.4.3 # via azure-cli-core, knack
@@ -53,18 +53,19 @@ docutils==0.15.2 # via botocore
dogpile.cache==0.9.0 # via openstacksdk dogpile.cache==0.9.0 # via openstacksdk
enum34==1.1.6; python_version < "3" # via cryptography, knack, msrest, ovirt-engine-sdk-python enum34==1.1.6; python_version < "3" # via cryptography, knack, msrest, ovirt-engine-sdk-python
futures==3.3.0; python_version < "3" # via openstacksdk, s3transfer futures==3.3.0; python_version < "3" # via openstacksdk, s3transfer
google-auth==1.6.2 # via -r /awx_devel/requirements/requirements_ansible.in google-auth==1.6.2 # via -r /awx_devel/requirements/requirements_ansible.in, kubernetes
humanfriendly==4.18 # via azure-cli-core humanfriendly==4.18 # via azure-cli-core
idna==2.8 # via requests idna==2.8 # via requests
ipaddress==1.0.23; python_version < "3" # via cryptography, openstacksdk ipaddress==1.0.23; python_version < "3" # via cryptography, kubernetes, openstacksdk
iso8601==0.1.12 # via keystoneauth1, openstacksdk iso8601==0.1.12 # via keystoneauth1, openstacksdk
isodate==0.6.0 # via msrest isodate==0.6.0 # via msrest
jinja2==2.10.1 # via -r /awx_devel/requirements/requirements_ansible.in jinja2==2.10.1 # via -r /awx_devel/requirements/requirements_ansible.in, openshift
jmespath==0.9.4 # via azure-cli-core, boto3, botocore, knack, openstacksdk jmespath==0.9.4 # via azure-cli-core, boto3, botocore, knack, openstacksdk
jsonpatch==1.24 # via openstacksdk jsonpatch==1.24 # via openstacksdk
jsonpointer==2.0 # via jsonpatch jsonpointer==2.0 # via jsonpatch
keystoneauth1==3.18.0 # via openstacksdk keystoneauth1==3.18.0 # via openstacksdk
knack==0.3.3 # via azure-cli-core knack==0.3.3 # via azure-cli-core
kubernetes==11.0.0 # via openshift
lxml==4.4.2 # via ncclient lxml==4.4.2 # via ncclient
markupsafe==1.1.1 # via jinja2 markupsafe==1.1.1 # via jinja2
monotonic==1.5; python_version < "3" # via humanfriendly monotonic==1.5; python_version < "3" # via humanfriendly
@@ -76,6 +77,7 @@ netaddr==0.7.19 # via -r /awx_devel/requirements/requirements_ansible.
netifaces==0.10.9 # via openstacksdk netifaces==0.10.9 # via openstacksdk
ntlm-auth==1.4.0 # via requests-credssp, requests-ntlm ntlm-auth==1.4.0 # via requests-credssp, requests-ntlm
oauthlib==3.1.0 # via requests-oauthlib oauthlib==3.1.0 # via requests-oauthlib
openshift==0.11.2 # via -r /awx_devel/requirements/requirements_ansible.in
openstacksdk==0.37.0 # via -r /awx_devel/requirements/requirements_ansible.in openstacksdk==0.37.0 # via -r /awx_devel/requirements/requirements_ansible.in
os-service-types==1.7.0 # via keystoneauth1, openstacksdk os-service-types==1.7.0 # via keystoneauth1, openstacksdk
ovirt-engine-sdk-python==4.3.0 # via -r /awx_devel/requirements/requirements_ansible.in ovirt-engine-sdk-python==4.3.0 # via -r /awx_devel/requirements/requirements_ansible.in
@@ -93,27 +95,32 @@ pykerberos==1.2.1 # via requests-kerberos
pynacl==1.3.0 # via paramiko pynacl==1.3.0 # via paramiko
pyopenssl==19.1.0 # via azure-cli-core, requests-credssp pyopenssl==19.1.0 # via azure-cli-core, requests-credssp
pyparsing==2.4.5 # via packaging pyparsing==2.4.5 # via packaging
python-dateutil==2.8.1 # via adal, azure-storage, botocore python-dateutil==2.8.1 # via adal, azure-storage, botocore, kubernetes
python-string-utils==0.6.0; python_version < "3" # via openshift
pyvmomi==6.7.3 # via -r /awx_devel/requirements/requirements_ansible.in pyvmomi==6.7.3 # via -r /awx_devel/requirements/requirements_ansible.in
pywinrm[kerberos]==0.3.0 # via -r /awx_devel/requirements/requirements_ansible.in pywinrm[kerberos]==0.3.0 # via -r /awx_devel/requirements/requirements_ansible.in
pyyaml==5.2 # via azure-cli-core, knack, openstacksdk pyyaml==5.2 # via azure-cli-core, knack, kubernetes, openstacksdk
requests-credssp==1.0.2 # via -r /awx_devel/requirements/requirements_ansible.in requests-credssp==1.0.2 # via -r /awx_devel/requirements/requirements_ansible.in
requests-kerberos==0.12.0 # via pywinrm requests-kerberos==0.12.0 # via pywinrm
requests-ntlm==1.1.0 # via pywinrm requests-ntlm==1.1.0 # via pywinrm
requests-oauthlib==1.3.0 # via msrest requests-oauthlib==1.3.0 # via kubernetes, msrest
requests==2.22.0 # via -r /awx_devel/requirements/requirements_ansible.in, adal, apache-libcloud, azure-cli-core, azure-keyvault, azure-storage, keystoneauth1, msrest, pyvmomi, pywinrm, requests-credssp, requests-kerberos, requests-ntlm, requests-oauthlib requests==2.22.0 # via -r /awx_devel/requirements/requirements_ansible.in, adal, apache-libcloud, azure-cli-core, azure-keyvault, azure-storage, keystoneauth1, kubernetes, msrest, pyvmomi, pywinrm, requests-credssp, requests-kerberos, requests-ntlm, requests-oauthlib
requestsexceptions==1.4.0 # via openstacksdk requestsexceptions==1.4.0 # via openstacksdk
rsa==4.0 # via google-auth rsa==4.0 # via google-auth
ruamel.ordereddict==0.4.14; python_version < "3" # via ruamel.yaml
ruamel.yaml.clib==0.2.0 # via ruamel.yaml
ruamel.yaml==0.16.10 # via openshift
s3transfer==0.2.1 # via boto3 s3transfer==0.2.1 # via boto3
selectors2==2.0.1 # via ncclient selectors2==2.0.1 # via ncclient
six==1.13.0 # via azure-cli-core, bcrypt, cryptography, google-auth, isodate, keystoneauth1, knack, munch, ncclient, openstacksdk, ovirt-engine-sdk-python, packaging, pynacl, pyopenssl, python-dateutil, pyvmomi, pywinrm, requests-credssp, stevedore six==1.13.0 # via azure-cli-core, bcrypt, cryptography, google-auth, isodate, keystoneauth1, knack, kubernetes, munch, ncclient, openshift, openstacksdk, ovirt-engine-sdk-python, packaging, pynacl, pyopenssl, python-dateutil, pyvmomi, pywinrm, requests-credssp, stevedore, websocket-client
stevedore==1.31.0 # via keystoneauth1 stevedore==1.31.0 # via keystoneauth1
tabulate==0.8.2 # via azure-cli-core, knack tabulate==0.8.2 # via azure-cli-core, knack
typing==3.7.4.1; python_version < "3" # via msrest typing==3.7.4.1; python_version < "3" # via msrest
urllib3==1.25.7 # via botocore, requests urllib3==1.25.7 # via botocore, kubernetes, requests
websocket-client==0.57.0 # via kubernetes
wheel==0.33.6 # via azure-cli-core (overriden, see upgrade blockers) wheel==0.33.6 # via azure-cli-core (overriden, see upgrade blockers)
xmltodict==0.12.0 # via pywinrm xmltodict==0.12.0 # via pywinrm
# The following packages are considered to be unsafe in a requirements file: # The following packages are considered to be unsafe in a requirements file:
pip==19.3.1 # via -r /awx_devel/requirements/requirements_ansible.in, azure-cli-core pip==19.3.1 # via -r /awx_devel/requirements/requirements_ansible.in, azure-cli-core
setuptools==41.6.0 # via -r /awx_devel/requirements/requirements_ansible.in, ncclient setuptools==41.6.0 # via -r /awx_devel/requirements/requirements_ansible.in, kubernetes, ncclient