Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
pve-manager
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
pve-manager
Commits
c19c03d6
Commit
c19c03d6
authored
Mar 22, 2012
by
Dietmar Maurer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add subscription management API
parent
7abe98f1
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
440 additions
and
0 deletions
+440
-0
Makefile
PVE/API2/Makefile
+1
-0
Nodes.pm
PVE/API2/Nodes.pm
+7
-0
Subscription.pm
PVE/API2/Subscription.pm
+361
-0
Makefile
bin/Makefile
+6
-0
pvesubscription
bin/pvesubscription
+65
-0
No files found.
PVE/API2/Makefile
View file @
c19c03d6
include
../../defines.mk
PERLSOURCE
=
\
Subscription.pm
\
VZDump.pm
\
Backup.pm
\
Cluster.pm
\
...
...
PVE/API2/Nodes.pm
View file @
c19c03d6
...
...
@@ -19,6 +19,7 @@ use PVE::AccessControl;
use
PVE::
Storage
;
use
PVE::
OpenVZ
;
use
PVE::
APLInfo
;
use
PVE::API2::
Subscription
;
use
PVE::API2::
Services
;
use
PVE::API2::
Network
;
use
PVE::API2::
Tasks
;
...
...
@@ -51,6 +52,11 @@ __PACKAGE__->register_method ({
path
=>
'
services
',
});
__PACKAGE__
->
register_method
({
subclass
=>
"
PVE::API2::Subscription
",
path
=>
'
subscription
',
});
__PACKAGE__
->
register_method
({
subclass
=>
"
PVE::API2::Network
",
path
=>
'
network
',
...
...
@@ -98,6 +104,7 @@ __PACKAGE__->register_method ({
{
name
=>
'
version
'
},
{
name
=>
'
syslog
'
},
{
name
=>
'
status
'
},
{
name
=>
'
subscription
'
},
{
name
=>
'
tasks
'
},
{
name
=>
'
rrd
'
},
# fixme: remove?
{
name
=>
'
rrddata
'
},
# fixme: remove?
...
...
PVE/API2/Subscription.pm
0 → 100644
View file @
c19c03d6
package
PVE::API2::
Subscription
;
use
strict
;
use
warnings
;
use
Digest::
MD5
qw(md5_hex md5_base64)
;
use
MIME::
Base64
;
use
HTTP::
Request
;
use
LWP::
UserAgent
;
use
JSON
;
use
PVE::
Tools
;
use
PVE::
Exception
qw(raise_param_exc)
;
use
PVE::
INotify
;
use
PVE::
Cluster
qw (cfs_read_file
cfs_write_file
);
use
PVE::
AccessControl
;
use
PVE::
Storage
;
use
PVE::
JSONSchema
qw(get_standard_option)
;
use
PVE::
SafeSyslog
;
use
PVE::
API2Tools
;
use
PVE::
RESTHandler
;
use
base
qw(PVE::RESTHandler)
;
PVE::INotify::
register_file
('
subscription
',
"
/etc/pve-subscription
",
\&
read_etc_pve_subscription
,
\&
write_etc_pve_subscription
);
# How long the local key is valid for in between remote checks
my
$localkeydays
=
15
;
# How many days to allow after local key expiry before blocking
# access if connection cannot be made
my
$allowcheckfaildays
=
5
;
my
$shared_key_data
=
"
kjfdlskfhiuewhfk947368
";
my
$hwaddress
;
sub
get_hwaddress
{
return
$hwaddress
if
defined
(
$hwaddress
);
my
$fn
=
'
/etc/ssh/ssh_host_rsa_key.pub
';
my
$sshkey
=
PVE::Tools::
file_get_contents
(
$fn
);
$hwaddress
=
uc
(
md5_hex
(
$sshkey
));
return
$hwaddress
;
}
my
$hwsockets
;
sub
get_sockets
{
return
$hwsockets
if
$hwsockets
;
my
$fh
=
IO::
File
->
new
('
/proc/cpuinfo
',
"
r
")
||
die
"
can't read cpu info - $!
\n
";
my
$sockets
=
0
;
while
(
defined
(
my
$line
=
<
$fh
>
))
{
if
(
$line
=~
m/^physical id\s*:\s*(\d+)\s*$/i
)
{
my
$sid
=
$1
+
1
;
$sockets
=
$sid
if
$sid
>
$sockets
;
}
}
close
(
$fh
);
die
"
unable to get socket count
\n
"
if
!
$sockets
;
$hwsockets
=
$sockets
;
return
$hwsockets
;
}
sub
parse_key
{
my
(
$key
)
=
@_
;
if
(
$key
=~
m/^pve([124])([cbsp])-[0-9a-f]{10}$/
)
{
return
wantarray
?
(
$1
,
$2
)
:
$1
;
# number of sockets, type
}
return
undef
;
}
sub
check_fields
{
my
(
$info
,
$server_id
,
$req_sockets
)
=
@_
;
foreach
my
$f
(
qw(status checktime key)
)
{
if
(
!
$info
->
{
$f
})
{
die
"
Missing field '
$f
'
\n
";
}
}
my
$sockets
=
parse_key
(
$info
->
{
key
});
if
(
!
$sockets
)
{
die
"
Wrong subscription key format
\n
";
}
if
(
$sockets
<
$req_sockets
)
{
die
"
wrong number of sockets (
$sockets
<
$req_sockets
)
\n
";
}
if
(
$info
->
{
checktime
}
>
time
())
{
die
"
Last check time in future.
\n
";
}
return
undef
if
$info
->
{
status
}
ne
'
Active
';
foreach
my
$f
(
qw(validdomain productname regdate nextduedate)
)
{
if
(
!
$info
->
{
$f
})
{
die
"
Missing field '
$f
'
\n
";
}
}
my
$found
;
foreach
my
$dom
(
split
(
/,/
,
$info
->
{
validdomain
}))
{
if
(
$dom
eq
$server_id
)
{
$found
=
1
;
last
;
}
}
die
"
Server ID does not match
\n
"
if
!
$found
;
return
undef
;
}
sub
read_etc_pve_subscription
{
my
(
$filename
,
$fh
)
=
@_
;
my
$info
=
{
status
=>
'
Invalid
'
};
my
$key
=
<
$fh
>
;
# first line is the key
chomp
$key
;
die
"
Wrong subscription key format
\n
"
if
!
parse_key
(
$key
);
my
$csum
=
<
$fh
>
;
# second line is a checksum
$info
->
{
key
}
=
$key
;
my
$data
=
'';
while
(
defined
(
my
$line
=
<
$fh
>
))
{
$data
.=
$line
;
}
if
(
$csum
&&
$data
)
{
chomp
$csum
;
my
$localinfo
=
{};
eval
{
my
$json_text
=
decode_base64
(
$data
);
$localinfo
=
decode_json
(
$json_text
);
my
$newcsum
=
md5_base64
(
$localinfo
->
{
checktime
}
.
$data
.
$shared_key_data
);
die
"
checksum failure
\n
"
if
$csum
ne
$newcsum
;
my
$req_sockets
=
get_sockets
();
my
$server_id
=
get_hwaddress
();
check_fields
(
$localinfo
,
$server_id
,
$req_sockets
);
my
$age
=
time
()
-
$localinfo
->
{
checktime
};
my
$maxage
=
(
$localkeydays
+
$allowcheckfaildays
)
*
60
*
60
*
24
;
if
(
$localinfo
->
{
status
}
eq
'
Active
'
&&
$age
>
$maxage
)
{
$localinfo
->
{
status
}
=
'
Invalid
';
$localinfo
->
{
message
}
=
"
subscription info too old
";
}
};
if
(
my
$err
=
$@
)
{
warn
$err
;
}
else
{
$info
=
$localinfo
;
}
}
return
$info
;
}
sub
write_etc_pve_subscription
{
my
(
$filename
,
$fh
,
$info
)
=
@_
;
if
(
$info
->
{
status
}
eq
'
New
')
{
PVE::Tools::
safe_print
(
$filename
,
$fh
,
"
$info
->{key}
\n
");
return
;
}
my
$json
=
encode_json
(
$info
);
my
$data
=
encode_base64
(
$json
);
my
$csum
=
md5_base64
(
$info
->
{
checktime
}
.
$data
.
$shared_key_data
);
my
$raw
=
"
$info
->{key}
\n
$csum
\n
$data
";
PVE::Tools::
safe_print
(
$filename
,
$fh
,
$raw
);
}
sub
check_subscription
{
my
(
$key
)
=
@_
;
my
$whmcsurl
=
"
http://shop2.maurer-it.com
";
my
$uri
=
"
$whmcsurl
/modules/servers/licensing/verify.php
";
my
$server_id
=
get_hwaddress
();
my
$req_sockets
=
get_sockets
();
my
$check_token
=
time
()
.
md5_hex
(
rand
(
8999999999
)
+
1000000000
)
.
$key
;
my
$params
=
{
licensekey
=>
$key
,
domain
=>
$server_id
,
ip
=>
'
localhost
',
check_token
=>
$check_token
,
};
my
$req
=
HTTP::
Request
->
new
('
POST
'
=>
$uri
);
$req
->
header
('
Content-Type
'
=>
'
application/x-www-form-urlencoded
');
# We use a temporary URI object to format
# the application/x-www-form-urlencoded content.
my
$url
=
URI
->
new
('
http:
');
$url
->
query_form
(
%
$params
);
my
$content
=
$url
->
query
;
$req
->
header
('
Content-Length
'
=>
length
(
$content
));
$req
->
content
(
$content
);
my
$ua
=
LWP::
UserAgent
->
new
(
protocols_allowed
=>
[
'
http
',
'
https
'
],
timeout
=>
30
);
my
$response
=
$ua
->
request
(
$req
);
my
$code
=
$response
->
code
;
if
(
$code
!=
200
)
{
my
$msg
=
$response
->
message
||
'
unknown
';
die
"
Invalid response from server:
$code
$msg
\n
";
}
my
$raw
=
$response
->
decoded_content
;
my
$subinfo
=
{};
while
(
$raw
=~
m/<(.*?)>([^<]+)<\/\1>/g
)
{
my
(
$k
,
$v
)
=
(
$1
,
$2
);
$subinfo
->
{
$k
}
=
$v
;
}
$subinfo
->
{
checktime
}
=
time
();
$subinfo
->
{
key
}
=
$key
;
my
$emd5sum
=
md5_hex
(
$shared_key_data
.
$check_token
);
if
(
!
$subinfo
->
{
md5hash
}
||
(
$subinfo
->
{
md5hash
}
ne
$emd5sum
))
{
die
"
MD5 Checksum Verification Failed
";
}
check_fields
(
$subinfo
,
$server_id
,
$req_sockets
);
return
$subinfo
;
}
__PACKAGE__
->
register_method
({
name
=>
'
get
',
path
=>
'',
method
=>
'
GET
',
description
=>
"
Read subscription info.
",
proxyto
=>
'
node
',
parameters
=>
{
additionalProperties
=>
0
,
properties
=>
{
node
=>
get_standard_option
('
pve-node
'),
},
},
returns
=>
{
type
=>
'
object
'},
code
=>
sub
{
my
(
$param
)
=
@_
;
my
$info
=
PVE::INotify::
read_file
('
subscription
');
if
(
!
$info
)
{
return
{
status
=>
"
NotFound
",
message
=>
"
There is no subscription key
",
}
}
return
$info
}});
__PACKAGE__
->
register_method
({
name
=>
'
update
',
path
=>
'',
method
=>
'
POST
',
description
=>
"
Update subscription info.
",
proxyto
=>
'
node
',
protected
=>
1
,
parameters
=>
{
additionalProperties
=>
0
,
properties
=>
{
node
=>
get_standard_option
('
pve-node
'),
force
=>
{
description
=>
"
Always connect to server, even if we have up to date info inside local cache.
",
type
=>
'
boolean
',
optional
=>
1
,
default
=>
0
}
},
},
returns
=>
{
type
=>
'
null
'},
code
=>
sub
{
my
(
$param
)
=
@_
;
my
$info
=
PVE::INotify::
read_file
('
subscription
');
return
undef
if
!
$info
;
if
(
!
$param
->
{
force
}
&&
$info
->
{
status
}
eq
'
Active
')
{
my
$age
=
time
()
-
$info
->
{
checktime
};
return
undef
if
$age
<
$localkeydays
*
60
*
60
*
24
;
}
my
$key
=
$info
->
{
key
};
$info
=
check_subscription
(
$key
);
PVE::INotify::
write_file
('
subscription
',
$info
);
return
undef
;
}});
__PACKAGE__
->
register_method
({
name
=>
'
set
',
path
=>
'',
method
=>
'
PUT
',
description
=>
"
Set subscription key.
",
proxyto
=>
'
node
',
protected
=>
1
,
parameters
=>
{
additionalProperties
=>
0
,
properties
=>
{
node
=>
get_standard_option
('
pve-node
'),
key
=>
{
description
=>
"
Proxmox VE subscription key
",
type
=>
'
string
',
},
},
},
returns
=>
{
type
=>
'
null
'},
code
=>
sub
{
my
(
$param
)
=
@_
;
my
$info
=
{
status
=>
'
New
',
key
=>
$param
->
{
key
},
checktime
=>
time
(),
};
my
$req_sockets
=
get_sockets
();
my
$server_id
=
get_hwaddress
();
check_fields
(
$info
,
$server_id
,
$req_sockets
);
PVE::INotify::
write_file
('
subscription
',
$info
);
$info
=
check_subscription
(
$param
->
{
key
});
PVE::INotify::
write_file
('
subscription
',
$info
);
return
undef
;
}});
1
;
bin/Makefile
View file @
c19c03d6
...
...
@@ -12,6 +12,7 @@ SCRIPTS = \
pvectl
\
pvedaemon
\
pveversion
\
pvesubscription
\
pveperf
MANS
=
\
...
...
@@ -21,6 +22,7 @@ MANS = \
pvestatd.1
\
pvedaemon.1
\
pveversion.1
\
pvesubscription.1
\
pveperf.1
all
:
${MANS}
...
...
@@ -38,6 +40,9 @@ pvectl.1.pod: pvectl
vzdump.1.pod
:
vzdump
perl
-I
..
-T
./vzdump printmanpod
>
$@
pvesubscription.1.pod
:
pvesubscription
perl
-I
..
-T
./pvesubscription printmanpod
>
$@
vzrestore.1.pod
:
vzrestore
perl
-I
.. ./vzrestore printmanpod
>
$@
...
...
@@ -52,6 +57,7 @@ install: ${SCRIPTS} ${MANS} pvemailforward
install
-d
${
PODDIR
}
install
-m
0644 pvectl.1.pod
${
PODDIR
}
install
-m
0644 vzdump.1.pod
${
PODDIR
}
install
-m
0644 pvesubscription.1.pod
${
PODDIR
}
install
-m
0644 vzrestore.1.pod
${
PODDIR
}
set
-e
&&
for
i
in
${
SUBDIRS
}
;
do
${
MAKE
}
-C
$$
i
$@
;
done
...
...
bin/pvesubscription
0 → 100755
View file @
c19c03d6
#!/usr/bin/perl -w
use
strict
;
use
PVE::
Tools
;
use
PVE::
SafeSyslog
;
use
PVE::
INotify
;
use
PVE::
RPCEnvironment
;
use
PVE::
CLIHandler
;
use
PVE::API2::
Subscription
;
use
base
qw(PVE::CLIHandler)
;
$ENV
{'
PATH
'}
=
'
/sbin:/bin:/usr/sbin:/usr/bin
';
initlog
('
pvesubscription
');
die
"
please run as root
\n
"
if
$>
!=
0
;
PVE::INotify::
inotify_init
();
my
$rpcenv
=
PVE::
RPCEnvironment
->
init
('
cli
');
$rpcenv
->
init_request
();
$rpcenv
->
set_language
(
$ENV
{
LANG
});
$rpcenv
->
set_user
('
root@pam
');
my
$nodename
=
PVE::INotify::
nodename
();
my
$cmddef
=
{
update
=>
[
'
PVE::API2::Subscription
',
'
update
',
undef
,
{
node
=>
$nodename
}
],
get
=>
[
'
PVE::API2::Subscription
',
'
get
',
undef
,
{
node
=>
$nodename
},
sub
{
my
$info
=
shift
;
foreach
my
$k
(
sort
keys
%
$info
)
{
print
"
$k
:
$info
->{
$k
}
\n
";
}
}],
set
=>
[
'
PVE::API2::Subscription
',
'
set
',
['
key
'],
{
node
=>
$nodename
}
],
};
my
$cmd
=
shift
;
PVE::CLIHandler::
handle_cmd
(
$cmddef
,
"
pvesubscription
",
$cmd
,
\
@ARGV
,
undef
,
$0
);
exit
0
;
__END__
=head1 NAME
pvesubscription - Proxmox VE subscription mamager
=head1 SYNOPSIS
=include synopsis
=head1 DESCRIPTION
This tool is used to handle pve subscriptions.
=include pve_copyright
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment