]> git.proxmox.com Git - proxmox-backup.git/blob - src/api2/node/subscription.rs
implement subscription handling and api
[proxmox-backup.git] / src / api2 / node / subscription.rs
1 use anyhow::{Error, format_err, bail};
2 use serde_json::Value;
3
4 use proxmox::api::{api, Router, RpcEnvironment, Permission};
5
6 use crate::tools;
7 use crate::tools::subscription::{self, SubscriptionStatus, SubscriptionInfo};
8 use crate::config::acl::{PRIV_SYS_AUDIT,PRIV_SYS_MODIFY};
9 use crate::config::cached_user_info::CachedUserInfo;
10 use crate::api2::types::{NODE_SCHEMA, Userid};
11
12 #[api(
13 input: {
14 properties: {
15 node: {
16 schema: NODE_SCHEMA,
17 },
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 },
24 },
25 },
26 protected: true,
27 access: {
28 permission: &Permission::Privilege(&["system"], PRIV_SYS_MODIFY, false),
29 },
30 )]
31 /// Check and update subscription status.
32 fn check_subscription(
33 force: bool,
34 ) -> Result<(), Error> {
35
36 let info = match subscription::read_subscription() {
37 Err(err) => bail!("could not read subscription status: {}", err),
38 Ok(Some(info)) => info,
39 Ok(None) => return Ok(()),
40 };
41
42 let server_id = tools::get_hardware_address()?;
43 let key = if let Some(key) = info.key {
44 // always update apt auth if we have a key to ensure user can access enterprise repo
45 subscription::update_apt_auth(Some(key.to_owned()), Some(server_id.to_owned()))?;
46 key
47 } else {
48 String::new()
49 };
50
51 if !force && info.status == SubscriptionStatus::ACTIVE {
52 let age = proxmox::tools::time::epoch_i64() - info.checktime.unwrap_or(i64::MAX);
53 if age < subscription::MAX_LOCAL_KEY_AGE {
54 return Ok(());
55 }
56 }
57
58 let info = subscription::check_subscription(key, server_id)?;
59
60 subscription::write_subscription(info)
61 .map_err(|e| format_err!("Error writing updated subscription status - {}", e))?;
62
63 Ok(())
64 }
65
66 #[api(
67 input: {
68 properties: {
69 node: {
70 schema: NODE_SCHEMA,
71 },
72 },
73 },
74 returns: {
75 description: "Subscription status.",
76 type: SubscriptionInfo,
77 },
78 access: {
79 permission: &Permission::Anybody,
80 },
81 )]
82 /// Read subscription info.
83 fn get_subscription(
84 _param: Value,
85 rpcenv: &mut dyn RpcEnvironment,
86 ) -> Result<SubscriptionInfo, Error> {
87 let url = "https://www.proxmox.com/en/proxmox-backup-server/pricing";
88
89 let info = match subscription::read_subscription() {
90 Err(err) => bail!("could not read subscription status: {}", err),
91 Ok(Some(info)) => info,
92 Ok(None) => SubscriptionInfo {
93 status: SubscriptionStatus::NOTFOUND,
94 message: Some("There is no subscription key".into()),
95 serverid: Some(tools::get_hardware_address()?),
96 url: Some(url.into()),
97 ..Default::default()
98 },
99 };
100
101 let userid: Userid = rpcenv.get_user().unwrap().parse()?;
102 let user_info = CachedUserInfo::new()?;
103 let user_privs = user_info.lookup_privs(&userid, &[]);
104
105 if (user_privs & PRIV_SYS_AUDIT) == 0 {
106 // not enough privileges for full state
107 return Ok(SubscriptionInfo {
108 status: info.status,
109 message: info.message,
110 url: info.url,
111 ..Default::default()
112 });
113 };
114
115 Ok(info)
116 }
117
118 #[api(
119 input: {
120 properties: {
121 node: {
122 schema: NODE_SCHEMA,
123 },
124 key: {
125 description: "Proxmox Backup Server subscription key",
126 type: String,
127 max_length: 32,
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.
137 fn 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.
165 fn delete_subscription() -> Result<(), Error> {
166
167 subscription::delete_subscription()
168 .map_err(|err| format_err!("Deleting subscription failed: {}", err))?;
169
170 Ok(())
171 }
172
173 pub const ROUTER: Router = Router::new()
174 .post(&API_METHOD_CHECK_SUBSCRIPTION)
175 .put(&API_METHOD_SET_SUBSCRIPTION)
176 .delete(&API_METHOD_DELETE_SUBSCRIPTION)
177 .get(&API_METHOD_GET_SUBSCRIPTION);