@@ -116,6 +116,14 @@ impl RustFsProvider {
116116 Ok ( Self { s3, admin, info } )
117117 }
118118
119+ /// Log the equivalent rustfs-cli invocation for an API call.
120+ /// `$ALIAS` stands for an `rc alias` configured with the admin
121+ /// credentials; `$USER_ALIAS` for one configured with the acting
122+ /// user's credentials. Filter with RUST_LOG=rc_cli=info.
123+ fn cli ( cmd : & str ) {
124+ tracing:: info!( target: "rc_cli" , "equivalent: rc {cmd}" ) ;
125+ }
126+
119127 /// Admin client authenticated as a regular user (for service-account
120128 /// operations, which RustFS scopes to the calling identity).
121129 fn client_as ( & self , username : & str , password : & str ) -> Result < AdminClient > {
@@ -154,57 +162,70 @@ fn optional<T>(res: rc_core::Result<T>) -> Result<Option<T>> {
154162#[ async_trait]
155163impl RustFs for RustFsProvider {
156164 async fn bucket_exists ( & self , bucket : & str ) -> Result < bool > {
165+ Self :: cli ( & format ! ( "stat $ALIAS/{bucket}" ) ) ;
157166 Ok ( self . s3 . bucket_exists ( bucket) . await ?)
158167 }
159168
160169 async fn create_bucket ( & self , bucket : & str ) -> Result < ( ) > {
170+ Self :: cli ( & format ! ( "mb $ALIAS/{bucket}" ) ) ;
161171 Ok ( self . s3 . create_bucket ( bucket) . await ?)
162172 }
163173
164174 async fn delete_bucket ( & self , bucket : & str ) -> Result < ( ) > {
175+ Self :: cli ( & format ! ( "rb $ALIAS/{bucket}" ) ) ;
165176 match self . s3 . delete_bucket ( bucket) . await {
166177 Ok ( ( ) ) => Ok ( ( ) ) ,
167178 Err ( e) => absent ( e) ,
168179 }
169180 }
170181
171182 async fn get_versioning ( & self , bucket : & str ) -> Result < Option < bool > > {
183+ Self :: cli ( & format ! ( "version info $ALIAS/{bucket}" ) ) ;
172184 Ok ( self . s3 . get_versioning ( bucket) . await ?)
173185 }
174186
175187 async fn set_versioning ( & self , bucket : & str , enabled : bool ) -> Result < ( ) > {
188+ let verb = if enabled { "enable" } else { "suspend" } ;
189+ Self :: cli ( & format ! ( "version {verb} $ALIAS/{bucket}" ) ) ;
176190 Ok ( self . s3 . set_versioning ( bucket, enabled) . await ?)
177191 }
178192
179193 async fn get_bucket_quota ( & self , bucket : & str ) -> Result < Option < u64 > > {
194+ Self :: cli ( & format ! ( "quota info $ALIAS/{bucket}" ) ) ;
180195 match optional ( self . admin . get_bucket_quota ( bucket) . await ) ? {
181196 Some ( q) => Ok ( q. quota . filter ( |q| * q > 0 ) ) ,
182197 None => Ok ( None ) ,
183198 }
184199 }
185200
186201 async fn set_bucket_quota ( & self , bucket : & str , quota : u64 ) -> Result < ( ) > {
202+ Self :: cli ( & format ! ( "quota set $ALIAS/{bucket} {quota}" ) ) ;
187203 self . admin . set_bucket_quota ( bucket, quota) . await ?;
188204 Ok ( ( ) )
189205 }
190206
191207 async fn get_user ( & self , access_key : & str ) -> Result < Option < User > > {
208+ Self :: cli ( & format ! ( "admin user info $ALIAS {access_key}" ) ) ;
192209 optional ( self . admin . get_user ( access_key) . await )
193210 }
194211
195212 async fn create_user ( & self , access_key : & str , secret_key : & str ) -> Result < ( ) > {
213+ Self :: cli ( & format ! ( "admin user add $ALIAS {access_key} ****" ) ) ;
196214 self . admin . create_user ( access_key, secret_key) . await ?;
197215 Ok ( ( ) )
198216 }
199217
200218 async fn delete_user ( & self , access_key : & str ) -> Result < ( ) > {
219+ Self :: cli ( & format ! ( "admin user rm $ALIAS {access_key}" ) ) ;
201220 match self . admin . delete_user ( access_key) . await {
202221 Ok ( ( ) ) => Ok ( ( ) ) ,
203222 Err ( e) => absent ( e) ,
204223 }
205224 }
206225
207226 async fn set_user_status ( & self , access_key : & str , enabled : bool ) -> Result < ( ) > {
227+ let verb = if enabled { "enable" } else { "disable" } ;
228+ Self :: cli ( & format ! ( "admin user {verb} $ALIAS {access_key}" ) ) ;
208229 let status = if enabled {
209230 UserStatus :: Enabled
210231 } else {
@@ -214,21 +235,29 @@ impl RustFs for RustFsProvider {
214235 }
215236
216237 async fn set_user_policies ( & self , user : & str , policies : & [ String ] ) -> Result < ( ) > {
238+ Self :: cli ( & format ! (
239+ "admin policy attach $ALIAS {} --user {user}" ,
240+ policies. join( "," )
241+ ) ) ;
217242 Ok ( self
218243 . admin
219244 . attach_policy ( policies, PolicyEntity :: User , user)
220245 . await ?)
221246 }
222247
223248 async fn get_policy ( & self , name : & str ) -> Result < Option < Policy > > {
249+ Self :: cli ( & format ! ( "admin policy info $ALIAS {name}" ) ) ;
224250 optional ( self . admin . get_policy ( name) . await )
225251 }
226252
227253 async fn put_policy ( & self , name : & str , document : & str ) -> Result < ( ) > {
254+ Self :: cli ( & format ! ( "admin policy create $ALIAS {name} policy.json" ) ) ;
255+ tracing:: debug!( target: "rc_cli" , "policy.json: {document}" ) ;
228256 Ok ( self . admin . create_policy ( name, document) . await ?)
229257 }
230258
231259 async fn delete_policy ( & self , name : & str ) -> Result < ( ) > {
260+ Self :: cli ( & format ! ( "admin policy rm $ALIAS {name}" ) ) ;
232261 match self . admin . delete_policy ( name) . await {
233262 Ok ( ( ) ) => Ok ( ( ) ) ,
234263 Err ( e) => absent ( e) ,
@@ -245,6 +274,9 @@ impl RustFs for RustFsProvider {
245274 password : & str ,
246275 access_key : & str ,
247276 ) -> Result < Option < ServiceAccount > > {
277+ Self :: cli ( & format ! (
278+ "admin service-account info $USER_ALIAS {access_key} # $USER_ALIAS uses {username}'s credentials"
279+ ) ) ;
248280 let client = self . client_as ( username, password) ?;
249281 optional ( client. get_service_account ( access_key) . await )
250282 }
@@ -258,6 +290,14 @@ impl RustFs for RustFsProvider {
258290 description : Option < String > ,
259291 policy : Option < String > ,
260292 ) -> Result < ( ) > {
293+ Self :: cli ( & format ! (
294+ "admin service-account create $USER_ALIAS {access_key} ****{} # $USER_ALIAS uses {username}'s credentials" ,
295+ if policy. is_some( ) {
296+ " --policy policy.json"
297+ } else {
298+ ""
299+ }
300+ ) ) ;
261301 let client = self . client_as ( username, password) ?;
262302 client
263303 . create_service_account ( CreateServiceAccountRequest {
@@ -278,6 +318,7 @@ impl RustFs for RustFsProvider {
278318 password : & str ,
279319 access_key : & str ,
280320 ) -> Result < ( ) > {
321+ Self :: cli ( & format ! ( "admin service-account rm $ALIAS {access_key}" ) ) ;
281322 // Try as admin first (covers keys whose owner was already deleted),
282323 // fall back to the owning user.
283324 match self . admin . delete_service_account ( access_key) . await {
0 commit comments