De Cero a Héroe con la API de IaaS OpenStack de K5 (Python 2.7X)
2017-01-27
Machine-translated from English. Read the English original
Hoy repasaré todos los pasos necesarios para desplegar un servidor en la plataforma IaaS de Fujitsu K5 utilizando únicamente llamadas a la API basadas en OpenStack. He elegido Python 2.7X con fines de demostración, ya que es en lo que se basa principalmente OpenStack. Sin embargo, debería ser bastante fácil portar las llamadas a la API a otro lenguaje de scripting, ya que no estoy utilizando ninguna biblioteca intermedia; todas mis solicitudes http hablan directamente con los puntos de conexión de K5.
Requisitos previos para este tutorial:
- Una cuenta K5 válida con acceso a un proyecto o una cuenta OpenStack válida que utilice Keystone V3 con Dominios y acceso a un proyecto.
- La cuenta debe ser un administrador del proyecto, es decir, necesitas tener los roles para crear y eliminar recursos dentro del proyecto.
- Un sistema Windows o Linux con python 2.7X instalado junto con el módulo Requests.
Pasos necesarios para construir un servidor utilizando la API de OpenStack
Una vez que hayas satisfecho los requisitos previos anteriores, repasemos rápidamente lo que se necesita para construir un servidor en un proyecto dentro de OpenStack.

Para el resto de este tutorial, pasaré revista a cada llamada a la API detallando qué se envía y qué se devuelve.

Paso 1 – Obtener un token K5 válido vinculado al proyecto donde deseas desplegar el servidor. Aquí es donde necesitarás tus credenciales de inicio de sesión de K5/OpenStack. Estas se proporcionarán con la solicitud inicial de un token vinculado al proyecto de la siguiente manera:
def get_scoped_token(adminUser, adminPassword, contract, projectid, region):
identityURL = 'https://identity.' + region + \
'.cloud.global.fujitsu.com/v3/auth/tokens'
try:
response = requests.post(identityURL,
headers={'Content-Type': 'application/json',
'Accept': 'application/json'},
json={"auth":
{"identity":
{"methods": ["password"], "password":
{"user":
{"domain":
{"name": contract},
"name": adminUser,
"password": adminPassword
}}},
"scope":
{"project":
{"id": projectid
}}}})
return response
except:
return 'Regional Project Token Scoping Failure'
def main():
k5token = get_scoped_token(adminUser, adminPassword, contract, demoProjectAid, region).json()
# print the output for demonstartion purposes
pprint.pprint(k5token)
Si se han proporcionado credenciales válidas, obtendrás un objeto de respuesta JSON que contiene los puntos de conexión de K5 registrados en su catálogo de keystone de OpenStack de la siguiente manera:
{u'token': {u'catalog': [{u'endpoints': [{u'id': u'b506af0e016a4b5fb592f196da569a41',
u'interface': u'public',
u'name': u'objectstorage',
u'region': u'uk-1',
u'url': u'https://objectstorage.uk-1.cloud.global.fujitsu.com/v1/AUTH_7015d1478a4c4bd7b970215d7b0260dd'}],
u'id': u'024329e4fde148e58ecd90b7d9872438',
u'type': u'object-store'},
{u'endpoints': [{u'id': u'0419c448001845af8f6828cf49745e72',
u'interface': u'public',
u'name': u'keymanagement',
u'region': u'uk-1',
u'url': u'https://keymanagement.uk-1.cloud.global.fujitsu.com/v1'}],
u'id': u'07f309b0ef9d42758ea4de47bdca9c32',
u'type': u'keystore'},
{u'endpoints': [{u'id': u'e1cc93936fb94cdbadc20f17c4ad3140',
u'interface': u'public',
u'name': u'certificate',
u'region': u'uk-1',
u'url': u'https://certificate.uk-1.cloud.global.fujitsu.com/v1'}],
u'id': u'0bd9a971e97d4c15af6b94311e4e9c15',
u'type': u'certificate'},
{u'endpoints': [{u'id': u'c3ee708a6ae24ddf92c078526c36a446',
u'interface': u'public',
u'name': u'orchestration',
u'region': u'uk-1',
u'url': u'https://orchestration.uk-1.cloud.global.fujitsu.com/v1/7015d1478a4c4bd7b970215d7b0260dd'}],
u'id': u'0dafa2a9240c41268c37818979769c88',
u'type': u'orchestration'},
{u'endpoints': [{u'id': u'ba9061d324954b1a9f6b1c1f5d4a5c5e',
u'interface': u'public',
u'name': u'blockstorage',
u'region': u'uk-1',
u'url': u'https://blockstorage.uk-1.cloud.global.fujitsu.com/v1/7015d1478a4c4bd7b970215d7b0260dd'}],
u'id': u'0ec640e57e4d4374841d2ab7b292f2c2',
u'type': u'volume'},
{u'endpoints': [{u'id': u'169bcb3f92384f709232864f4d5304eb',
u'interface': u'public',
u'name': u'loadbalancing',
u'region': u'uk-1',
u'url': u'https://loadbalancing.uk-1.cloud.global.fujitsu.com'}],
u'id': u'15ef761fa00a438985213aec7b6fb18a',
u'type': u'loadbalancing'},
{u'endpoints': [],
u'id': u'1a53a2e82370422d90174c4acf585ea9',
u'type': u'dwh'},
{u'endpoints': [],
u'id': u'1b35fa74ae0e46ebbc2014f976fec0e1',
u'type': u'contract'},
{u'endpoints': [],
u'id': u'253096ed430c49c48c9f3549e867b538',
u'type': u'appplatform'},
{u'endpoints': [{u'id': u'e26ad89a682d4c8f8a71c9e76cd785b4',
u'interface': u'public',
u'name': u'compute-w',
u'region': u'uk-1',
u'url': u'https://compute-w.uk-1.cloud.global.fujitsu.com'}],
u'id': u'327c11710f184555b43bc6fdfc47626b',
u'type': u'compute-w'},
{u'endpoints': [],
u'id': u'3435ad7a1da04b1cb2e249665529eb51',
u'type': u'notification'},
{u'endpoints': [{u'id': u'f70e51b9a6a74a87a4c7055b8df8bedf',
u'interface': u'public',
u'name': u'compute',
u'region': u'uk-1',
u'url': u'https://compute.uk-1.cloud.global.fujitsu.com/v2/7015d1478a4c4bd7b970215d7b0260dd'}],
u'id': u'3e19093f50cc4590973c8953e2c327f9',
u'type': u'compute'},
{u'endpoints': [{u'id': u'c46b5ec51ab04402a9ffd8177743ba6f',
u'interface': u'public',
u'name': u'queue',
u'region': u'uk-1',
u'url': u'https://queue.uk-1.cloud.global.fujitsu.com'}],
u'id': u'4a9ab69b74ec4948a0a6958177d30387',
u'type': u'queue'},
{u'endpoints': [{u'id': u'071ee50be4b341558e37f84abac47d02',
u'interface': u'public',
u'name': u'autoscale',
u'region': u'uk-1',
u'url': u'https://autoscale.uk-1.cloud.global.fujitsu.com/autoscale_schedulers'}],
u'id': u'4f158b2836434c7ca6ee47e40a3ee56c',
u'type': u'autoscale'},
{u'endpoints': [{u'id': u'6ac15657fbc548d7ab2ed986b8d94192',
u'interface': u'public',
u'name': u'telemetry',
u'region': u'uk-1',
u'url': u'https://telemetry.uk-1.cloud.global.fujitsu.com'}],
u'id': u'54ee7596f0e1433cb8db6201be2cf772',
u'type': u'metering'},
{u'endpoints': [],
u'id': u'5954129d136e4a76b7cd6f3d1f3808b5',
u'type': u'cdn'},
{u'endpoints': [],
u'id': u'5a252878ffd7402498b6b74b575a899a',
u'type': u'oss'},
{u'endpoints': [{u'id': u'2d600a5de6ec42c6a5eab7b519832d87',
u'interface': u'public',
u'name': u'rolemanagement',
u'region': u'uk-1',
u'url': u'https://rolemanagement.uk-1.cloud.global.fujitsu.com/v1'}],
u'id': u'5bc90099f0ad490c811239a6a3a8f853',
u'type': u'rolemanagement'},
{u'endpoints': [{u'id': u'768450282d5546409395d2cb35502dad',
u'interface': u'public',
u'name': u'compute-b',
u'region': u'uk-1',
u'url': u'https://compute-b.uk-1.cloud.global.fujitsu.com'}],
u'id': u'65f754202b6049578e9a292a801e28f7',
u'type': u'compute-b'},
{u'endpoints': [{u'id': u'675910513a7e466c84c39c5ca9445b81',
u'interface': u'public',
u'name': u'networking',
u'region': u'uk-1',
u'url': u'https://networking.uk-1.cloud.global.fujitsu.com'}],
u'id': u'6cf37e33dc7140b9b032faabfa53a53e',
u'type': u'network'},
{u'endpoints': [],
u'id': u'7426c97af5174c1abdb8b84ba02227ce',
u'type': u'dns'},
{u'endpoints': [{u'id': u'6976cbeed14c464da15c13e949b41607',
u'interface': u'public',
u'name': u'database',
u'region': u'uk-1',
u'url': u'https://database.uk-1.cloud.global.fujitsu.com/v1.0/7015d1478a4c4bd7b970215d7b0260dd'}],
u'id': u'75c0280f15844d7a9eb22b1ad5a978e8',
u'type': u'database'},
{u'endpoints': [{u'id': u'db15a7126d4a4f1f81903bb4d56be32b',
u'interface': u'admin',
u'name': u'identity',
u'region': u'uk-1',
u'url': u'https://identity.uk-1.cloud.global.fujitsu.com/v2.0'}],
u'id': u'79066fe949064550930a61b33a49eb53',
u'type': u'identity'},
{u'endpoints': [],
u'id': u'804190a423804019aab8fd934db0086e',
u'type': u'intdns'},
{u'endpoints': [],
u'id': u'8d364df08cbc4d7188f0cf83744b0336',
u'type': u'invoicing'},
{u'endpoints': [],
u'id': u'9674ae5917af401397071c028ff33b68',
u'type': u'catalog'},
{u'endpoints': [{u'id': u'fd6g35fgknrzumut7bx6p6bwzehkfhrz',
u'interface': u'public',
u'name': u'software',
u'region': u'uk-1',
u'url': u'https://software.uk-1.cloud.global.fujitsu.com/v1.0'}],
u'id': u'9760973e49b04b00b41e60c180a80562',
u'type': u'software'},
{u'endpoints': [{u'id': u'8c4ace3bbbd44883b5762a9ad8432a46',
u'interface': u'public',
u'name': u'blockstoragev2',
u'region': u'uk-1',
u'url': u'https://blockstorage.uk-1.cloud.global.fujitsu.com/v2/7015d1478a4c4bd7b970215d7b0260dd'}],
u'id': u'9bf82d0466714eee86e304ab3301aec9',
u'type': u'volumev2'},
{u'endpoints': [],
u'id': u'a2b90094346c48deabb9ca645bacf588',
u'type': u'dnsadmin'},
{u'endpoints': [{u'id': u'225257ec50ef47668185587cc6edb95d',
u'interface': u'public',
u'name': u'vmimport',
u'region': u'uk-1',
u'url': u'https://vmimport.uk-1.cloud.global.fujitsu.com'}],
u'id': u'c73fa07c3b604b4f89d5a2b9c4621cf2',
u'type': u'vmimport'},
{u'endpoints': [{u'id': u'27dc2bba1c5d4a14b68657fc8fdd4e3e',
u'interface': u'public',
u'name': u'identityv3',
u'region': u'uk-1',
u'url': u'https://identity.uk-1.cloud.global.fujitsu.com/v3'}],
u'id': u'cc6f50d496884ef0a751acb2e1eceedd',
u'type': u'identityv3'},
{u'endpoints': [{u'id': u'06fbcf8235434f23a08faed03b4af9ac',
u'interface': u'public',
u'name': u'appmanagement',
u'region': u'uk-1',
u'url': u'https://applicationmanagement.uk-1.cloud.global.fujitsu.com'}],
u'id': u'ce2f6bbe7a9f446b82d63725bd7bb484',
u'type': u'appmanagement'},
{u'endpoints': [],
u'id': u'd07aa581c0734b6bb85cd496115b5110',
u'type': u'nosql'},
{u'endpoints': [],
u'id': u'd2f57dcae4c84466ac357220ff3d8900',
u'type': u'baremetal'},
{u'endpoints': [],
u'id': u'd4601f51af8f43f3b0e3409e4cbac690',
u'type': u'mail'},
{u'endpoints': [{u'id': u'bf356065e45349a5bde5e043c95a1923',
u'interface': u'public',
u'name': u'networking-ex',
u'region': u'uk-1',
u'url': u'https://networking-ex.uk-1.cloud.global.fujitsu.com'}],
u'id': u'd4937aa1275c41378bf2ae1dbe829c68',
u'type': u'networking-ex'},
{u'endpoints': [{u'id': u'dc2ebf9d6fc04f1facc263a733cf754d',
u'interface': u'public',
u'name': u'global-identity',
u'region': u'jp-east-1',
u'url': u'https://identity.gls.cloud.global.fujitsu.com/v3'}],
u'id': u'e74b9c29d6504f10a8fb8e1495f3f5c6',
u'type': u'global-identity'},
{u'endpoints': [{u'id': u'a832d640886b4ef89027339a2edf8fcd',
u'interface': u'public',
u'name': u'image',
u'region': u'uk-1',
u'url': u'https://image.uk-1.cloud.global.fujitsu.com'}],
u'id': u'ea850dab0e964e12a9f66787ee8623ae',
u'type': u'image'},
{u'endpoints': [],
u'id': u'f1302a2477bf492bb3e867952175974a',
u'type': u'billing'},
{u'endpoints': [{u'id': u'e8bde8fe61a14a88b414e5568fc17201',
u'interface': u'public',
u'name': u'import-export',
u'region': u'uk-1',
u'url': u'https://import-export.uk-1.cloud.global.fujitsu.com'}],
u'id': u'fc302725919645199373077fa299fc6e',
u'type': u'import-export'}],
u'expires_at': u'2017-01-27T13:53:55.982381Z',
u'extras': {},
u'issued_at': u'2017-01-27T10:53:55.982425Z',
u'methods': [u'password'],
u'project': {u'domain': {u'id': u'3256d41b17014d5c99727993d6fca821',
u'name': u'YssmW1yI'},
u'id': u'7015d1478a4c4bd7b970215d7b0260dd',
u'name': u'Project_A'},
u'roles': [{u'id': u'0739580a550d4a0f9c78f45a9f038c05',
u'name': u'cpf_systemowner'},
{u'id': u'3af119c426a742999e7890f6d1f70b36',
u'name': u'cpf_admin'}],
u'user': {u'domain': {u'id': u'3256d41b17014d5c99727993d6fca821',
u'name': u'YssmW1yI'},
u'id': u'03758af9df694db784c3547ab8217abb',
u'name': u'landg'}}}
Esta información es muy importante, ya que cuando desees automatizar completamente K5, así es como detectas tus varios puntos de conexión para los servicios que necesitas consumir.
Nota: Los puntos de conexión que tienen un sufijo '-ex' en sus nombres son los puntos de conexión mejorados de OpenStack. Estos puntos de conexión incluyen las características adicionales que Fujitsu ha añadido a K5 por encima y más allá de las características estándar de OpenStack.
Entonces, ¿qué falta en esta imagen...? ¿Dónde está el token??? No temas, en realidad se almacena en la cabecera de la respuesta en una variable llamada 'X-Subject-Token'. Por ejemplo –
# print the K5 poject scoped token
print "\n\n K5 Project Scoped Token :", k5token.headers['X-Subject-Token'], "\n"
...revela un token, que por cierto es válido durante 2 horas, de la siguiente manera..
K5 Project Scoped Token : f5b72cd06517447fae59360f6deba7d8
Este token debe pasarse con todas las llamadas posteriores a la API de K5 en la cabecera para proporcionar tus credenciales de autenticación y autorización a cada solicitud de servicio.
El punto de conexión de la API de OpenStack neutron estándar se puede extraer de la respuesta anterior buscando el punto de conexión llamado 'networking'. He utilizado la siguiente función para devolver la URL del punto de conexión que estoy buscando –
def get_endpoint(k5token, endpoint_type):
# list the endpoints
for ep in k5token.json()['token']['catalog']:
if len(ep['endpoints'])>0:
# if this is the endpoint that I'm looking for return the url
if endpoint_type == ep['endpoints'][0].get('name'):
#pprint.pprint(ep)
return ep['endpoints'][0].get('url')
Por ejemplo –
# list the networking endpoints
print get_endpoint(k5token,"networking")
Devolverá el punto de conexión de la API de neutron que necesito –
K5 Networking EndPoints :
https://networking.uk-1.cloud.global.fujitsu.com
Ahora que tenemos los detalles necesarios del token y del punto de conexión, pasemos a la siguiente etapa.

Paso 2 – Crear la red de capa 2. La siguiente llamada de neutron crea una subred de capa 2 de K5 con las propiedades que pasas a través de la API de la siguiente manera:
def create_network(k5token, name, availability_zone):
networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/networks')
print networkURL
token = k5token.headers['X-Subject-Token']
try:
response = requests.post(networkURL,
headers={'X-Auth-Token': token,
'Content-Type': 'application/json'},
json={
"network":
{
"name": name,
"admin_state_up": True,
"availability_zone": availability_zone
}
})
return response
except:
return ("\nUnexpected error:", sys.exc_info())
Por ejemplo –
# Create a layer 2 virtual network
network = create_network(k5token, "demonet", "uk-1b")
print network
print network.json()
produce –
https://networking.uk-1.cloud.global.fujitsu.com/v2.0/networks
{u'network': {u'status': u'ACTIVE', u'subnets': [], u'name': u'demonet', u'admin_state_up': True, u'tenant_id': u'7015d1478a4c4bd7b970215d7b0260dd', u'availability_zone': u'uk-1b', u'shared': False, u'id': u'02fd7be4-b5f1-455c-8aea-37b299e85ddd'}}
Necesitamos capturar el id de la red recién creada, ya que lo utilizaremos en la siguiente llamada a la API –
network_id = network.json()['network'].get('id')
Ahora creemos nuestra subred.

Paso 3 – Crear la subred de capa 3. Una vez más, estamos utilizando la llamada a la API de neutron estándar aquí y pasando el id de la red recién creada a la llamada. La función utilizada se ve así –
def create_subnet(k5token, name, netid, cidr, az):
networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/subnets')
print networkURL
token = k5token.headers['X-Subject-Token']
try:
response = requests.post(networkURL,
headers={'X-Auth-Token': token,
'Content-Type': 'application/json'},
json={
"subnet": {
"name": name,
"network_id": netid,
"ip_version": 4,
"cidr": cidr,
"availability_zone": az
}
})
return response
except:
return ("\nUnexpected error:", sys.exc_info())
Y cuando se invoca de la siguiente manera –
subnet = create_subnet(k5token, "demosubnet", network_id, "192.168.10.0/24", "uk-1b")
print subnet
print subnet.json()
subnet_id = subnet.json()['subnet'].get('id')
print subnet_id
produce la siguiente respuesta –
https://networking.uk-1.cloud.global.fujitsu.com/v2.0/subnets
{u'subnet': {u'name': u'demosubnet', u'enable_dhcp': True, u'availability_zone': u'uk-1b', u'network_id': u'1af9e3fe-4546-4b59-a5a5-10e48af5302a', u'tenant_id': u'7015d1478a4c4bd7b970215d7b0260dd', u'dns_nameservers': [], u'allocation_pools': [{u'start': u'192.168.10.2', u'end': u'192.168.10.254'}], u'host_routes': [], u'ip_version': 4, u'gateway_ip': u'192.168.10.1', u'cidr': u'192.168.10.0/24', u'id': u'2322908f-cf58-4124-a273-86a33cc429b5'}}
2322908f-cf58-4124-a273-86a33cc429b5
Observa que ahora también hemos capturado el id de la nueva subred. Esperemos que el patrón se vuelva obvio ahora a medida que avanzamos al siguiente paso.

Paso 4 – Crear un enrutador virtual. Una vez más, estamos trabajando con el punto de conexión de neutrons de OpenStack esta vez construyendo un enrutador virtual. Se ha utilizado la siguiente función –
def create_router(k5token, name, availability_zone):
networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/routers')
print networkURL
token = k5token.headers['X-Subject-Token']
try:
response = requests.post(networkURL,
headers={'X-Auth-Token': token,
'Content-Type': 'application/json'},
json={
"router": {
"name": name,
"admin_state_up": True,
"availability_zone": availability_zone
}})
return response
except:
return ("\nUnexpected error:", sys.exc_info())
que, cuando se invoca así –
# Create a layer 3 virtual router
router = create_router(k5token, "demorouter", "uk-1b")
print router
print router.json()
router_id = router.json()['router'].get('id')
print router_id
devuelve –
https://networking.uk-1.cloud.global.fujitsu.com/v2.0/routers
{u'router': {u'status': u'ACTIVE', u'external_gateway_info': None, u'name': u'demorouter', u'admin_state_up': True, u'tenant_id': u'7015d1478a4c4bd7b970215d7b0260dd', u'availability_zone': u'uk-1b', u'id': u'0a0661a9-7e30-4f8e-904a-c4a9469d3fca'}}
0a0661a9-7e30-4f8e-904a-c4a9469d3fca
Una vez más, capturamos el identificador del recurso recién creado – router_id.

Paso 5 – Ahora configuremos el enrutador. Primero establecemos la puerta de enlace externa utilizando la siguiente llamada a la función –
def update_router_gateway(k5token, router_id, network_id):
networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/routers/') + router_id
print networkURL
token = k5token.headers['X-Subject-Token']
try:
response = requests.put(networkURL,
headers={'X-Auth-Token': token,
'Content-Type': 'application/json'},
json={
"router": {
"external_gateway_info": {
"network_id": network_id
}
}})
return response
except:
return ("\nUnexpected error:", sys.exc_info())
llamada desde el cuerpo del script de la siguiente manera –
# Add external gateway to router (extaz2 is the external network id for the external network in availability zone b)
router_gateway = update_router_gateway(k5token, router_id, extaz2)
print router_gateway
print router_gateway.json()
produciendo los siguientes resultados –
https://networking.uk-1.cloud.global.fujitsu.com/v2.0/routers/245a02e7-8b0e-4d1f-af6a-dfc07ed916e0
{u'router': {u'status': u'ACTIVE', u'external_gateway_info': {u'network_id': u'd730db50-0e0c-4790-9972-1f6e2b8c4915', u'enable_snat': True}, u'name': u'demorouter', u'admin_state_up': True, u'tenant_id': u'7015d1478a4c4bd7b970215d7b0260dd', u'availability_zone': u'uk-1b', u'routes': [], u'id': u'245a02e7-8b0e-4d1f-af6a-dfc07ed916e0'}}

Paso 6 – Ahora 'conectaremos' nuestra red virtual a nuestro enrutador virtual con esta llamada a la función –
def add_interface_to_router(k5token, router_id, subnet_id):
networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/routers/') + router_id + '/add_router_interface'
print networkURL
token = k5token.headers['X-Subject-Token']
try:
response = requests.put(networkURL,
headers={'X-Auth-Token': token,
'Content-Type': 'application/json'},
json={
"subnet_id": subnet_id})
return response
except:
return ("\nUnexpected error:", sys.exc_info())
que se invoca de esta manera –
# Plug new network subnet into the router
router_interface = add_interface_to_router(k5token, router_id, subnet_id)
print router_interface
print router_interface.json()
con la siguiente salida –
https://networking.uk-1.cloud.global.fujitsu.com/v2.0/routers/43e95138-9124-4e04-a5d4-ae5b90f4fded/add_router_interface
{u'subnet_id': u'16b59543-c303-4e33-9b96-b538625f40b2', u'tenant_id': u'7015d1478a4c4bd7b970215d7b0260dd', u'port_id': u'1ba71079-288e-49b7-925d-fb31658bc9c6', u'id': u'43e95138-9124-4e04-a5d4-ae5b90f4fded', u'availability_zone': u'uk-1b'}
Esto completa los conceptos básicos de la infraestructura de red.

Paso 7 – El servidor necesitará un grupo de seguridad asignado a sus interfaces de red, así que crearemos esto ahora junto con las reglas que permitirán los protocolos ssh, tcp y rdp solo entrantes.
Se utilizó esta llamada a la API para crear el grupo de seguridad –
def create_security_group(k5token, name, description):
networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/security-groups')
print networkURL
token = k5token.headers['X-Subject-Token']
try:
response = requests.post(networkURL,
headers={'X-Auth-Token': token, 'Content-Type': 'application/json', 'Accept': 'application/json'},
json={
"security_group": {
"name": name,
"description": description
}
})
return response
except:
return ("\nUnexpected error:", sys.exc_info())
que se invoca de la siguiente manera –
# Create a new security group
security_group = create_security_group(k5token, "demosecuritygroup", "Demo Security Group Allows RDP, SSH and ICMP")
print security_group
print security_group.json()
security_group_id = security_group.json()['security_group'].get('id')
print security_group_id
resultando en esta salida –
https://networking.uk-1.cloud.global.fujitsu.com/v2.0/security-groups
{u'security_group': {u'id': u'ae44389e-f884-4726-8bc3-ec3cbc7b876e', u'tenant_id': u'7015d1478a4c4bd7b970215d7b0260dd', u'description': u'Demo Security Group Allows RDP, SSH and ICMP', u'security_group_rules': [{u'remote_group_id': None, u'direction': u'egress', u'protocol': None, u'ethertype': u'IPv6', u'port_range_max': None, u'security_group_id': u'ae44389e-f884-4726-8bc3-ec3cbc7b876e', u'tenant_id': u'7015d1478a4c4bd7b970215d7b0260dd', u'port_range_min': None, u'remote_ip_prefix': None, u'id': u'55d5c3f1-3cf0-46c0-b876-6e89a1a1fc55'}, {u'remote_group_id': None, u'direction': u'egress', u'protocol': None, u'ethertype': u'IPv4', u'port_range_max': None, u'security_group_id': u'ae44389e-f884-4726-8bc3-ec3cbc7b876e', u'tenant_id': u'7015d1478a4c4bd7b970215d7b0260dd', u'port_range_min': None, u'remote_ip_prefix': None, u'id': u'c83371a8-f217-4038-982a-0165df8e9f4f'}], u'name': u'demosecuritygroup'}}
ae44389e-f884-4726-8bc3-ec3cbc7b876e

Paso 8 – Crear nuestras reglas de grupo de seguridad con la siguiente llamada a la API –
def create_security_group_rule(k5token, security_group_id, direction, portmin, portmax, protocol):
networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/security-group-rules')
print networkURL
token = k5token.headers['X-Subject-Token']
try:
response = requests.post(networkURL,
headers={'X-Auth-Token': token, 'Content-Type': 'application/json', 'Accept': 'application/json'},
json={
"security_group_rule": {
"direction": direction,
"port_range_min": portmin,
"ethertype": "IPv4",
"port_range_max": portmax,
"protocol": protocol,
"security_group_id": security_group_id
}
})
return response
except:
return ("\nUnexpected error:", sys.exc_info())
de nuevo (sé que es repetitivo) la llamada se invoca de la siguiente manera –
# Create security group rules
# allow rdp
rdp_rule = create_security_group_rule(k5token, security_group_id, "ingress", "3389", "3389", "tcp")
print rdp_rule
print rdp_rule.json()
# allow ssh # allow rdp
ssh_rule = create_security_group_rule(k5token, security_group_id, "ingress", "22", "22", "tcp")
print ssh_rule
print ssh_rule.json()
# allow icmp
icmp_rule = create_security_group_rule(k5token, security_group_id, "ingress", "0", "0", "icmp")
print icmp_rule
print icmp_rule.json()
produciendo –
https://networking.uk-1.cloud.global.fujitsu.com/v2.0/security-group-rules
{u'security_group_rule': {u'remote_group_id': None, u'direction': u'ingress', u'remote_ip_prefix': None, u'protocol': u'tcp', u'ethertype': u'IPv4', u'port_range_max': 3389, u'security_group_id': u'778052d3-d9b8-4eee-9ddc-655f185729ff', u'port_range_min': 3389, u'tenant_id': u'7015d1478a4c4bd7b970215d7b0260dd', u'id': u'7054f52e-b284-4f37-a859-e043dbb6393e'}}
https://networking.uk-1.cloud.global.fujitsu.com/v2.0/security-group-rules
{u'security_group_rule': {u'remote_group_id': None, u'direction': u'ingress', u'remote_ip_prefix': None, u'protocol': u'tcp', u'ethertype': u'IPv4', u'port_range_max': 22, u'security_group_id': u'778052d3-d9b8-4eee-9ddc-655f185729ff', u'port_range_min': 22, u'tenant_id': u'7015d1478a4c4bd7b970215d7b0260dd', u'id': u'f70815f8-ac23-43d9-b808-ebf8e12948a2'}}
https://networking.uk-1.cloud.global.fujitsu.com/v2.0/security-group-rules
{u'security_group_rule': {u'remote_group_id': None, u'direction': u'ingress', u'remote_ip_prefix': None, u'protocol': u'icmp', u'ethertype': u'IPv4', u'port_range_max': 0, u'security_group_id': u'778052d3-d9b8-4eee-9ddc-655f185729ff', u'port_range_min': 0, u'tenant_id': u'7015d1478a4c4bd7b970215d7b0260dd', u'id': u'49bdf8b6-618c-4714-b112-7420d815cd83'}}

Paso 9 – Obtengamos un puerto de nuestra nueva subred que se adjuntará al servidor con una llamada a la API como esta –
def create_port(k5token, name, network_id, security_group_id, availability_zone):
networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/ports')
print networkURL
token = k5token.headers['X-Subject-Token']
try:
response = requests.post(networkURL,
headers={
'X-Auth-Token': token, 'Content-Type': 'application/json', 'Accept': 'application/json'},
json={"port":
{"network_id": network_id,
"name": name,
"admin_state_up": True,
"availability_zone": availability_zone,
"security_groups":
[security_group_id]}})
return response
except:
return ("\nUnexpected error:", sys.exc_info())
invocada de la siguiente manera –
# Create a new port for the server
server_port = create_port(k5token, "demoserverport", network_id, security_group_id, "uk-1b")
print server_port
print server_port.json()
server_port_id = server_port.json()['port'].get('id')
print server_port_id
produciendo la siguiente salida –
https://networking.uk-1.cloud.global.fujitsu.com/v2.0/ports
{u'port': {u'status': u'DOWN', u'name': u'demoserverport', u'allowed_address_pairs': [], u'admin_state_up': True, u'network_id': u'bc491d0d-56c2-4706-b7b4-6e97029dbeaf', u'tenant_id': u'7015d1478a4c4bd7b970215d7b0260dd', u'availability_zone': u'uk-1b', u'binding:vnic_type': u'normal', u'device_owner': u'', u'mac_address': u'fa:16:3e:60:d6:31', u'fixed_ips': [{u'subnet_id': u'bafdfc08-b55b-4a99-b1c9-2f43cf661a54', u'ip_address': u'192.168.10.2'}], u'id': u'f1db8672-2923-46fb-a65b-4f1e643f5a9e', u'security_groups': [u'7e35e0bc-6254-4ce6-9233-fce162db4a8e'], u'device_id': u''}}
f1db8672-2923-46fb-a65b-4f1e643f5a9e

Paso 10 – Ya casi estamos. La última pieza del rompecabezas antes de poder desplegar un servidor es la clave SSH. Esta siguiente función crea una clave SSH para ti; por favor, asegúrate de almacenar la Clave Privada en algún lugar seguro. K5 solo almacena las claves públicas por diseño.
def create_keypair(k5token, keypair_name, availability_zone):
computeURL = unicode(get_endpoint(k5token, "compute")) + unicode('/os-keypairs')
print computeURL
token = k5token.headers['X-Subject-Token']
try:
response = requests.post(computeURL,
headers={
'X-Auth-Token': token,
'Content-Type': 'application/json',
'Accept': 'application/json'},
json={
"keypair": {
"name": keypair_name,
"availability_zone": availability_zone
}})
return response
except:
return ("\nUnexpected error:", sys.exc_info())
invocada de esta manera –
# Create ssh key pair that can be injected into the server
server_key = create_keypair(k5token, "demokeypair", "uk-1b")
print server_key
print server_key.json()
server_key_id = server_key.json()['keypair'].get('id')
print server_key_id
server_key_private = server_key.json()['keypair'].get('private_key')
print server_key_private
server_key_public = server_key.json()['keypair'].get('public_key')
print server_key_public
debería producir –
https://compute.uk-1.cloud.global.fujitsu.com/v2/7015d1478a4c4bd7b970215d7b0260dd/os-keypairs
{u'keypair': {u'public_key': u'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAu6R92WdwAgPJrWiwkd+wdHQ61ZX/1PL+yVWUXZ86Of+sHhHFUN2vCj6YfzuqKNJaAYjvy6Mga6rT1VBNyoD5EPryaop7w/1GMzRdZ7UaAwtJnNezu8bG054BVpTJ6vspNYsEGZs0KpggsN5O0f0qa2inxq/jDGTy+Le1qWBaQqB33PPVsH6y8a2DgZmDp6n8BY1DTd32GQzprq7ARfWhNu3nNXYmjAjUe/F1H2z2FmkfTDGvs1Un8ETUdywK7Deh938Nqi7agT7ECYSvawlAjwiBILjx0EsERQJr02dRw/BsgbeLsWY50X3l76tmRaiNE95jDGgzovGDBwm8fIL9LQ== Generated by Nova\n', u'private_key': u'-----BEGIN RSA PRIVATE KEY-----\nMIIEoQIBAAKCAQEAu6R92WdwAgPJrWiwkd+wdHQ61ZX/1PL+yVWUXZ86Of+sHhHF\nUN2vCj6YfzuqKNJaAYjvy6Mga6rT1VBNyoD5EPryaop7w/1GMzRdZ7UaAwtJnNez\nu8bG054BVpTJ6vspNYsEGZs0KpggsN5O0f0qa2inxq/jDGTy+Le1qWBaQqB33PPV\nsH6y8a2DgZmDp6n8BY1DTd32GQzprq7ARfWhNu3nNXYmjAjUe/F1H2z2FmkfTDGv\ns1Un8ETUdywK7Deh938Nqi7agT7ECYSvawlAjwiBILjx0EsERQJr02dRw/BsgbeL\nsWY50X3l76tmRaiNE95jDGgzovGDBwm8fIL9LQIBIwKCAQBAVad9vRB1uCfjrt1z\n16o2jkAOtxXinHSczOJpPegT4qFpZS21U1H04kLpy1BIgqKELvMhPz5QzNrqDOd4\noT9ziT0r17VnxI0Y3sDwW1lgISCNi8iYJuUVWr6hV5WvppHJNvoXaGmoNCh3J6X+\n2nTxoDmF8ylGE/uIeYAc0JP5lYQfHpMkMwG1pLOLf6Eb7OZg752+Dp07jedPabYx\n1i/PIkozmslKbgGM3R2CmhoYEWMKpmoOnPlzb4blRcxCiopSWQuhlj/2EI0sE1hc\n6+NE6pbQ5ddsZmm4DvQTACfy/l8H444DvLOAU2zEOVIp5hkCLP4Yv6YBBjfClqWq\nE7YLAoGBAOE/6AqprnrKzaAcboSiOMW4oidUKFFe9heqJJC54LIqGFyl1qEeJAvt\nllr9DjVA1xY/PRrCtb3D8y5ZJXmHjiRmwT/3UWW/Y0Zy+RkewLbmr0X/jVjk75Ns\n6wTcHlW/6/GEj9ny2ed+kul8IKOH1CFtxEVjiaTGXPy1yvxGSezlAoGBANVCR/My\nkMh/v4JjoWkeqOuyMDqPYFohuO9c6zF6uY5GBtzOcWT/eUQI1i66x/S6Cf2DOd+b\nVZKbobIBUFL36r915MEbkeTe1eHV/dSSmIgfV63qjTnvMLx/QR8VMzIp8+XQz/4z\npfFx96nh45MY9U1fwY3gr5VZl7kEXLJbf5KpAoGBAK3Dlb8VLtPBBQZ8VUG++JiH\nHgEVCSjUOi+DQMdq0eiG35ftpZI70qodroC0le6RGvPnpCqWNG3RrPfeXrzWSRTE\nS++ERhtKf8ih1hqxUtY87ZxmDfQeUmpp9yEBk75+HGnbSmZNoMiGNtFfwWg1lQPY\nVZSdPkvpeu7VYhMRpr4PAoGAc8TlOuDvgskBj+zxORCk17iAlNF9csHZa/892Qgb\nlmCHYexpcVd8WCIN3tpsjCp6c62jEvyNihn4sRan8oaVYJ8Vx+plJHj3w71PR4LH\n1N3QgvurwF1GV7LLlIfZ9qkPX3/74cREI/wKGmSuvZE0tPl3s2tYAJ5ZrZSnWYIg\nrrMCgYBvNCvqchbyDrClZTDJqAm+dpMKAdhKABHpuQUqG3hI+3M/hvjCRmFvLPdZ\nD1LNYXX2xB695iXuwF0Ekyvlf0QajToswSrl3wF06osObJ3iGb1IMtfTmb++JL9d\ncKclHW55JWix70Be6/krDsR6CSGT8Q1DiAJDxYxlzlb496AJ8A==\n-----END RSA PRIVATE KEY-----\n', u'user_id': u'03758af9df694db784c3547ab8217abb', u'name': u'demokeypair', u'fingerprint': u'38:a1:83:52:fd:fa:81:a3:87:3b:01:fc:0f:f1:8a:86'}}
None
-----BEGIN RSA PRIVATE KEY-----
MIIEoQIBAAKCAQEAu6R92WdwAgPJrWiwkd+wdHQ61ZX/1PL+yVWUXZ86Of+sHhHF
UN2vCj6YfzuqKNJaAYjvy6Mga6rT1VBNyoD5EPryaop7w/1GMzRdZ7UaAwtJnNez
u8bG054BVpTJ6vspNYsEGZs0KpggsN5O0f0qa2inxq/jDGTy+Le1qWBaQqB33PPV
sH6y8a2DgZmDp6n8BY1DTd32GQzprq7ARfWhNu3nNXYmjAjUe/F1H2z2FmkfTDGv
s1Un8ETUdywK7Deh938Nqi7agT7ECYSvawlAjwiBILjx0EsERQJr02dRw/BsgbeL
sWY50X3l76tmRaiNE95jDGgzovGDBwm8fIL9LQIBIwKCAQBAVad9vRB1uCfjrt1z
16o2jkAOtxXinHSczOJpPegT4qFpZS21U1H04kLpy1BIgqKELvMhPz5QzNrqDOd4
oT9ziT0r17VnxI0Y3sDwW1lgISCNi8iYJuUVWr6hV5WvppHJNvoXaGmoNCh3J6X+
2nTxoDmF8ylGE/uIeYAc0JP5lYQfHpMkMwG1pLOLf6Eb7OZg752+Dp07jedPabYx
1i/PIkozmslKbgGM3R2CmhoYEWMKpmoOnPlzb4blRcxCiopSWQuhlj/2EI0sE1hc
6+NE6pbQ5ddsZmm4DvQTACfy/l8H444DvLOAU2zEOVIp5hkCLP4Yv6YBBjfClqWq
E7YLAoGBAOE/6AqprnrKzaAcboSiOMW4oidUKFFe9heqJJC54LIqGFyl1qEeJAvt
llr9DjVA1xY/PRrCtb3D8y5ZJXmHjiRmwT/3UWW/Y0Zy+RkewLbmr0X/jVjk75Ns
6wTcHlW/6/GEj9ny2ed+kul8IKOH1CFtxEVjiaTGXPy1yvxGSezlAoGBANVCR/My
kMh/v4JjoWkeqOuyMDqPYFohuO9c6zF6uY5GBtzOcWT/eUQI1i66x/S6Cf2DOd+b
VZKbobIBUFL36r915MEbkeTe1eHV/dSSmIgfV63qjTnvMLx/QR8VMzIp8+XQz/4z
pfFx96nh45MY9U1fwY3gr5VZl7kEXLJbf5KpAoGBAK3Dlb8VLtPBBQZ8VUG++JiH
HgEVCSjUOi+DQMdq0eiG35ftpZI70qodroC0le6RGvPnpCqWNG3RrPfeXrzWSRTE
S++ERhtKf8ih1hqxUtY87ZxmDfQeUmpp9yEBk75+HGnbSmZNoMiGNtFfwWg1lQPY
VZSdPkvpeu7VYhMRpr4PAoGAc8TlOuDvgskBj+zxORCk17iAlNF9csHZa/892Qgb
lmCHYexpcVd8WCIN3tpsjCp6c62jEvyNihn4sRan8oaVYJ8Vx+plJHj3w71PR4LH
1N3QgvurwF1GV7LLlIfZ9qkPX3/74cREI/wKGmSuvZE0tPl3s2tYAJ5ZrZSnWYIg
rrMCgYBvNCvqchbyDrClZTDJqAm+dpMKAdhKABHpuQUqG3hI+3M/hvjCRmFvLPdZ
D1LNYXX2xB695iXuwF0Ekyvlf0QajToswSrl3wF06osObJ3iGb1IMtfTmb++JL9d
cKclHW55JWix70Be6/krDsR6CSGT8Q1DiAJDxYxlzlb496AJ8A==
-----END RSA PRIVATE KEY-----
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAu6R92WdwAgPJrWiwkd+wdHQ61ZX/1PL+yVWUXZ86Of+sHhHFUN2vCj6YfzuqKNJaAYjvy6Mga6rT1VBNyoD5EPryaop7w/1GMzRdZ7UaAwtJnNezu8bG054BVpTJ6vspNYsEGZs0KpggsN5O0f0qa2inxq/jDGTy+Le1qWBaQqB33PPVsH6y8a2DgZmDp6n8BY1DTd32GQzprq7ARfWhNu3nNXYmjAjUe/F1H2z2FmkfTDGvs1Un8ETUdywK7Deh938Nqi7agT7ECYSvawlAjwiBILjx0EsERQJr02dRw/BsgbeLsWY50X3l76tmRaiNE95jDGgzovGDBwm8fIL9LQ== Generated by Nova

Paso 11 – El que todos hemos estado esperando, el despliegue de la máquina virtual. Para esto notarás que he configurado dos parámetros prerequisito más: el id del sabor o tamaño de camiseta del vCPU y la RAM de la instancia, y el id de la imagen del sistema operativo que utilizaremos. La llamada a la API se ve así –
def create_server_with_port(k5token, name, imageid, flavorid, sshkey_name, security_group_name, availability_zone, volsize, port_id):
computeURL = unicode(get_endpoint(k5token, "compute")) + unicode('/servers')
print computeURL
token = k5token.headers['X-Subject-Token']
try:
response = requests.post(computeURL,
headers={'X-Auth-Token':token,'Content-Type': 'application/json','Accept':'application/json'},
json={"server": {
"name": name,
"security_groups":[{"name": security_group_name }],
"availability_zone":availability_zone,
"imageRef": imageid,
"flavorRef": flavorid,
"key_name": sshkey_name,
"block_device_mapping_v2": [{
"uuid": imageid,
"boot_index": "0",
"device_name": "/dev/vda",
"source_type": "image",
"volume_size": volsize,
"destination_type": "volume",
"delete_on_termination": True
}],
"networks": [{"port": port_id}],
"metadata": {"Example Custom Tag": "Finance Department"}
}})
return response
except:
return ("\nUnexpected error:", sys.exc_info())
y se llama de esta manera –
# K5 predefined parameters for images and flavors
# this is the id of the K5 ubuntu image
image_id = "ffa17298-537d-40b2-a848-0a4d22b49df5"
# the is the id of a small flavor size (T-1 or P1...need to verify)
flavor_id = "1901"
# Create the virtual machine
new_server = create_server_with_port(k5token, "demoserver", image_id, flavor_id, server_key_name, security_group_name, "uk-1b", 3, server_port_id)
print new_server
print new_server.json()
produciendo lo siguiente –
https://compute.uk-1.cloud.global.fujitsu.com/v2/7015d1478a4c4bd7b970215d7b0260dd/servers
{u'server': {u'links': [{u'href': u'http://10.23.0.201/v2/7015d1478a4c4bd7b970215d7b0260dd/servers/5c57d8bc-6c2d-42bf-a84a-77745651b8e4', u'rel': u'self'}, {u'href': u'http://10.23.0.201/7015d1478a4c4bd7b970215d7b0260dd/servers/5c57d8bc-6c2d-42bf-a84a-77745651b8e4', u'rel': u'bookmark'}], u'OS-DCF:diskConfig': u'MANUAL', u'id': u'5c57d8bc-6c2d-42bf-a84a-77745651b8e4', u'security_groups': [{u'name': u'demosecuritygroup'}]}}
¡Y eso es todo! Ahora deberías tener una nueva instancia ejecutándose en K5.
El siguiente paso solo es necesario si deseas adjuntar una dirección ip flotante externa/pública a tu nueva instancia.

Paso 12 – Añadir una dirección ip flotante o global a la nueva máquina virtual utilizando la siguiente llamada a la API –
def create_global_ip(k5token, ext_network_id, port_id, availability_zone):
networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/floatingips')
print networkURL
token = k5token.headers['X-Subject-Token']
try:
response = requests.post(networkURL,
headers={
'X-Auth-Token': token,
'Content-Type': 'application/json',
'Accept': 'application/json'},
json={
"floatingip": {
"floating_network_id": ext_network_id,
"port_id": port_id,
"availability_zone": availability_zone
},
})
return response
except:
return ("\nUnexpected error:", sys.exc_info())
que debería verse así cuando se invoca –
# Assign a global/public ip address
public_ip = create_global_ip(k5token, extaz2, server_port_id, "uk-1b")
print public_ip
print public_ip.json()
print public_ip.json()['floatingip'].get('floating_ip_address')
y producir esto –
https://networking.uk-1.cloud.global.fujitsu.com/v2.0/floatingips
{u'floatingip': {u'router_id': u'4dde5593-6657-4dea-9095-e0f80129e3f4', u'status': u'DOWN', u'availability_zone': u'uk-1b', u'tenant_id': u'7015d1478a4c4bd7b970215d7b0260dd', u'floating_network_id': u'd730db50-0e0c-4790-9972-1f6e2b8c4915', u'fixed_ip_address': u'192.168.10.2', u'floating_ip_address': u'62.60.42.67', u'port_id': u'f5b24292-8a73-4903-afe1-a71da61a18db', u'id': u'77214fa3-e04a-40f6-93a6-400743bb0862'}}
62.60.42.67

¡La dirección ip anterior se puede utilizar para acceder a tu servidor desde internet!
Ten en cuenta que este es deliberadamente un tutorial bastante detallado. También es posible hacer esto sin tantos pasos, es decir, no creando primero un puerto. Esto es para usuarios que requieren ese poco de detalle extra.
La lista completa del tutorial de ejemplo está aquí..
Este archivo contiene texto Unicode oculto o bidireccional que puede interpretarse o compilarse de manera diferente a lo que aparece a continuación. Para revisarlo, abre el archivo en un editor que revele caracteres Unicode ocultos.
Más información sobre caracteres Unicode bidireccionales
| #!/usr/bin/python | |
| """Resumen: | |
| El siguiente tutorial demuestra cómo se pueden utilizar las APIs nativas de OpenStack para desplegar un servidor, red, subred y enrutador | |
| en la Plataforma IaaS de Fujitsu K5 | |
| Autor: Graham Land | |
| Fecha: 27/01/17 | |
| Twitter: @allthingsclowd | |
| Github: https://github.com/allthingscloud | |
| Blog: https://allthingscloud.eu | |
| """ | |
| import requests | |
| import sys | |
| import json | |
| import pprint | |
| def get_endpoint(k5token, endpoint_type): | |
| # listar los puntos de conexión | |
| for ep in k5token.json()['token']['catalog']: | |
| if len(ep['endpoints'])>0: | |
| # si este es el punto de conexión que estoy buscando devuelve la url | |
| if endpoint_type == ep['endpoints'][0].get('name'): | |
| #pprint.pprint(ep) | |
| return ep['endpoints'][0].get('url') | |
| def get_scoped_token(adminUser, adminPassword, contract, projectid, region): | |
| identityURL = 'https://identity.' + region + \ | |
| '.cloud.global.fujitsu.com/v3/auth/tokens' | |
| try: | |
| response = requests.post(identityURL, | |
| headers={'Content-Type': 'application/json', | |
| 'Accept': 'application/json'}, | |
| json={"auth": | |
| {"identity": | |
| {"methods": ["password"], "password": | |
| {"user": | |
| {"domain": | |
| {"name": contract}, | |
| "name": adminUser, | |
| "password": adminPassword | |
| }}}, | |
| "scope": | |
| {"project": | |
| {"id": projectid | |
| }}}}) | |
| return response | |
| except: | |
| return 'Fallo en el alcance del token del proyecto regional' | |
| def create_network(k5token, name, availability_zone): | |
| networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/networks') | |
| print networkURL | |
| token = k5token.headers['X-Subject-Token'] | |
| try: | |
| response = requests.post(networkURL, | |
| headers={'X-Auth-Token': token, | |
| 'Content-Type': 'application/json'}, | |
| json={ | |
| "network": | |
| { | |
| "name": name, | |
| "admin_state_up": True, | |
| "availability_zone": availability_zone | |
| } | |
| }) | |
| return response | |
| except: | |
| return ("\nError inesperado:", sys.exc_info()) | |
| def create_subnet(k5token, name, netid, cidr, availability_zone): | |
| networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/subnets') | |
| print networkURL | |
| token = k5token.headers['X-Subject-Token'] | |
| try: | |
| response = requests.post(networkURL, | |
| headers={'X-Auth-Token': token, | |
| 'Content-Type': 'application/json'}, | |
| json={ | |
| "subnet": { | |
| "name": name, | |
| "network_id": netid, | |
| "ip_version": 4, | |
| "cidr": cidr, | |
| "availability_zone": availability_zone | |
| } | |
| }) | |
| return response | |
| except: | |
| return ("\nError inesperado:", sys.exc_info()) | |
| def create_router(k5token, name, availability_zone): | |
| networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/routers') | |
| print networkURL | |
| token = k5token.headers['X-Subject-Token'] | |
| try: | |
| response = requests.post(networkURL, | |
| headers={'X-Auth-Token': token, | |
| 'Content-Type': 'application/json'}, | |
| json={ | |
| "router": { | |
| "name": name, | |
| "admin_state_up": True, | |
| "availability_zone": availability_zone | |
| }}) | |
| return response | |
| except: | |
| return ("\nError inesperado:", sys.exc_info()) | |
| def update_router_gateway(k5token, router_id, network_id): | |
| networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/routers/') + router_id | |
| print networkURL | |
| token = k5token.headers['X-Subject-Token'] | |
| try: | |
| response = requests.put(networkURL, | |
| headers={'X-Auth-Token': token, | |
| 'Content-Type': 'application/json'}, | |
| json={ | |
| "router": { | |
| "external_gateway_info": { | |
| "network_id": network_id | |
| } | |
| }}) | |
| return response | |
| except: | |
| return ("\nError inesperado:", sys.exc_info()) | |
| def add_interface_to_router(k5token, router_id, subnet_id): | |
| networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/routers/') + router_id + '/add_router_interface' | |
| print networkURL | |
| token = k5token.headers['X-Subject-Token'] | |
| try: | |
| response = requests.put(networkURL, | |
| headers={'X-Auth-Token': token, | |
| 'Content-Type': 'application/json'}, | |
| json={ | |
| "subnet_id": subnet_id}) | |
| return response | |
| except: | |
| return ("\nError inesperado:", sys.exc_info()) | |
| def create_security_group(k5token, name, description): | |
| networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/security-groups') | |
| print networkURL | |
| token = k5token.headers['X-Subject-Token'] | |
| try: | |
| response = requests.post(networkURL, | |
| headers={'X-Auth-Token': token, 'Content-Type': 'application/json', 'Accept': 'application/json'}, | |
| json={ | |
| "security_group": { | |
| "name": name, | |
| "description": description | |
| } | |
| }) | |
| return response | |
| except: | |
| return ("\nError inesperado:", sys.exc_info()) | |
| def create_security_group_rule(k5token, security_group_id, direction, portmin, portmax, protocol): | |
| networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/security-group-rules') | |
| print networkURL | |
| token = k5token.headers['X-Subject-Token'] | |
| try: | |
| response = requests.post(networkURL, | |
| headers={'X-Auth-Token': token, 'Content-Type': 'application/json', 'Accept': 'application/json'}, | |
| json={ | |
| "security_group_rule": { | |
| "direction": direction, | |
| "port_range_min": portmin, | |
| "ethertype": "IPv4", | |
| "port_range_max": portmax, | |
| "protocol": protocol, | |
| "security_group_id": security_group_id | |
| } | |
| }) | |
| return response | |
| except: | |
| return ("\nError inesperado:", sys.exc_info()) | |
| def create_port(k5token, name, network_id, security_group_id, availability_zone): | |
| networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/ports') | |
| print networkURL | |
| token = k5token.headers['X-Subject-Token'] | |
| try: | |
| response = requests.post(networkURL, | |
| headers={ | |
| 'X-Auth-Token': token, 'Content-Type': 'application/json', 'Accept': 'application/json'}, | |
| json={"port": | |
| {"network_id": network_id, | |
| "name": name, | |
| "admin_state_up": True, | |
| "availability_zone": availability_zone, | |
| "security_groups": | |
| [security_group_id]}}) | |
| return response | |
| except: | |
| return ("\nError inesperado:", sys.exc_info()) | |
| def create_keypair(k5token, keypair_name, availability_zone): | |
| computeURL = unicode(get_endpoint(k5token, "compute")) + unicode('/os-keypairs') | |
| print computeURL | |
| token = k5token.headers['X-Subject-Token'] | |
| try: | |
| response = requests.post(computeURL, | |
| headers={ | |
| 'X-Auth-Token': token, | |
| 'Content-Type': 'application/json', | |
| 'Accept': 'application/json'}, | |
| json={ | |
| "keypair": { | |
| "name": keypair_name, | |
| "availability_zone": availability_zone | |
| }}) | |
| return response | |
| except: | |
| return ("\nError inesperado:", sys.exc_info()) | |
| def create_server_with_port(k5token, name, imageid, flavorid, sshkey_name, security_group_name, availability_zone, volsize, port_id): | |
| computeURL = unicode(get_endpoint(k5token, "compute")) + unicode('/servers') | |
| print computeURL | |
| token = k5token.headers['X-Subject-Token'] | |
| try: | |
| response = requests.post(computeURL, | |
| headers={'X-Auth-Token':token,'Content-Type': 'application/json','Accept':'application/json'}, | |
| json={"server": { | |
| "name": name, | |
| "security_groups":[{"name": security_group_name }], | |
| "availability_zone":availability_zone, | |
| "imageRef": imageid, | |
| "flavorRef": flavorid, | |
| "key_name": sshkey_name, | |
| "block_device_mapping_v2": [{ | |
| "uuid": imageid, | |
| "boot_index": "0", | |
| "device_name": "/dev/vda", | |
| "source_type": "image", | |
| "volume_size": volsize, | |
| "destination_type": "volume", | |
| "delete_on_termination": True | |
| }], | |
| "networks": [{"port": port_id}], | |
| "metadata": {"Example Custom Tag": "Finance Department"} | |
| }}) | |
| return response | |
| except: | |
| return ("\nError inesperado:", sys.exc_info()) | |
| def create_global_ip(k5token, ext_network_id, port_id, availability_zone): | |
| networkURL = unicode(get_endpoint(k5token, "networking")) + unicode('/v2.0/floatingips') | |
| print networkURL | |
| token = k5token.headers['X-Subject-Token'] | |
| try: | |
| response = requests.post(networkURL, | |
| headers={ | |
| 'X-Auth-Token': token, | |
| 'Content-Type': 'application/json', | |
| 'Accept': 'application/json'}, | |
| json={ | |
| "floatingip": { | |
| "floating_network_id": ext_network_id, | |
| "port_id": port_id, | |
| "availability_zone": availability_zone | |
| }, | |
| }) | |
| return response | |
| except: | |
| return ("\nError inesperado:", sys.exc_info()) | |
| def main(): | |
| # Inicializar parámetros del entorno | |
| adminUser = 'username goes here' # nombre de inicio de sesión de usuario k5/openstack | |
| adminPassword = 'password goes here' # contraseña de usuario k5/openstack | |
| contract = 'contract name goes here' # nombre del contrato k5 o nombre del dominio openstack | |
| defaultProject = 'default project name goes here' # id del proyecto predeterminado – en k5 es el nombre del proyecto que comienza con el nombre del contrato y termina con -prj | |
| extaz2 = 'd730db50-0e0c-4790-9972-1f6e2b8c4915' # id de la red externa de la zona de disponibilidad b de K5 | |
| demoProjectA = 'target project goes here' # nombre del proyecto objetivo de demostración k5/openstack | |
| demoProjectAid = 'demo project id' # id del proyecto objetivo de demostración k5/openstack | |
| region = 'uk-1' # región objetivo | |
| # Obtener un token vinculado al proyecto | |
| k5token = get_scoped_token(adminUser, adminPassword, contract, demoProjectAid, region) | |
| # Crear una red virtual de capa 2 | |
| network = create_network(k5token, "demonet", "uk-1b") | |
| print network | |
| print network.json() | |
| network_id = network.json()['network'].get('id') | |
| print network_id | |
| # Crear una subred de capa 3 | |
| subnet = create_subnet(k5token, "demosubnet", network_id, "192.168.10.0/24", "uk-1b") | |
| print subnet | |
| print subnet.json() | |
| subnet_id = subnet.json()['subnet'].get('id') | |
| print subnet_id | |
| # Crear un enrutador virtual de capa 3 | |
| router = create_router(k5token, "demorouter", "uk-1b") | |
| print router | |
| print router.json() | |
| router_id = router.json()['router'].get('id') | |
| print router_id | |
| # Añadir puerta de enlace externa al enrutador (extaz2 es el id de la red externa para la red externa en la zona de disponibilidad b) | |
| router_gateway = update_router_gateway(k5token, router_id, extaz2) | |
| print router_gateway | |
| print router_gateway.json() | |
| # Conectar la subred de la nueva red al enrutador | |
| router_interface = add_interface_to_router(k5token, router_id, subnet_id) | |
| print router_interface | |
| print router_interface.json() | |
| # Crear un nuevo grupo de seguridad | |
| security_group = create_security_group(k5token, "demosecuritygroup", "Demo Security Group Allows RDP, SSH and ICMP") | |
| print security_group | |
| print security_group.json() | |
| security_group_id = security_group.json()['security_group'].get('id') | |
| print security_group_id | |
| security_group_name = security_group.json()['security_group'].get('name') | |
| # Crear reglas de grupo de seguridad | |
| # permitir rdp | |
| rdp_rule = create_security_group_rule(k5token, security_group_id, "ingress", "3389", "3389", "tcp") | |
| print rdp_rule | |
| print rdp_rule.json() | |
| # permitir ssh # permitir rdp | |
| ssh_rule = create_security_group_rule(k5token, security_group_id, "ingress", "22", "22", "tcp") | |
| print ssh_rule | |
| print ssh_rule.json() | |
| # permitir icmp | |
| icmp_rule = create_security_group_rule(k5token, security_group_id, "ingress", "0", "0", "icmp") | |
| print icmp_rule | |
| print icmp_rule.json() | |
| # Crear un nuevo puerto para el servidor | |
| server_port = create_port(k5token, "demoserverport", network_id, security_group_id, "uk-1b") | |
| print server_port | |
| print server_port.json() | |
| server_port_id = server_port.json()['port'].get('id') | |
| print server_port_id | |
| # Crear par de claves ssh que se puede inyectar en el servidor | |
| server_key = create_keypair(k5token, "demokeypair", "uk-1b") | |
| print server_key | |
| print server_key.json() | |
| server_key_id = server_key.json()['keypair'].get('id') | |
| print server_key_id | |
| server_key_private = server_key.json()['keypair'].get('private_key') | |
| print server_key_private | |
| server_key_public = server_key.json()['keypair'].get('public_key') | |
| print server_key_public | |
| server_key_name = server_key.json()['keypair'].get('name') | |
| # Parámetros predefinidos de K5 para imágenes y sabores | |
| # este es el id de la imagen ubuntu de K5 | |
| image_id = "ffa17298-537d-40b2-a848-0a4d22b49df5" | |
| # este es el id de un tamaño de sabor pequeño (T-1 o P1...necesita verificación) | |
| flavor_id = "1901" | |
| # Crear la máquina virtual | |
| new_server = create_server_with_port(k5token, "demoserver", image_id, flavor_id, server_key_name, security_group_name, "uk-1b", 3, server_port_id) | |
| print new_server | |
| print new_server.json() | |
| # Asignar una dirección ip global/pública | |
| public_ip = create_global_ip(k5token, extaz2, server_port_id, "uk-1b") | |
| print public_ip | |
| print public_ip.json() | |
| print public_ip.json()['floatingip'].get('floating_ip_address') | |
| if __name__ == "__main__": | |
| main() |
ver raw
OpenStack_Fujitsu_K5_Server_Build_API_Demo.py
alojado con ❤ por GitHub
o se puede descargar de github aquí..
https://github.com/allthingsclowd/OpenStack_Fujitsu_K5_Server_Build_API_Demo
Asegúrate de configurar los parámetros de entrada ubicados en la función principal para que coincidan con tu entorno objetivo. También hay un script de purga que creé en mi publicación anterior que es bastante útil aquí para las pruebas.
¡Feliz Apilamiento!
withk5youcan
Originally published on allthingscloud.eu (2017-01-27).