Merge "OSC: Add cluster config command"

This commit is contained in:
Jenkins 2017-07-27 14:25:23 +00:00 committed by Gerrit Code Review
commit 83a13e44d8
5 changed files with 196 additions and 236 deletions

View File

@ -16,6 +16,14 @@
# under the License.
import json
import os
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography import x509
from cryptography.x509.oid import NameOID
from magnumclient import exceptions as exc
from magnumclient.i18n import _
@ -142,3 +150,116 @@ def handle_json_from_file(json_arg):
raise exc.InvalidAttribute(err)
return json_arg
def config_cluster(cluster, cluster_template, cfg_dir, force=False):
"""Return and write configuration for the given cluster."""
if cluster_template.coe == 'kubernetes':
return _config_cluster_kubernetes(cluster, cluster_template,
cfg_dir, force)
elif (cluster_template.coe == 'swarm'
or cluster_template.coe == 'swarm-mode'):
return _config_cluster_swarm(cluster, cluster_template, cfg_dir, force)
def _config_cluster_kubernetes(cluster, cluster_template,
cfg_dir, force=False):
"""Return and write configuration for the given kubernetes cluster."""
cfg_file = "%s/config" % cfg_dir
if cluster_template.tls_disabled:
cfg = ("apiVersion: v1\n"
"clusters:\n"
"- cluster:\n"
" server: %(api_address)s\n"
" name: %(name)s\n"
"contexts:\n"
"- context:\n"
" cluster: %(name)s\n"
" user: %(name)s\n"
" name: %(name)s\n"
"current-context: %(name)s\n"
"kind: Config\n"
"preferences: {}\n"
"users:\n"
"- name: %(name)s'\n"
% {'name': cluster.name, 'api_address': cluster.api_address})
else:
cfg = ("apiVersion: v1\n"
"clusters:\n"
"- cluster:\n"
" certificate-authority: %(cfg_dir)s/ca.pem\n"
" server: %(api_address)s\n"
" name: %(name)s\n"
"contexts:\n"
"- context:\n"
" cluster: %(name)s\n"
" user: %(name)s\n"
" name: %(name)s\n"
"current-context: %(name)s\n"
"kind: Config\n"
"preferences: {}\n"
"users:\n"
"- name: %(name)s\n"
" user:\n"
" client-certificate: %(cfg_dir)s/cert.pem\n"
" client-key: %(cfg_dir)s/key.pem\n"
% {'name': cluster.name,
'api_address': cluster.api_address,
'cfg_dir': cfg_dir})
if os.path.exists(cfg_file) and not force:
raise exc.CommandError("File %s exists, aborting." % cfg_file)
else:
f = open(cfg_file, "w")
f.write(cfg)
f.close()
if 'csh' in os.environ['SHELL']:
return "setenv KUBECONFIG %s\n" % cfg_file
else:
return "export KUBECONFIG=%s\n" % cfg_file
def _config_cluster_swarm(cluster, cluster_template, cfg_dir, force=False):
"""Return and write configuration for the given swarm cluster."""
tls = "" if cluster_template.tls_disabled else True
if 'csh' in os.environ['SHELL']:
result = ("setenv DOCKER_HOST %(docker_host)s\n"
"setenv DOCKER_CERT_PATH %(cfg_dir)s\n"
"setenv DOCKER_TLS_VERIFY %(tls)s\n"
% {'docker_host': cluster.api_address,
'cfg_dir': cfg_dir,
'tls': tls}
)
else:
result = ("export DOCKER_HOST=%(docker_host)s\n"
"export DOCKER_CERT_PATH=%(cfg_dir)s\n"
"export DOCKER_TLS_VERIFY=%(tls)s\n"
% {'docker_host': cluster.api_address,
'cfg_dir': cfg_dir,
'tls': tls}
)
return result
def generate_csr_and_key():
"""Return a dict with a new csr and key."""
key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend())
csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, u"Magnum User"),
])).sign(key, hashes.SHA256(), default_backend())
result = {
'csr': csr.public_bytes(
encoding=serialization.Encoding.PEM).decode("utf-8"),
'key': key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()).decode("utf-8"),
}
return result

View File

@ -12,7 +12,10 @@
# License for the specific language governing permissions and limitations
# under the License.
import os
from magnumclient.common import utils as magnum_utils
from magnumclient import exceptions
from magnumclient.i18n import _
from osc_lib.command import command
@ -242,3 +245,68 @@ class UpdateCluster(command.Command):
patch)
print("Request to update cluster %s has been accepted." %
parsed_args.cluster)
class ConfigCluster(command.Command):
_description = _("Get Configuration for a Cluster")
def get_parser(self, prog_name):
parser = super(ConfigCluster, self).get_parser(prog_name)
parser.add_argument(
'cluster',
metavar='<cluster>',
help=_('The name or UUID of cluster to update'))
parser.add_argument(
'--dir',
metavar='<dir>',
default='.',
help=_('Directory to save the certificate and config files.'))
parser.add_argument(
'--force',
metavar='<force>',
default=False,
help=_('Directory to save the certificate and config files.'))
return parser
def take_action(self, parsed_args):
"""Configure native client to access cluster.
You can source the output of this command to get the native client of
the corresponding COE configured to access the cluster.
"""
self.log.debug("take_action(%s)", parsed_args)
mag_client = self.app.client_manager.container_infra
parsed_args.dir = os.path.abspath(parsed_args.dir)
cluster = mag_client.clusters.get(parsed_args.cluster)
if cluster.status not in ('CREATE_COMPLETE', 'UPDATE_COMPLETE',
'ROLLBACK_COMPLETE'):
raise exceptions.CommandError("cluster in status %s" %
cluster.status)
cluster_template = mag_client.cluster_templates.get(
cluster.cluster_template_id)
opts = {
'cluster_uuid': cluster.uuid,
}
if not cluster_template.tls_disabled:
tls = magnum_utils.generate_csr_and_key()
tls['ca'] = mag_client.certificates.get(**opts).pem
opts['csr'] = tls['csr']
tls['cert'] = mag_client.certificates.create(**opts).pem
for k in ('key', 'cert', 'ca'):
fname = "%s/%s.pem" % (parsed_args.dir, k)
if os.path.exists(fname) and not parsed_args.force:
raise Exception("File %s exists, aborting." % fname)
else:
f = open(fname, "w")
f.write(tls[k])
f.close()
print(magnum_utils.config_cluster(cluster,
cluster_template,
parsed_args.dir,
force=parsed_args.force))

View File

@ -17,12 +17,6 @@ from magnumclient.common import utils as magnum_utils
from magnumclient import exceptions
from magnumclient.i18n import _
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography import x509
from cryptography.x509.oid import NameOID
import os
@ -242,7 +236,7 @@ def do_bay_config(cs, args):
}
if not baymodel.tls_disabled:
tls = _generate_csr_and_key()
tls = magnum_utils.generate_csr_and_key()
tls['ca'] = cs.certificates.get(**opts).pem
opts['csr'] = tls['csr']
tls['cert'] = cs.certificates.create(**opts).pem
@ -255,112 +249,5 @@ def do_bay_config(cs, args):
f.write(tls[k])
f.close()
print(_config_bay(bay, baymodel, cfg_dir=args.dir, force=args.force))
def _config_bay(bay, baymodel, cfg_dir, force=False):
"""Return and write configuration for the given bay."""
if baymodel.coe == 'kubernetes':
return _config_bay_kubernetes(bay, baymodel, cfg_dir, force)
elif baymodel.coe == 'swarm':
return _config_bay_swarm(bay, baymodel, cfg_dir, force)
def _config_bay_kubernetes(bay, baymodel, cfg_dir, force=False):
"""Return and write configuration for the given kubernetes bay."""
cfg_file = "%s/config" % cfg_dir
if baymodel.tls_disabled:
cfg = ("apiVersion: v1\n"
"clusters:\n"
"- cluster:\n"
" server: %(api_address)s\n"
" name: %(name)s\n"
"contexts:\n"
"- context:\n"
" cluster: %(name)s\n"
" user: %(name)s\n"
" name: default/%(name)s\n"
"current-context: default/%(name)s\n"
"kind: Config\n"
"preferences: {}\n"
"users:\n"
"- name: %(name)s'\n"
% {'name': bay.name, 'api_address': bay.api_address})
else:
cfg = ("apiVersion: v1\n"
"clusters:\n"
"- cluster:\n"
" certificate-authority: ca.pem\n"
" server: %(api_address)s\n"
" name: %(name)s\n"
"contexts:\n"
"- context:\n"
" cluster: %(name)s\n"
" user: %(name)s\n"
" name: default/%(name)s\n"
"current-context: default/%(name)s\n"
"kind: Config\n"
"preferences: {}\n"
"users:\n"
"- name: %(name)s\n"
" user:\n"
" client-certificate: cert.pem\n"
" client-key: key.pem\n"
% {'name': bay.name, 'api_address': bay.api_address})
if os.path.exists(cfg_file) and not force:
raise exceptions.CommandError("File %s exists, aborting." % cfg_file)
else:
f = open(cfg_file, "w")
f.write(cfg)
f.close()
if 'csh' in os.environ['SHELL']:
return "setenv KUBECONFIG %s\n" % cfg_file
else:
return "export KUBECONFIG=%s\n" % cfg_file
def _config_bay_swarm(bay, baymodel, cfg_dir, force=False):
"""Return and write configuration for the given swarm bay."""
tls = "" if baymodel.tls_disabled else True
if 'csh' in os.environ['SHELL']:
result = ("setenv DOCKER_HOST %(docker_host)s\n"
"setenv DOCKER_CERT_PATH %(cfg_dir)s\n"
"setenv DOCKER_TLS_VERIFY %(tls)s\n"
% {'docker_host': bay.api_address,
'cfg_dir': cfg_dir,
'tls': tls}
)
else:
result = ("export DOCKER_HOST=%(docker_host)s\n"
"export DOCKER_CERT_PATH=%(cfg_dir)s\n"
"export DOCKER_TLS_VERIFY=%(tls)s\n"
% {'docker_host': bay.api_address,
'cfg_dir': cfg_dir,
'tls': tls}
)
return result
def _generate_csr_and_key():
"""Return a dict with a new csr and key."""
key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend())
csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, u"Magnum User"),
])).sign(key, hashes.SHA256(), default_backend())
result = {
'csr': csr.public_bytes(
encoding=serialization.Encoding.PEM).decode("utf-8"),
'key': key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()).decode("utf-8"),
}
return result
print(magnum_utils.config_cluster(bay, baymodel, cfg_dir=args.dir,
force=args.force))

View File

@ -19,13 +19,6 @@ from magnumclient.common import utils as magnum_utils
from magnumclient import exceptions
from magnumclient.i18n import _
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography import x509
from cryptography.x509.oid import NameOID
# Maps old parameter names to their new names and whether they are required
# e.g. keypair-id to keypair
@ -265,7 +258,7 @@ def do_cluster_config(cs, args):
}
if not cluster_template.tls_disabled:
tls = _generate_csr_and_key()
tls = magnum_utils.generate_csr_and_key()
tls['ca'] = cs.certificates.get(**opts).pem
opts['csr'] = tls['csr']
tls['cert'] = cs.certificates.create(**opts).pem
@ -278,115 +271,5 @@ def do_cluster_config(cs, args):
f.write(tls[k])
f.close()
print(_config_cluster(cluster, cluster_template,
cfg_dir=args.dir, force=args.force))
def _config_cluster(cluster, cluster_template, cfg_dir, force=False):
"""Return and write configuration for the given cluster."""
if cluster_template.coe == 'kubernetes':
return _config_cluster_kubernetes(cluster, cluster_template,
cfg_dir, force)
elif cluster_template.coe == 'swarm':
return _config_cluster_swarm(cluster, cluster_template, cfg_dir, force)
def _config_cluster_kubernetes(cluster, cluster_template,
cfg_dir, force=False):
"""Return and write configuration for the given kubernetes cluster."""
cfg_file = "%s/config" % cfg_dir
if cluster_template.tls_disabled:
cfg = ("apiVersion: v1\n"
"clusters:\n"
"- cluster:\n"
" server: %(api_address)s\n"
" name: %(name)s\n"
"contexts:\n"
"- context:\n"
" cluster: %(name)s\n"
" user: %(name)s\n"
" name: %(name)s\n"
"current-context: %(name)s\n"
"kind: Config\n"
"preferences: {}\n"
"users:\n"
"- name: %(name)s'\n"
% {'name': cluster.name, 'api_address': cluster.api_address})
else:
cfg = ("apiVersion: v1\n"
"clusters:\n"
"- cluster:\n"
" certificate-authority: ca.pem\n"
" server: %(api_address)s\n"
" name: %(name)s\n"
"contexts:\n"
"- context:\n"
" cluster: %(name)s\n"
" user: %(name)s\n"
" name: default/%(name)s\n"
"current-context: default/%(name)s\n"
"kind: Config\n"
"preferences: {}\n"
"users:\n"
"- name: %(name)s\n"
" user:\n"
" client-certificate: cert.pem\n"
" client-key: key.pem\n"
% {'name': cluster.name, 'api_address': cluster.api_address})
if os.path.exists(cfg_file) and not force:
raise exceptions.CommandError("File %s exists, aborting." % cfg_file)
else:
f = open(cfg_file, "w")
f.write(cfg)
f.close()
if 'csh' in os.environ['SHELL']:
return "setenv KUBECONFIG %s\n" % cfg_file
else:
return "export KUBECONFIG=%s\n" % cfg_file
def _config_cluster_swarm(cluster, cluster_template, cfg_dir, force=False):
"""Return and write configuration for the given swarm cluster."""
tls = "" if cluster_template.tls_disabled else True
if 'csh' in os.environ['SHELL']:
result = ("setenv DOCKER_HOST %(docker_host)s\n"
"setenv DOCKER_CERT_PATH %(cfg_dir)s\n"
"setenv DOCKER_TLS_VERIFY %(tls)s\n"
% {'docker_host': cluster.api_address,
'cfg_dir': cfg_dir,
'tls': tls}
)
else:
result = ("export DOCKER_HOST=%(docker_host)s\n"
"export DOCKER_CERT_PATH=%(cfg_dir)s\n"
"export DOCKER_TLS_VERIFY=%(tls)s\n"
% {'docker_host': cluster.api_address,
'cfg_dir': cfg_dir,
'tls': tls}
)
return result
def _generate_csr_and_key():
"""Return a dict with a new csr and key."""
key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend())
csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, u"Magnum User"),
])).sign(key, hashes.SHA256(), default_backend())
result = {
'csr': csr.public_bytes(
encoding=serialization.Encoding.PEM).decode("utf-8"),
'key': key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()).decode("utf-8"),
}
return result
print(magnum_utils.config_cluster(cluster, cluster_template,
cfg_dir=args.dir, force=args.force))

View File

@ -41,6 +41,7 @@ openstack.container_infra.v1 =
coe_cluster_delete = magnumclient.osc.v1.clusters:DeleteCluster
coe_cluster_show = magnumclient.osc.v1.clusters:ShowCluster
coe_cluster_update = magnumclient.osc.v1.clusters:UpdateCluster
coe_cluster_config = magnumclient.osc.v1.clusters:ConfigCluster
[build_sphinx]
source-dir = doc/source