diff --git a/api-daemon/migrations/versions/88fa0d88a9f8_pvc_version_0_9_55.py b/api-daemon/migrations/versions/88fa0d88a9f8_pvc_version_0_9_55.py new file mode 100644 index 00000000..c739aa49 --- /dev/null +++ b/api-daemon/migrations/versions/88fa0d88a9f8_pvc_version_0_9_55.py @@ -0,0 +1,38 @@ +"""PVC version 0.9.55 + +Revision ID: 88fa0d88a9f8 +Revises: 5c2109dbbeae +Create Date: 2022-10-06 10:33:38.784497 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '88fa0d88a9f8' +down_revision = '5c2109dbbeae' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column('profile', 'script', + existing_type=sa.INTEGER(), + nullable=False) + op.alter_column('profile', 'system_template', + existing_type=sa.INTEGER(), + nullable=False) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column('profile', 'system_template', + existing_type=sa.INTEGER(), + nullable=True) + op.alter_column('profile', 'script', + existing_type=sa.INTEGER(), + nullable=True) + # ### end Alembic commands ### diff --git a/api-daemon/pvcapid/flaskapi.py b/api-daemon/pvcapid/flaskapi.py index b4999f22..e2ec398e 100755 --- a/api-daemon/pvcapid/flaskapi.py +++ b/api-daemon/pvcapid/flaskapi.py @@ -7352,11 +7352,19 @@ class API_Provisioner_Profile_Root(Resource): "required": True, "helptext": "A profile type must be specified.", }, - {"name": "system_template"}, + { + "name": "system_template", + "required": True, + "helptext": "A system_template must be specified.", + }, {"name": "network_template"}, {"name": "storage_template"}, {"name": "userdata"}, - {"name": "script"}, + { + "name": "script", + "required": True, + "helptext": "A script must be specified.", + }, {"name": "ova"}, {"name": "arg", "action": "append"}, ] @@ -7385,12 +7393,12 @@ class API_Provisioner_Profile_Root(Resource): - in: query name: script type: string - required: false + required: true description: Script name - in: query name: system_template type: string - required: false + required: true description: System template name - in: query name: network_template @@ -7473,11 +7481,19 @@ class API_Provisioner_Profile_Element(Resource): "required": True, "helptext": "A profile type must be specified.", }, - {"name": "system_template"}, + { + "name": "system_template", + "required": True, + "helptext": "A system_template must be specified.", + }, {"name": "network_template"}, {"name": "storage_template"}, {"name": "userdata"}, - {"name": "script"}, + { + "name": "script", + "required": True, + "helptext": "A script must be specified.", + }, {"name": "ova"}, {"name": "arg", "action": "append"}, ] @@ -7511,17 +7527,17 @@ class API_Provisioner_Profile_Element(Resource): - in: query name: network_template type: string - required: true + required: false description: Network template name - in: query name: storage_template type: string - required: true + required: false description: Storage template name - in: query name: userdata type: string - required: true + required: false description: Userdata template name - in: query name: ova diff --git a/api-daemon/pvcapid/models.py b/api-daemon/pvcapid/models.py index 6cd440de..d9d2b35b 100755 --- a/api-daemon/pvcapid/models.py +++ b/api-daemon/pvcapid/models.py @@ -230,11 +230,13 @@ class DBProfile(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Text, nullable=False, unique=True) profile_type = db.Column(db.Text, nullable=False) - system_template = db.Column(db.Integer, db.ForeignKey("system_template.id")) + system_template = db.Column( + db.Integer, db.ForeignKey("system_template.id"), nullable=False + ) network_template = db.Column(db.Integer, db.ForeignKey("network_template.id")) storage_template = db.Column(db.Integer, db.ForeignKey("storage_template.id")) userdata = db.Column(db.Integer, db.ForeignKey("userdata.id")) - script = db.Column(db.Integer, db.ForeignKey("script.id")) + script = db.Column(db.Integer, db.ForeignKey("script.id"), nullable=False) ova = db.Column(db.Integer, db.ForeignKey("ova.id")) arguments = db.Column(db.Text) diff --git a/api-daemon/pvcapid/ova.py b/api-daemon/pvcapid/ova.py index 84a377fe..c51942f6 100755 --- a/api-daemon/pvcapid/ova.py +++ b/api-daemon/pvcapid/ova.py @@ -168,6 +168,15 @@ def delete_ova(zkhandler, name): @ZKConnection(config) def upload_ova(zkhandler, pool, name, ova_size): + # Check that we have a default_ova provisioning script + _, retcode = provisioner.list_script("default_ova", is_fuzzy=False) + if retcode != "200": + output = { + "message": "Did not find a 'default_ova' provisioning script. Please add one with that name, either the example from '/usr/share/pvc/provisioner/examples/script/2-ova.py' or a custom one, before uploading OVAs." + } + retcode = 400 + return output, retcode + ova_archive = None # Cleanup function @@ -402,7 +411,7 @@ def upload_ova(zkhandler, pool, name, ova_size): None, None, userdata=None, - script=None, + script="default_ova", ova=name, arguments=None, ) diff --git a/api-daemon/pvcapid/vmbuilder.py b/api-daemon/pvcapid/vmbuilder.py index 73b98991..a2d8564a 100755 --- a/api-daemon/pvcapid/vmbuilder.py +++ b/api-daemon/pvcapid/vmbuilder.py @@ -277,6 +277,8 @@ def create_vm( vm_data["script"] = db_row.get("script") else: vm_data["script"] = None + + if profile_data.get("profile_type") == "ova": query = "SELECT * FROM ova WHERE id = %s" args = (profile_data["ova"],) db_cur.execute(query, args) @@ -285,6 +287,7 @@ def create_vm( query = "SELECT * FROM ova_volume WHERE ova = %s" args = (profile_data["ova"],) db_cur.execute(query, args) + # Replace the existing volumes list with our OVA volume list vm_data["volumes"] = db_cur.fetchall() retcode, stdout, stderr = pvc_common.run_os_command("uname -m") diff --git a/client-cli/pvc/pvc.py b/client-cli/pvc/pvc.py index 317e0d5f..79760e77 100755 --- a/client-cli/pvc/pvc.py +++ b/client-cli/pvc/pvc.py @@ -5265,7 +5265,8 @@ def provisioner_profile_list(limit): "-s", "--system-template", "system_template", - help="The system template for the profile.", + required=True, + help="The system template for the profile (required).", ) @click.option( "-n", @@ -5280,10 +5281,24 @@ def provisioner_profile_list(limit): help="The storage template for the profile.", ) @click.option( - "-u", "--userdata", "userdata", help="The userdata document for the profile." + "-u", + "--userdata", + "userdata", + help="The userdata document for the profile.", +) +@click.option( + "-x", + "--script", + "script", + required=True, + help="The script for the profile (required).", +) +@click.option( + "-o", + "--ova", + "ova", + help="The OVA image for the profile; set automatically with 'provisioner ova upload'.", ) -@click.option("-x", "--script", "script", help="The script for the profile.") -@click.option("-o", "--ova", "ova", help="The OVA image for the profile.") @click.option( "-a", "--script-arg", diff --git a/docs/manuals/swagger.json b/docs/manuals/swagger.json index ed1fcf57..03001f4d 100644 --- a/docs/manuals/swagger.json +++ b/docs/manuals/swagger.json @@ -3025,14 +3025,14 @@ "description": "Script name", "in": "query", "name": "script", - "required": false, + "required": true, "type": "string" }, { "description": "System template name", "in": "query", "name": "system_template", - "required": false, + "required": true, "type": "string" }, { @@ -3165,21 +3165,21 @@ "description": "Network template name", "in": "query", "name": "network_template", - "required": true, + "required": false, "type": "string" }, { "description": "Storage template name", "in": "query", "name": "storage_template", - "required": true, + "required": false, "type": "string" }, { "description": "Userdata template name", "in": "query", "name": "userdata", - "required": true, + "required": false, "type": "string" }, {