]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/node/subscription.rs
api: define subscription key schema and use it
[proxmox-backup.git] / src / api2 / node / subscription.rs
CommitLineData
7b22fb25
TL
1use anyhow::{Error, format_err, bail};
2use serde_json::Value;
7e13b2d6 3
9626c286 4use proxmox::api::{api, Router, RpcEnvironment, Permission};
a2479cfa
WB
5
6use crate::tools;
7b22fb25
TL
7use crate::tools::subscription::{self, SubscriptionStatus, SubscriptionInfo};
8use crate::config::acl::{PRIV_SYS_AUDIT,PRIV_SYS_MODIFY};
9626c286 9use crate::config::cached_user_info::CachedUserInfo;
926d2531 10use crate::api2::types::{NODE_SCHEMA, SUBSCRIPTION_KEY_SCHEMA, Authid};
7e13b2d6 11
1bfc1efa 12#[api(
113c9b59
SR
13 input: {
14 properties: {
15 node: {
16 schema: NODE_SCHEMA,
17 },
7b22fb25
TL
18 force: {
19 description: "Always connect to server, even if information in cache is up to date.",
20 type: bool,
21 optional: true,
22 default: false,
23 },
113c9b59
SR
24 },
25 },
7b22fb25
TL
26 protected: true,
27 access: {
28 permission: &Permission::Privilege(&["system"], PRIV_SYS_MODIFY, false),
29 },
30)]
31/// Check and update subscription status.
32fn check_subscription(
33 force: bool,
34) -> Result<(), Error> {
b57b3c9b
TL
35 // FIXME: drop once proxmox-api-macro is bumped to >> 5.0.0-1
36 let _remove_me = API_METHOD_CHECK_SUBSCRIPTION_PARAM_DEFAULT_FORCE;
7b22fb25
TL
37
38 let info = match subscription::read_subscription() {
39 Err(err) => bail!("could not read subscription status: {}", err),
40 Ok(Some(info)) => info,
41 Ok(None) => return Ok(()),
42 };
43
44 let server_id = tools::get_hardware_address()?;
45 let key = if let Some(key) = info.key {
46 // always update apt auth if we have a key to ensure user can access enterprise repo
47 subscription::update_apt_auth(Some(key.to_owned()), Some(server_id.to_owned()))?;
48 key
49 } else {
50 String::new()
51 };
52
53 if !force && info.status == SubscriptionStatus::ACTIVE {
54 let age = proxmox::tools::time::epoch_i64() - info.checktime.unwrap_or(i64::MAX);
55 if age < subscription::MAX_LOCAL_KEY_AGE {
56 return Ok(());
57 }
58 }
59
60 let info = subscription::check_subscription(key, server_id)?;
61
62 subscription::write_subscription(info)
63 .map_err(|e| format_err!("Error writing updated subscription status - {}", e))?;
64
65 Ok(())
66}
67
68#[api(
69 input: {
1bfc1efa 70 properties: {
7b22fb25
TL
71 node: {
72 schema: NODE_SCHEMA,
1bfc1efa
DM
73 },
74 },
75 },
7b22fb25
TL
76 returns: {
77 description: "Subscription status.",
78 type: SubscriptionInfo,
79 },
1bfc1efa 80 access: {
9626c286 81 permission: &Permission::Anybody,
1bfc1efa
DM
82 },
83)]
84/// Read subscription info.
9626c286
FG
85fn get_subscription(
86 _param: Value,
87 rpcenv: &mut dyn RpcEnvironment,
7b22fb25
TL
88) -> Result<SubscriptionInfo, Error> {
89 let url = "https://www.proxmox.com/en/proxmox-backup-server/pricing";
90
91 let info = match subscription::read_subscription() {
92 Err(err) => bail!("could not read subscription status: {}", err),
93 Ok(Some(info)) => info,
94 Ok(None) => SubscriptionInfo {
95 status: SubscriptionStatus::NOTFOUND,
96 message: Some("There is no subscription key".into()),
97 serverid: Some(tools::get_hardware_address()?),
98 url: Some(url.into()),
99 ..Default::default()
100 },
101 };
102
e6dc35ac 103 let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
9626c286 104 let user_info = CachedUserInfo::new()?;
e6dc35ac 105 let user_privs = user_info.lookup_privs(&auth_id, &[]);
7b22fb25
TL
106
107 if (user_privs & PRIV_SYS_AUDIT) == 0 {
108 // not enough privileges for full state
109 return Ok(SubscriptionInfo {
110 status: info.status,
111 message: info.message,
112 url: info.url,
113 ..Default::default()
114 });
9626c286 115 };
7e13b2d6 116
7b22fb25
TL
117 Ok(info)
118}
119
120#[api(
121 input: {
122 properties: {
123 node: {
124 schema: NODE_SCHEMA,
125 },
126 key: {
926d2531 127 schema: SUBSCRIPTION_KEY_SCHEMA,
7b22fb25
TL
128 },
129 },
130 },
131 protected: true,
132 access: {
133 permission: &Permission::Privilege(&["system"], PRIV_SYS_MODIFY, false),
134 },
135)]
136/// Set a subscription key and check it.
137fn set_subscription(
138 key: String,
139) -> Result<(), Error> {
140
141 let server_id = tools::get_hardware_address()?;
142
143 let info = subscription::check_subscription(key, server_id.to_owned())?;
144
145 subscription::write_subscription(info)
146 .map_err(|e| format_err!("Error writing subscription status - {}", e))?;
147
148 Ok(())
149}
150
151#[api(
152 input: {
153 properties: {
154 node: {
155 schema: NODE_SCHEMA,
156 },
157 },
158 },
159 protected: true,
160 access: {
161 permission: &Permission::Privilege(&["system"], PRIV_SYS_MODIFY, false),
162 },
163)]
164/// Delete subscription info.
165fn delete_subscription() -> Result<(), Error> {
166
167 subscription::delete_subscription()
168 .map_err(|err| format_err!("Deleting subscription failed: {}", err))?;
169
170 Ok(())
7e13b2d6
DM
171}
172
255f378a 173pub const ROUTER: Router = Router::new()
7b22fb25
TL
174 .post(&API_METHOD_CHECK_SUBSCRIPTION)
175 .put(&API_METHOD_SET_SUBSCRIPTION)
176 .delete(&API_METHOD_DELETE_SUBSCRIPTION)
1bfc1efa 177 .get(&API_METHOD_GET_SUBSCRIPTION);