parent
92df125a77
commit
49e5ce1176
|
@ -3334,6 +3334,53 @@ class API_Storage_Ceph_Volume_Element_Clone(Resource):
|
||||||
)
|
)
|
||||||
api.add_resource(API_Storage_Ceph_Volume_Element_Clone, '/storage/ceph/volume/<pool>/<volume>/clone')
|
api.add_resource(API_Storage_Ceph_Volume_Element_Clone, '/storage/ceph/volume/<pool>/<volume>/clone')
|
||||||
|
|
||||||
|
# /storage/ceph/volume/<pool>/<volume>/upload
|
||||||
|
class API_Storage_Ceph_Volume_Element_Upload(Resource):
|
||||||
|
@Authenticator
|
||||||
|
def post(self, pool, volume):
|
||||||
|
"""
|
||||||
|
Upload a disk image to Ceph volume {volume} in pool {pool}
|
||||||
|
---
|
||||||
|
tags:
|
||||||
|
- storage / ceph
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: file
|
||||||
|
type: binary
|
||||||
|
required: true
|
||||||
|
description: The raw binary contents of the file
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
id: Message
|
||||||
|
404:
|
||||||
|
description: Not found
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
id: Message
|
||||||
|
400:
|
||||||
|
description: Bad request
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
id: Message
|
||||||
|
"""
|
||||||
|
from flask_restful import reqparse
|
||||||
|
from werkzeug.datastructures import FileStorage
|
||||||
|
parser = reqparse.RequestParser()
|
||||||
|
parser.add_argument('file', type=FileStorage, location='files')
|
||||||
|
data = parser.parse_args()
|
||||||
|
image_data = data.get('file', None)
|
||||||
|
if not image_data:
|
||||||
|
return {'message':'An image file contents must be specified'}, 400
|
||||||
|
return api_helper.ceph_volume_upload(
|
||||||
|
pool,
|
||||||
|
volume,
|
||||||
|
image_data
|
||||||
|
)
|
||||||
|
api.add_resource(API_Storage_Ceph_Volume_Element_Upload, '/storage/ceph/volume/<pool>/<volume>/upload')
|
||||||
|
|
||||||
# /storage/ceph/snapshot
|
# /storage/ceph/snapshot
|
||||||
class API_Storage_Ceph_Snapshot_Root(Resource):
|
class API_Storage_Ceph_Snapshot_Root(Resource):
|
||||||
@RequestParser([
|
@RequestParser([
|
||||||
|
|
|
@ -1327,6 +1327,49 @@ def ceph_volume_remove(pool, name):
|
||||||
}
|
}
|
||||||
return output, retcode
|
return output, retcode
|
||||||
|
|
||||||
|
def ceph_volume_upload(pool, volume, data):
|
||||||
|
"""
|
||||||
|
Upload a raw file via HTTP post to a PVC Ceph volume
|
||||||
|
"""
|
||||||
|
# Map the target blockdev
|
||||||
|
zk_conn = pvc_common.startZKConnection(config['coordinators'])
|
||||||
|
retflag, retdata = pvc_ceph.map_volume(zk_conn, pool, volume)
|
||||||
|
pvc_common.stopZKConnection(zk_conn)
|
||||||
|
if not retflag:
|
||||||
|
output = {
|
||||||
|
'message': retdata.replace('\"', '\'')
|
||||||
|
}
|
||||||
|
retcode = 400
|
||||||
|
return output, retcode
|
||||||
|
blockdev = retdata
|
||||||
|
|
||||||
|
output = {
|
||||||
|
'message': "Wrote uploaded file to volume '{}' in pool '{}'.".format(volume, pool)
|
||||||
|
}
|
||||||
|
retcode = 200
|
||||||
|
|
||||||
|
# Save the data to the blockdev
|
||||||
|
try:
|
||||||
|
data.save(blockdev)
|
||||||
|
except:
|
||||||
|
output = {
|
||||||
|
'message': "ERROR: Failed to write image file to volume."
|
||||||
|
}
|
||||||
|
retcode = 400
|
||||||
|
|
||||||
|
# Unmap the target blockdev
|
||||||
|
zk_conn = pvc_common.startZKConnection(config['coordinators'])
|
||||||
|
retflag, retdata = pvc_ceph.unmap_volume(zk_conn, pool, volume)
|
||||||
|
pvc_common.stopZKConnection(zk_conn)
|
||||||
|
if not retflag:
|
||||||
|
output = {
|
||||||
|
'message': retdata.replace('\"', '\'')
|
||||||
|
}
|
||||||
|
retcode = 400
|
||||||
|
return output, retcode
|
||||||
|
|
||||||
|
return output, retcode
|
||||||
|
|
||||||
def ceph_volume_snapshot_list(pool=None, volume=None, limit=None, is_fuzzy=True):
|
def ceph_volume_snapshot_list(pool=None, volume=None, limit=None, is_fuzzy=True):
|
||||||
"""
|
"""
|
||||||
Get the list of RBD volume snapshots in the Ceph storage cluster.
|
Get the list of RBD volume snapshots in the Ceph storage cluster.
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#
|
#
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import click
|
import click
|
||||||
import json
|
import json
|
||||||
|
@ -903,7 +904,7 @@ def add_volume(zk_conn, pool, name, size):
|
||||||
'/ceph/snapshots/{}/{}'.format(pool, name): '',
|
'/ceph/snapshots/{}/{}'.format(pool, name): '',
|
||||||
})
|
})
|
||||||
|
|
||||||
return True, 'Created RBD volume "{}/{}" ({})'.format(pool, name, size)
|
return True, 'Created RBD volume "{}/{}" ({}).'.format(pool, name, size)
|
||||||
|
|
||||||
def clone_volume(zk_conn, pool, name_src, name_new):
|
def clone_volume(zk_conn, pool, name_src, name_new):
|
||||||
if not verifyVolume(zk_conn, pool, name_src):
|
if not verifyVolume(zk_conn, pool, name_src):
|
||||||
|
@ -994,6 +995,41 @@ def remove_volume(zk_conn, pool, name):
|
||||||
|
|
||||||
return True, 'Removed RBD volume "{}" in pool "{}".'.format(name, pool)
|
return True, 'Removed RBD volume "{}" in pool "{}".'.format(name, pool)
|
||||||
|
|
||||||
|
def map_volume(zk_conn, pool, name):
|
||||||
|
if not verifyVolume(zk_conn, pool, name):
|
||||||
|
return False, 'ERROR: No volume with name "{}" is present in pool "{}".'.format(name, pool)
|
||||||
|
|
||||||
|
# 1. Map the volume onto the local system
|
||||||
|
retcode, stdout, stderr = common.run_os_command('rbd map {}/{}'.format(pool, name))
|
||||||
|
if retcode:
|
||||||
|
return False, 'ERROR: Failed to map RBD volume "{}" in pool "{}": {}'.format(name, pool, stderr)
|
||||||
|
|
||||||
|
# 2. Calculate the absolute path to the mapped volume
|
||||||
|
mapped_volume = '/dev/rbd/{}/{}'.format(pool, name)
|
||||||
|
|
||||||
|
# 3. Ensure the volume exists
|
||||||
|
if not os.path.exists(mapped_volume):
|
||||||
|
return False, 'ERROR: Mapped volume not found at expected location "{}".'.format(mapped_volume)
|
||||||
|
|
||||||
|
return True, mapped_volume
|
||||||
|
|
||||||
|
def unmap_volume(zk_conn, pool, name):
|
||||||
|
if not verifyVolume(zk_conn, pool, name):
|
||||||
|
return False, 'ERROR: No volume with name "{}" is present in pool "{}".'.format(name, pool)
|
||||||
|
|
||||||
|
mapped_volume = '/dev/rbd/{}/{}'.format(pool, name)
|
||||||
|
|
||||||
|
# 1. Ensure the volume exists
|
||||||
|
if not os.path.exists(mapped_volume):
|
||||||
|
return False, 'ERROR: Mapped volume not found at expected location "{}".'.format(mapped_volume)
|
||||||
|
|
||||||
|
# 2. Unap the volume
|
||||||
|
retcode, stdout, stderr = common.run_os_command('rbd unmap {}'.format(mapped_volume))
|
||||||
|
if retcode:
|
||||||
|
return False, 'ERROR: Failed to unmap RBD volume at "{}": {}'.format(mapped_volume, stderr)
|
||||||
|
|
||||||
|
return True, 'Unmapped RBD volume at "{}".'.format(mapped_volume)
|
||||||
|
|
||||||
def get_list_volume(zk_conn, pool, limit, is_fuzzy=True):
|
def get_list_volume(zk_conn, pool, limit, is_fuzzy=True):
|
||||||
volume_list = []
|
volume_list = []
|
||||||
if pool and not verifyPool(zk_conn, pool):
|
if pool and not verifyPool(zk_conn, pool):
|
||||||
|
|
|
@ -4691,6 +4691,44 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/storage/ceph/volume/{pool}/{volume}/upload": {
|
||||||
|
"post": {
|
||||||
|
"description": "",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "The raw binary contents of the file",
|
||||||
|
"in": "query",
|
||||||
|
"name": "file",
|
||||||
|
"required": true,
|
||||||
|
"type": "binary"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Message"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Message"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Message"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Upload a disk image to Ceph volume {volume} in pool {pool}",
|
||||||
|
"tags": [
|
||||||
|
"storage / ceph"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/vm": {
|
"/api/v1/vm": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "",
|
"description": "",
|
||||||
|
|
Loading…
Reference in New Issue