Add GET handlers for both all custom CPU models and specific ones, POST
handler for creating custom CPU models, PUT handler for updating them,
and DELETE handler for deleting them.

Original patches:
https://lore.proxmox.com/pve-devel/[email protected]/
https://lore.proxmox.com/pve-devel/[email protected]/

Originally-by: Stefan Reiter <[email protected]>
Signed-off-by: Arthur Bied-Charreton <[email protected]>
---
 src/PVE/API2/Qemu/CPU.pm | 236 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 235 insertions(+), 1 deletion(-)

diff --git a/src/PVE/API2/Qemu/CPU.pm b/src/PVE/API2/Qemu/CPU.pm
index f8a7e11d..9d89504d 100644
--- a/src/PVE/API2/Qemu/CPU.pm
+++ b/src/PVE/API2/Qemu/CPU.pm
@@ -52,7 +52,7 @@ __PACKAGE__->register_method({
                 },
             },
         },
-        links => [{ rel => 'child', href => '{name}' }],
+        links => [{ rel => 'child', href => 'model/{cputype}' }],
     },
     code => sub {
         my ($param) = @_;
@@ -67,4 +67,238 @@ __PACKAGE__->register_method({
     },
 });
 
+__PACKAGE__->register_method({
+    name => 'config',
+    path => 'model',
+    method => 'GET',
+    description => 'Read all custom CPU models definitions',
+    permissions => {
+        check => ['perm', '/nodes', ['Sys.Audit']],
+    },
+    parameters => {
+        additionalProperties => 0,
+        properties => {
+            node => get_standard_option('pve-node'),
+        },
+    },
+    returns => {
+        type => 'array',
+        items => {
+            type => 'object',
+            properties => get_standard_option('pve-qemu-cpu'),
+        },
+    },
+    code => sub {
+        my $conf = PVE::QemuServer::CPUConfig::load_custom_model_conf();
+        delete $conf->{order};
+        my $ids = [];
+        foreach my $id (keys %{ $conf->{ids} }) {
+            delete $conf->{ids}->{$id}->{type};
+            push @$ids, $conf->{ids}->{$id};
+        }
+        return $ids;
+    },
+});
+
+__PACKAGE__->register_method({
+    name => 'create',
+    path => 'model',
+    method => 'POST',
+    protected => 1,
+    description => 'Add a custom CPU model definition',
+    permissions => {
+        check => ['perm', '/nodes', ['Sys.Console']],
+    },
+    parameters => {
+        additionalProperties => 0,
+        properties => PVE::QemuServer::CPUConfig::add_cpu_json_properties({
+            digest => get_standard_option('pve-config-digest'),
+            node => get_standard_option('pve-node'),
+        }),
+    },
+    returns => { type => 'null' },
+    code => sub {
+        my ($param) = @_;
+        delete $param->{node};
+
+        my $digest = extract_param($param, 'digest');
+
+        my $name = $param->{cputype};
+        die "custom cpu models 'cputype' must start with 'custom-' prefix\n"
+            if $name !~ m/^custom-/;
+        (my $name_no_prefix = $name) =~ s/^custom-//;
+
+        PVE::QemuServer::CPUConfig::lock_cpu_config(sub {
+            my $conf = PVE::QemuServer::CPUConfig::load_custom_model_conf();
+            PVE::SectionConfig::assert_if_modified($conf, $digest);
+
+            die "custom CPU model '$name' already exists\n"
+                if defined($conf->{ids}->{$name_no_prefix});
+            $conf->{ids}->{$name_no_prefix} = $param;
+
+            PVE::QemuServer::CPUConfig::write_custom_model_conf($conf);
+        });
+    },
+});
+
+__PACKAGE__->register_method({
+    name => 'delete',
+    path => 'model/{cputype}',
+    method => 'DELETE',
+    protected => 1,
+    description => 'Delete a custom CPU model definition',
+    permissions => {
+        check => ['perm', '/nodes', ['Sys.Console']],
+    },
+    parameters => {
+        additionalProperties => 0,
+        properties => {
+            node => get_standard_option('pve-node'),
+            digest => get_standard_option('pve-config-digest'),
+            cputype => {
+                type => 'string',
+                description => "The custom model to delete. Must be prefixed 
with 'custom-'",
+            },
+        },
+    },
+    returns => { type => 'null' },
+    code => sub {
+        my ($param) = @_;
+
+        my $digest = extract_param($param, 'digest');
+
+        my $name = $param->{cputype};
+        die "'cputype' must start with 'custom-' prefix\n" if $name !~ 
m/^custom-/;
+        (my $name_no_prefix = $name) =~ s/^custom-//;
+
+        PVE::QemuServer::CPUConfig::lock_cpu_config(sub {
+            my $conf = PVE::QemuServer::CPUConfig::load_custom_model_conf();
+            PVE::SectionConfig::assert_if_modified($conf, $digest);
+
+            die "custom CPU model '$name_no_prefix' does not exist\n"
+                if !defined($conf->{ids}->{$name_no_prefix});
+            delete $conf->{ids}->{$name_no_prefix};
+
+            PVE::QemuServer::CPUConfig::write_custom_model_conf($conf);
+        });
+
+    },
+});
+
+__PACKAGE__->register_method({
+    name => 'update',
+    path => 'model/{cputype}',
+    method => 'PUT',
+    protected => 1,
+    description => "Update a custom CPU model definition.",
+    permissions => {
+        check => ['perm', '/nodes', ['Sys.Console']],
+    },
+    parameters => {
+        additionalProperties => 0,
+        properties => PVE::QemuServer::CPUConfig::add_cpu_json_properties({
+            node => get_standard_option('pve-node'),
+            digest => get_standard_option('pve-config-digest'),
+            delete => {
+                type => 'string',
+                format => 'pve-configid-list',
+                description => "A list of properties to delete.",
+                optional => 1,
+            },
+        }),
+    },
+    returns => { type => 'null' },
+    code => sub {
+        my ($param) = @_;
+        delete $param->{node};
+
+        my $digest = extract_param($param, 'digest');
+        my $delete = extract_param($param, 'delete') // '';
+        my %delete_hash = map { $_ => 1 } PVE::Tools::split_list($delete);
+
+        my $name = $param->{cputype};
+        die "custom CPU model's 'cputype' must start with 'custom-' prefix\n"
+            if $name !~ m/^custom-/;
+
+        (my $name_no_prefix = $name) =~ s/^custom-//;
+
+        PVE::QemuServer::CPUConfig::lock_cpu_config(sub {
+            my $conf = PVE::QemuServer::CPUConfig::load_custom_model_conf();
+
+            PVE::SectionConfig::assert_if_modified($conf, $digest);
+
+            my $model = $conf->{ids}->{$name_no_prefix};
+            die "custom CPU model '$name_no_prefix' does not exist\n" if 
!defined($model);
+
+            my $props = 
PVE::QemuServer::CPUConfig::add_cpu_json_properties({});
+            for my $p (keys %$props) {
+                if ($delete_hash{$p}) {
+                    die "cannot delete 'cputype' property\n" if $p eq 
'cputype';
+                    die "cannot set and delete property '$p' at once\n" if 
$param->{$p};
+                    delete $model->{$p};
+                } elsif (defined($param->{$p})) {
+                    $model->{$p} = $param->{$p};
+                }
+            }
+
+            PVE::QemuServer::CPUConfig::write_custom_model_conf($conf);
+        });
+    },
+});
+
+__PACKAGE__->register_method({
+    name => 'info',
+    path => 'model/{cputype}',
+    method => 'GET',
+    description => 'Retrieve details about a specific CPU model',
+    permissions => {
+        check => ['perm', '/nodes', ['Sys.Audit']],
+    },
+    parameters => {
+        additionalProperties => 0,
+        properties => {
+            node => get_standard_option('pve-node'),
+            cputype => {
+                type => 'string',
+                description =>
+                    "Name of the CPU model to query. Prefix with 'custom-' for 
custom models.",
+            },
+        },
+    },
+    returns => {
+        type => 'object',
+        properties => PVE::QemuServer::CPUConfig::add_cpu_json_properties({
+            vendor => {
+                type => 'string',
+                description => 'The CPU vendor reported to the guest OS. Only'
+                    . ' relevant for default models.',
+                optional => 1,
+            },
+            digest => get_standard_option('pve-config-digest'),
+        }),
+    },
+    code => sub {
+        my ($param) = @_;
+        my $cputype = $param->{cputype};
+
+        if ($cputype =~ m/^custom-/) {
+            my $conf = PVE::QemuServer::CPUConfig::load_custom_model_conf();
+            my $digest = $conf->{digest};
+            my $retval = 
PVE::QemuServer::CPUConfig::get_custom_model($cputype);
+            $retval->{digest} = $digest;
+            return $retval;
+        }
+
+        # this correctly errors in case $cputype is unknown
+        my $vendor = PVE::QemuServer::CPUConfig::get_cpu_vendor($cputype);
+
+        my $retval = {
+            cputype => $cputype,
+            vendor => $vendor,
+        };
+
+        return $retval;
+    },
+});
+
 1;
-- 
2.47.3



Reply via email to