Repository: Azure/azure-linux-extensions

Issue:
add/restore support for account expiration in VMAccess extension
For some reason account expiration support not added or removed from VMAccess extension.

vmaccess.py

```
    error_string = waagent.MyDistro.CreateAccount(
        user_name, user_pass, None, None)
```

waagent

```
    def CreateAccount(self,user, password, expiration, thumbprint):
        return CreateAccount(user, password, expiration, thumbprint)
```

Sometimes it is needed to set expiration time for account but with current version it is not possible.
Looks like it was supported before since it is mentioned in [blog about VMAccess Extension](https://azure.microsoft.com/en-us/blog/using-vmaccess-extension-to-reset-login-credentials-for-linux-vm/)



Discussion:
Thank you for the report!  Agreed, this functionality should exist.  I will add support.

I reviewed every revision of vmaccess.py, and I cannot find a single instance where code to use expiration exists.  It appears there was a miscommunication between the implementers and the documenters.


Resolving patch:
diff --git a/VMAccess/vmaccess.py b/VMAccess/vmaccess.py
--- a/VMAccess/vmaccess.py
+++ b/VMAccess/vmaccess.py
@@ -140,17 +140,18 @@ def _set_user_account_pub_key(protect_settings, hutil):
     user_name = protect_settings['username']
     user_pass = protect_settings.get('password')
     cert_txt = protect_settings.get('ssh_key')
+    expiration = protect_settings.get('expiration')
     no_convert = False
-    if(not(user_pass) and not(cert_txt) and not(ovf_env.SshPublicKeys)):
+    if not user_pass and not cert_txt and not ovf_env.SshPublicKeys:
         raise Exception("No password or ssh_key is specified.")
 
     # Reset user account and password, password could be empty
     sudoers = _get_other_sudoers(user_name)
     error_string = waagent.MyDistro.CreateAccount(
-        user_name, user_pass, None, None)
+        user_name, user_pass, expiration, None)
     _save_other_sudoers(sudoers)
 
-    if error_string != None:
+    if error_string is not None:
         err_msg = "Failed to create the account or set the password"
         waagent.AddExtensionEvent(name=hutil.get_name(),
                                   op=waagent.WALAEventOperation.Enable,
@@ -172,7 +173,7 @@ def _set_user_account_pub_key(protect_settings, hutil):
                 'authorized_keys')
             ovf_env.UserName = user_name
             if(no_convert):
-                if(cert_txt):
+                if cert_txt:
                     pub_path = ovf_env.PrepareDir(pub_path)
                     final_cert_txt = cert_txt
                     if(not cert_txt.endswith("\n")):
@@ -301,9 +302,9 @@ def _reset_sshd_config(sshd_file_path):
         cfg_content += "      [Socket]\n"
         cfg_content += "      ListenStream={0}\n".format(sshd_port)
         cfg_content += "      Accept=yes\n"
-        
+
         waagent.SetFileContents(cfg_tempfile, cfg_content)
-        
+
         waagent.Run("coreos-cloudinit -from-file " + cfg_tempfile, chk_err=False)
         os.remove(cfg_tempfile)
     else:
@@ -312,7 +313,7 @@ def _reset_sshd_config(sshd_file_path):
 
 
 def _backup_sshd_config(sshd_file_path):
-    if(os.path.exists(sshd_file_path)):
+    if os.path.exists(sshd_file_path):
         backup_file_name = '%s_%s' % (
             sshd_file_path, time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()))
         shutil.copyfile(sshd_file_path, backup_file_name)
@@ -320,10 +321,10 @@ def _backup_sshd_config(sshd_file_path):
 
 def _save_cert_str_as_file(cert_txt, file_name):
     cert_start = cert_txt.find(BeginCertificateTag)
-    if(cert_start >= 0):
+    if cert_start >= 0:
         cert_txt = cert_txt[cert_start + len(BeginCertificateTag):]
     cert_end = cert_txt.find(EndCertificateTag)
-    if(cert_end >= 0):
+    if cert_end >= 0:
         cert_txt = cert_txt[:cert_end]
     cert_txt = cert_txt.strip()
     cert_txt = "{0}\n{1}\n{2}\n".format(BeginCertificateTag, cert_txt, EndCertificateTag)
@@ -345,7 +346,6 @@ def _open_ssh_port():
 
 
 def _del_rule_if_exists(rule_string):
-    match_string = '-A %s' % rule_string
     cmd_result = waagent.RunGetOutput("iptables-save")
     while cmd_result[0] == 0 and (rule_string in cmd_result[1]):
         waagent.Run("iptables -D %s" % rule_string)
@@ -353,11 +353,11 @@ def _del_rule_if_exists(rule_string):
 
 
 def _insert_rule_if_not_exists(rule_string):
-    match_string = '-A %s' % rule_string
     cmd_result = waagent.RunGetOutput("iptables-save")
     if cmd_result[0] == 0 and (rule_string not in cmd_result[1]):
         waagent.Run("iptables -I %s" % rule_string)
 
+
 def check_and_repair_disk(hutil):
     public_settings = hutil.get_public_settings()
     if public_settings:
@@ -381,6 +381,7 @@ def check_and_repair_disk(hutil):
             hutil.log("Repaired and remounted disk")
             return outdata
 
+
 def _fsck_check(hutil):
     try:
         retcode = waagent.Run("fsck -As -y")
@@ -399,14 +400,14 @@ def _fsck_repair(hutil, disk_name):
     # first unmount disks and loop devices lazy + forced
     try:
         cmd_result = waagent.Run("umount -f /%s" % disk_name)
-        if cmd_result!=0:
+        if cmd_result != 0:
             # Fail fast
             hutil.log("Failed to unmount disk: %s" % disk_name)
             # run repair
             retcode = waagent.Run("fsck -AR -y")
             hutil.log("Ran fsck with return code: %d" % retcode)
         if retcode == 0:
-            retcode,output = waagent.RunGetOutput("mount")
+            retcode, output = waagent.RunGetOutput("mount")
             hutil.log(output)
             return output
         else:


Test patch: