]> git.proxmox.com Git - pve-manager.git/blobdiff - PVE/API2/Ceph.pm
api: ceph: remove deprecrated config and configdb endpoints
[pve-manager.git] / PVE / API2 / Ceph.pm
index d872c7c03b8c82197383ec067b901daa4a13f0e2..1b765b759ebfb9951fa2f5d803ea3c3bf8609ca9 100644 (file)
@@ -16,19 +16,26 @@ use PVE::RADOS;
 use PVE::RESTHandler;
 use PVE::RPCEnvironment;
 use PVE::Storage;
-use PVE::Tools qw(run_command file_get_contents file_set_contents);
+use PVE::Tools qw(run_command file_get_contents file_set_contents extract_param);
 
+use PVE::API2::Ceph::Cfg;
 use PVE::API2::Ceph::OSD;
 use PVE::API2::Ceph::FS;
 use PVE::API2::Ceph::MDS;
 use PVE::API2::Ceph::MGR;
 use PVE::API2::Ceph::MON;
+use PVE::API2::Ceph::Pool;
 use PVE::API2::Storage::Config;
 
 use base qw(PVE::RESTHandler);
 
 my $pve_osd_default_journal_size = 1024*5;
 
+__PACKAGE__->register_method ({
+    subclass => "PVE::API2::Ceph::Cfg",
+    path => 'cfg',
+});
+
 __PACKAGE__->register_method ({
     subclass => "PVE::API2::Ceph::OSD",
     path => 'osd',
@@ -54,6 +61,11 @@ __PACKAGE__->register_method ({
     path => 'fs',
 });
 
+__PACKAGE__->register_method ({
+    subclass => "PVE::API2::Ceph::Pool",
+    path => 'pool',
+});
+
 __PACKAGE__->register_method ({
     name => 'index',
     path => '',
@@ -81,194 +93,29 @@ __PACKAGE__->register_method ({
        my ($param) = @_;
 
        my $result = [
+           { name => 'cmd-safety' },
+           { name => 'cfg' },
+           { name => 'config' },
+           { name => 'configdb' },
+           { name => 'crush' },
+           { name => 'fs' },
            { name => 'init' },
+           { name => 'log' },
+           { name => 'mds' },
+           { name => 'mgr' },
            { name => 'mon' },
            { name => 'osd' },
            { name => 'pools' },
-           { name => 'fs' },
-           { name => 'mds' },
-           { name => 'stop' },
-           { name => 'start' },
            { name => 'restart' },
-           { name => 'status' },
-           { name => 'crush' },
-           { name => 'config' },
-           { name => 'log' },
-           { name => 'disks' },
-           { name => 'flags' }, # FIXME: remove with 7.0
            { name => 'rules' },
+           { name => 'start' },
+           { name => 'status' },
+           { name => 'stop' },
        ];
 
        return $result;
     }});
 
-__PACKAGE__->register_method ({
-    name => 'disks',
-    path => 'disks',
-    method => 'GET',
-    description => "List local disks.",
-    proxyto => 'node',
-    protected => 1,
-    permissions => {
-       check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
-    },
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           node => get_standard_option('pve-node'),
-           type => {
-               description => "Only list specific types of disks.",
-               type => 'string',
-               enum => ['unused', 'journal_disks'],
-               optional => 1,
-           },
-       },
-    },
-    returns => {
-       type => 'array',
-       items => {
-           type => "object",
-           properties => {
-               dev => { type => 'string' },
-               used => { type => 'string', optional => 1 },
-               gpt => { type => 'boolean' },
-               size => { type => 'integer' },
-               osdid => { type => 'integer' },
-               vendor =>  { type => 'string', optional => 1 },
-               model =>  { type => 'string', optional => 1 },
-               serial =>  { type => 'string', optional => 1 },
-           },
-       },
-       # links => [ { rel => 'child', href => "{}" } ],
-    },
-    code => sub {
-       my ($param) = @_;
-
-       PVE::Ceph::Tools::check_ceph_inited();
-
-       my $disks = PVE::Diskmanage::get_disks(undef, 1);
-
-       my $res = [];
-       foreach my $dev (keys %$disks) {
-           my $d = $disks->{$dev};
-           if ($param->{type}) {
-               if ($param->{type} eq 'journal_disks') {
-                   next if $d->{osdid} >= 0;
-                   next if !$d->{gpt};
-               } elsif ($param->{type} eq 'unused') {
-                   next if $d->{used};
-               } else {
-                   die "internal error"; # should not happen
-               }
-           }
-
-           $d->{dev} = "/dev/$dev";
-           push @$res, $d;
-       }
-
-       return $res;
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'config',
-    path => 'config',
-    method => 'GET',
-    proxyto => 'node',
-    permissions => {
-       check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
-    },
-    description => "Get Ceph configuration.",
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           node => get_standard_option('pve-node'),
-       },
-    },
-    returns => { type => 'string' },
-    code => sub {
-       my ($param) = @_;
-
-       PVE::Ceph::Tools::check_ceph_inited();
-
-       my $path = PVE::Ceph::Tools::get_config('pve_ceph_cfgpath');
-       return file_get_contents($path);
-
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'configdb',
-    path => 'configdb',
-    method => 'GET',
-    proxyto => 'node',
-    protected => 1,
-    permissions => {
-       check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
-    },
-    description => "Get Ceph configuration database.",
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           node => get_standard_option('pve-node'),
-       },
-    },
-    returns => {
-       type => 'array',
-       items => {
-           type => 'object',
-           properties => {
-               section => { type => "string", },
-               name => { type => "string", },
-               value => { type => "string", },
-               level => { type => "string", },
-               'can_update_at_runtime' => { type => "boolean", },
-               mask => { type => "string" },
-           },
-       },
-    },
-    code => sub {
-       my ($param) = @_;
-
-       PVE::Ceph::Tools::check_ceph_inited();
-
-       my $rados = PVE::RADOS->new();
-       my $res = $rados->mon_command( { prefix => 'config dump', format => 'json' });
-       foreach my $entry (@$res) {
-           $entry->{can_update_at_runtime} = $entry->{can_update_at_runtime}? 1 : 0; # JSON::true/false -> 1/0
-       }
-
-       return $res;
-    }});
-
-my $add_storage = sub {
-    my ($pool, $storeid) = @_;
-
-    my $storage_params = {
-       type => 'rbd',
-       pool => $pool,
-       storage => $storeid,
-       krbd => 0,
-       content => 'rootdir,images',
-    };
-
-    PVE::API2::Storage::Config->create($storage_params);
-};
-
-my $get_storages = sub {
-    my ($pool) = @_;
-
-    my $cfg = PVE::Storage::config();
-
-    my $storages = $cfg->{ids};
-    my $res = {};
-    foreach my $storeid (keys %$storages) {
-       my $curr = $storages->{$storeid};
-       $res->{$storeid} = $storages->{$storeid}
-           if $curr->{type} eq 'rbd' && $pool eq $curr->{pool};
-    }
-
-    return $res;
-};
-
 __PACKAGE__->register_method ({
     name => 'init',
     path => 'init',
@@ -583,383 +430,6 @@ __PACKAGE__->register_method ({
        return PVE::Ceph::Tools::ceph_cluster_status();
     }});
 
-__PACKAGE__->register_method ({
-    name => 'lspools',
-    path => 'pools',
-    method => 'GET',
-    description => "List all pools.",
-    proxyto => 'node',
-    protected => 1,
-    permissions => {
-       check => ['perm', '/', [ 'Sys.Audit', 'Datastore.Audit' ], any => 1],
-    },
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           node => get_standard_option('pve-node'),
-       },
-    },
-    returns => {
-       type => 'array',
-       items => {
-           type => "object",
-           properties => {
-               pool => { type => 'integer' },
-               pool_name => { type => 'string' },
-               size => { type => 'integer' },
-               pg_autoscale_mode => { type => 'string', optional => 1 },
-           },
-       },
-       links => [ { rel => 'child', href => "{pool_name}" } ],
-    },
-    code => sub {
-       my ($param) = @_;
-
-       PVE::Ceph::Tools::check_ceph_inited();
-
-       my $rados = PVE::RADOS->new();
-
-       my $stats = {};
-       my $res = $rados->mon_command({ prefix => 'df' });
-
-       foreach my $d (@{$res->{pools}}) {
-           next if !$d->{stats};
-           next if !defined($d->{id});
-           $stats->{$d->{id}} = $d->{stats};
-       }
-
-       $res = $rados->mon_command({ prefix => 'osd dump' });
-       my $rulestmp = $rados->mon_command({ prefix => 'osd crush rule dump'});
-
-       my $rules = {};
-       for my $rule (@$rulestmp) {
-           $rules->{$rule->{rule_id}} = $rule->{rule_name};
-       }
-
-       my $data = [];
-       my $attr_list = [
-           'pool',
-           'pool_name',
-           'size',
-           'min_size',
-           'pg_num',
-           'crush_rule',
-           'pg_autoscale_mode',
-       ];
-
-       foreach my $e (@{$res->{pools}}) {
-           my $d = {};
-           foreach my $attr (@$attr_list) {
-               $d->{$attr} = $e->{$attr} if defined($e->{$attr});
-           }
-
-           if (defined($d->{crush_rule}) && defined($rules->{$d->{crush_rule}})) {
-               $d->{crush_rule_name} = $rules->{$d->{crush_rule}};
-           }
-
-           if (my $s = $stats->{$d->{pool}}) {
-               $d->{bytes_used} = $s->{bytes_used};
-               $d->{percent_used} = $s->{percent_used};
-           }
-           push @$data, $d;
-       }
-
-
-       return $data;
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'createpool',
-    path => 'pools',
-    method => 'POST',
-    description => "Create POOL",
-    proxyto => 'node',
-    protected => 1,
-    permissions => {
-       check => ['perm', '/', [ 'Sys.Modify' ]],
-    },
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           node => get_standard_option('pve-node'),
-           name => {
-               description => "The name of the pool. It must be unique.",
-               type => 'string',
-           },
-           size => {
-               description => 'Number of replicas per object',
-               type => 'integer',
-               default => 3,
-               optional => 1,
-               minimum => 1,
-               maximum => 7,
-           },
-           min_size => {
-               description => 'Minimum number of replicas per object',
-               type => 'integer',
-               default => 2,
-               optional => 1,
-               minimum => 1,
-               maximum => 7,
-           },
-           pg_num => {
-               description => "Number of placement groups.",
-               type => 'integer',
-               default => 128,
-               optional => 1,
-               minimum => 8,
-               maximum => 32768,
-           },
-           crush_rule => {
-               description => "The rule to use for mapping object placement in the cluster.",
-               type => 'string',
-               optional => 1,
-           },
-           application => {
-               description => "The application of the pool, 'rbd' by default.",
-               type => 'string',
-               enum => ['rbd', 'cephfs', 'rgw'],
-               optional => 1,
-           },
-           add_storages => {
-               description => "Configure VM and CT storage using the new pool.",
-               type => 'boolean',
-               optional => 1,
-           },
-       },
-    },
-    returns => { type => 'string' },
-    code => sub {
-       my ($param) = @_;
-
-       PVE::Cluster::check_cfs_quorum();
-       PVE::Ceph::Tools::check_ceph_configured();
-
-       my $pool = $param->{name};
-       my $rpcenv = PVE::RPCEnvironment::get();
-       my $user = $rpcenv->get_user();
-
-       if ($param->{add_storages}) {
-           $rpcenv->check($user, '/storage', ['Datastore.Allocate']);
-           die "pool name contains characters which are illegal for storage naming\n"
-               if !PVE::JSONSchema::parse_storage_id($pool);
-       }
-
-       my $pg_num = $param->{pg_num} || 128;
-       my $size = $param->{size} || 3;
-       my $min_size = $param->{min_size} || 2;
-       my $application = $param->{application} // 'rbd';
-
-       my $worker = sub {
-
-           PVE::Ceph::Tools::create_pool($pool, $param);
-
-           if ($param->{add_storages}) {
-               my $err;
-               eval { $add_storage->($pool, "${pool}"); };
-               if ($@) {
-                   warn "failed to add storage: $@";
-                   $err = 1;
-               }
-               die "adding storage for pool '$pool' failed, check log and add manually!\n"
-                   if $err;
-           }
-       };
-
-       return $rpcenv->fork_worker('cephcreatepool', $pool,  $user, $worker);
-    }});
-
-my $possible_flags = PVE::Ceph::Tools::get_possible_osd_flags();
-my $possible_flags_list = [ sort keys %$possible_flags ];
-
-# FIXME: Remove with PVE 7.0
-__PACKAGE__->register_method ({
-    name => 'get_flags',
-    path => 'flags',
-    method => 'GET',
-    description => "get all set ceph flags",
-    proxyto => 'node',
-    protected => 1,
-    permissions => {
-       check => ['perm', '/', [ 'Sys.Audit' ]],
-    },
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           node => get_standard_option('pve-node'),
-       },
-    },
-    returns => { type => 'string' },
-    code => sub {
-       my ($param) = @_;
-
-       PVE::Ceph::Tools::check_ceph_configured();
-
-       my $rados = PVE::RADOS->new();
-
-       my $stat = $rados->mon_command({ prefix => 'osd dump' });
-
-       return $stat->{flags} // '';
-    }});
-
-# FIXME: Remove with PVE 7.0
-__PACKAGE__->register_method ({
-    name => 'set_flag',
-    path => 'flags/{flag}',
-    method => 'POST',
-    description => "Set a specific ceph flag",
-    proxyto => 'node',
-    protected => 1,
-    permissions => {
-       check => ['perm', '/', [ 'Sys.Modify' ]],
-    },
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           node => get_standard_option('pve-node'),
-           flag => {
-               description => 'The ceph flag to set',
-               type => 'string',
-               enum => $possible_flags_list,
-           },
-       },
-    },
-    returns => { type => 'null' },
-    code => sub {
-       my ($param) = @_;
-
-       PVE::Ceph::Tools::check_ceph_configured();
-
-       my $rados = PVE::RADOS->new();
-
-       $rados->mon_command({
-           prefix => "osd set",
-           key => $param->{flag},
-       });
-
-       return undef;
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'unset_flag',
-    path => 'flags/{flag}',
-    method => 'DELETE',
-    description => "Unset a ceph flag",
-    proxyto => 'node',
-    protected => 1,
-    permissions => {
-       check => ['perm', '/', [ 'Sys.Modify' ]],
-    },
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           node => get_standard_option('pve-node'),
-           flag => {
-               description => 'The ceph flag to unset',
-               type => 'string',
-               enum => $possible_flags_list,
-           },
-       },
-    },
-    returns => { type => 'null' },
-    code => sub {
-       my ($param) = @_;
-
-       PVE::Ceph::Tools::check_ceph_configured();
-
-       my $rados = PVE::RADOS->new();
-
-       $rados->mon_command({
-           prefix => "osd unset",
-           key => $param->{flag},
-       });
-
-       return undef;
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'destroypool',
-    path => 'pools/{name}',
-    method => 'DELETE',
-    description => "Destroy pool",
-    proxyto => 'node',
-    protected => 1,
-    permissions => {
-       check => ['perm', '/', [ 'Sys.Modify' ]],
-    },
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           node => get_standard_option('pve-node'),
-           name => {
-               description => "The name of the pool. It must be unique.",
-               type => 'string',
-           },
-           force => {
-               description => "If true, destroys pool even if in use",
-               type => 'boolean',
-               optional => 1,
-               default => 0,
-           },
-           remove_storages => {
-               description => "Remove all pveceph-managed storages configured for this pool",
-               type => 'boolean',
-               optional => 1,
-               default => 0,
-           },
-       },
-    },
-    returns => { type => 'string' },
-    code => sub {
-       my ($param) = @_;
-
-       PVE::Ceph::Tools::check_ceph_inited();
-
-       my $rpcenv = PVE::RPCEnvironment::get();
-       my $user = $rpcenv->get_user();
-       $rpcenv->check($user, '/storage', ['Datastore.Allocate'])
-           if $param->{remove_storages};
-
-       my $pool = $param->{name};
-
-       my $worker = sub {
-           my $storages = $get_storages->($pool);
-
-           # if not forced, destroy ceph pool only when no
-           # vm disks are on it anymore
-           if (!$param->{force}) {
-               my $storagecfg = PVE::Storage::config();
-               foreach my $storeid (keys %$storages) {
-                   my $storage = $storages->{$storeid};
-
-                   # check if any vm disks are on the pool
-                   print "checking storage '$storeid' for RBD images..\n";
-                   my $res = PVE::Storage::vdisk_list($storagecfg, $storeid);
-                   die "ceph pool '$pool' still in use by storage '$storeid'\n"
-                       if @{$res->{$storeid}} != 0;
-               }
-           }
-
-           PVE::Ceph::Tools::destroy_pool($pool);
-
-           if ($param->{remove_storages}) {
-               my $err;
-               foreach my $storeid (keys %$storages) {
-                   # skip external clusters, not managed by pveceph
-                   next if $storages->{$storeid}->{monhost};
-                   eval { PVE::API2::Storage::Config->delete({storage => $storeid}) };
-                   if ($@) {
-                       warn "failed to remove storage '$storeid': $@\n";
-                       $err = 1;
-                   }
-               }
-               die "failed to remove (some) storages - check log and remove manually!\n"
-                   if $err;
-           }
-       };
-       return $rpcenv->fork_worker('cephdestroypool', $pool,  $user, $worker);
-    }});
-
 
 __PACKAGE__->register_method ({
     name => 'crush',
@@ -1088,7 +558,12 @@ __PACKAGE__->register_method ({
        type => 'array',
        items => {
            type => "object",
-           properties => {},
+           properties => {
+               name => {
+                   description => "Name of the CRUSH rule.",
+                   type => "string",
+               }
+           },
        },
        links => [ { rel => 'child', href => "{name}" } ],
     },
@@ -1110,4 +585,100 @@ __PACKAGE__->register_method ({
        return $res;
     }});
 
+__PACKAGE__->register_method ({
+    name => 'cmd_safety',
+    path => 'cmd-safety',
+    method => 'GET',
+    description => "Heuristical check if it is safe to perform an action.",
+    proxyto => 'node',
+    protected => 1,
+    permissions => {
+       check => ['perm', '/', [ 'Sys.Audit' ]],
+    },
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           service => {
+               description => 'Service type',
+               type => 'string',
+               enum => ['osd', 'mon', 'mds'],
+           },
+           id => {
+               description => 'ID of the service',
+               type => 'string',
+           },
+           action => {
+               description => 'Action to check',
+               type => 'string',
+               enum => ['stop', 'destroy'],
+           },
+       },
+    },
+    returns => {
+       type => 'object',
+       properties => {
+          safe  => {
+               type => 'boolean',
+               description => 'If it is safe to run the command.',
+           },
+           status => {
+               type => 'string',
+               optional => 1,
+               description => 'Status message given by Ceph.'
+           },
+       },
+    },
+    code => sub {
+       my ($param) = @_;
+
+       PVE::Ceph::Tools::check_ceph_inited();
+
+       my $id = $param->{id};
+       my $service = $param->{service};
+       my $action = $param->{action};
+
+       my $rados = PVE::RADOS->new();
+
+       my $supported_actions = {
+           osd => {
+               stop => 'ok-to-stop',
+               destroy => 'safe-to-destroy',
+           },
+           mon => {
+               stop => 'ok-to-stop',
+               destroy => 'ok-to-rm',
+           },
+           mds => {
+               stop => 'ok-to-stop',
+           },
+       };
+
+       die "Service does not support this action: ${service}: ${action}\n"
+           if !$supported_actions->{$service}->{$action};
+
+       my $result = {
+           safe => 0,
+           status => '',
+       };
+
+       my $params = {
+           prefix => "${service} $supported_actions->{$service}->{$action}",
+           format => 'plain',
+       };
+       if ($service eq 'mon' && $action eq 'destroy') {
+           $params->{id} = $id;
+       } else {
+           $params->{ids} = [ $id ];
+       }
+
+       $result = $rados->mon_cmd($params, 1);
+       die $@ if $@;
+
+       $result->{safe} = $result->{return_code} == 0 ? 1 : 0;
+       $result->{status} = $result->{status_message};
+
+       return $result;
+    }});
+
 1;