@@ -2614,18 +2614,18 @@ async def export_bundle(self, filename=None):
26142614 except IOError :
26152615 raise
26162616
2617- async def add_secret (self , name , dataArgs , file = "" , info = "" ):
2617+ async def add_secret (self , name , data_args , file = "" , info = "" ):
26182618 """Adds a secret with a list of key values
26192619
26202620 Equivalent to the cli command:
26212621 juju add-secret [options] <name> [key[#base64|#file]=value...]
26222622
26232623 :param name str: The name of the secret to be added.
2624- :param dataArgs []str: The key value pairs to be added into the secret.
2624+ :param data_args []str: The key value pairs to be added into the secret.
26252625 :param file str: A path to a yaml file containing secret key values.
26262626 :param info str: The secret description.
26272627 """
2628- data = create_secret_data (dataArgs )
2628+ data = create_secret_data (data_args )
26292629
26302630 if file :
26312631 data_from_file = read_secret_data (file )
@@ -2649,6 +2649,39 @@ async def add_secret(self, name, dataArgs, file="", info=""):
26492649 raise JujuAPIError (result .error .message )
26502650 return result .result
26512651
2652+ async def update_secret (self , name , data_args = [], new_name = "" , file = "" , info = "" ):
2653+ """Update a secret with a list of key values, or info.
2654+
2655+ Equivalent to the cli command:
2656+ juju add-secret [options] <name> [key[#base64|#file]=value...]
2657+
2658+ :param name str: The name of the secret to be added.
2659+ :param data_args []str: The key value pairs to be added into the secret.
2660+ :param file str: A path to a yaml file containing secret key values.
2661+ :param info str: The secret description.
2662+ """
2663+ data = create_secret_data (data_args )
2664+ if file :
2665+ data_from_file = read_secret_data (file )
2666+ for k , v in data_from_file .items ():
2667+ # Caution: key/value pairs in files overwrite the ones in the args.
2668+ data [k ] = v
2669+
2670+ if client .SecretsFacade .best_facade_version (self .connection ()) < 2 :
2671+ raise JujuNotSupportedError ("user secrets" )
2672+ secretsFacade = client .SecretsFacade .from_connection (self .connection ())
2673+ results = await secretsFacade .UpdateSecrets ([{
2674+ 'content' : {'data' : data },
2675+ 'description' : info ,
2676+ 'existing-label' : name ,
2677+ 'label' : new_name ,
2678+ }])
2679+ if len (results .results ) != 1 :
2680+ raise JujuAPIError (f"expected 1 result, got { len (results .results )} " )
2681+ result_error = results .results [0 ]
2682+ if result_error .error is not None :
2683+ raise JujuAPIError (result_error .error )
2684+
26522685 async def list_secrets (self , filter = "" , show_secrets = False ):
26532686 """
26542687 Returns the list of available secrets.
@@ -2660,6 +2693,68 @@ async def list_secrets(self, filter="", show_secrets=False):
26602693 })
26612694 return results .results
26622695
2696+ async def remove_secret (self , secret_name , revision = - 1 ):
2697+ """Remove an existing secret.
2698+
2699+ :param secret_name str: ID|name of the secret to remove.
2700+ :param revision int: remove the specified revision.
2701+ """
2702+ if client .SecretsFacade .best_facade_version (self .connection ()) < 2 :
2703+ raise JujuNotSupportedError ("user secrets" )
2704+ remove_secret_arg = {
2705+ 'label' : secret_name ,
2706+ }
2707+ if revision >= 0 :
2708+ remove_secret_arg ['revisions' ] = [revision ]
2709+
2710+ secretsFacade = client .SecretsFacade .from_connection (self .connection ())
2711+ results = await secretsFacade .RemoveSecrets ([remove_secret_arg ])
2712+ if len (results .results ) != 1 :
2713+ raise JujuAPIError (f"expected 1 result, got { len (results .results )} " )
2714+ result_error = results .results [0 ]
2715+ if result_error .error is not None :
2716+ raise JujuAPIError (result_error .error )
2717+
2718+ async def grant_secret (self , secret_name , application , * applications ):
2719+ """Grants access to a secret to the specified applications.
2720+
2721+ :param secret_name str: ID|name of the secret.
2722+ :param application str: name of an application for which the access is granted
2723+ :param applications []str: names of more applications to associate the secret with
2724+ """
2725+ if client .SecretsFacade .best_facade_version (self .connection ()) < 2 :
2726+ raise JujuNotSupportedError ("user secrets" )
2727+ secretsFacade = client .SecretsFacade .from_connection (self .connection ())
2728+ results = await secretsFacade .GrantSecret (
2729+ applications = [application ] + list (applications ),
2730+ label = secret_name )
2731+ if len (results .results ) != 1 :
2732+ raise JujuAPIError (f"expected 1 result, got { len (results .results )} " )
2733+ result_error = results .results [0 ]
2734+ if result_error .error is not None :
2735+ raise JujuAPIError (result_error .error )
2736+
2737+ async def revoke_secret (self , secret_name , application , * applications ):
2738+ """Revoke access to a secret.
2739+
2740+ Revoke applications' access to view the value of a specified secret.
2741+
2742+ :param secret_name str: ID|name of the secret.
2743+ :param application str: name of an application for which the access to the secret is revoked
2744+ :param applications []str: names of more applications to disassociate the secret with
2745+ """
2746+ if client .SecretsFacade .best_facade_version (self .connection ()) < 2 :
2747+ raise JujuNotSupportedError ("user secrets" )
2748+ secretsFacade = client .SecretsFacade .from_connection (self .connection ())
2749+ results = await secretsFacade .RevokeSecret (
2750+ applications = [application ] + list (applications ),
2751+ label = secret_name )
2752+ if len (results .results ) != 1 :
2753+ raise JujuAPIError (f"expected 1 result, got { len (results .results )} " )
2754+ result_error = results .results [0 ]
2755+ if result_error .error is not None :
2756+ raise JujuAPIError (result_error .error )
2757+
26632758 async def _get_source_api (self , url , controller_name = None ):
26642759 controller = Controller ()
26652760 if url .has_empty_source ():
0 commit comments