Skip to content

Commit

Permalink
Merge branch 'develop' into ignore-warn
Browse files Browse the repository at this point in the history
  • Loading branch information
nagworld9 authored Jun 30, 2023
2 parents 072bd5a + 6a32b50 commit c5809cb
Show file tree
Hide file tree
Showing 27 changed files with 544 additions and 180 deletions.
17 changes: 10 additions & 7 deletions azurelinuxagent/common/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,17 +129,17 @@ def load_conf_from_file(conf_file_path, conf=__conf__):
"ResourceDisk.EnableSwapEncryption": False,
"AutoUpdate.Enabled": True,
"EnableOverProvisioning": True,
"GAUpdates.Enabled": True,
#
# "Debug" options are experimental and may be removed in later
# versions of the Agent.
#
"Debug.CgroupLogMetrics": False,
"Debug.CgroupDisableOnProcessCheckFailure": True,
"Debug.CgroupDisableOnQuotaCheckFailure": True,
"Debug.DownloadNewAgents": True,
"Debug.EnableAgentMemoryUsageCheck": False,
"Debug.EnableFastTrack": True,
"Debug.EnableGAVersioning": False
"Debug.EnableGAVersioning": True
}


Expand Down Expand Up @@ -503,12 +503,15 @@ def get_monitor_network_configuration_changes(conf=__conf__):
return conf.get_switch("Monitor.NetworkConfigurationChanges", False)


def get_ga_updates_enabled(conf=__conf__):
def get_download_new_agents(conf=__conf__):
"""
If True, the agent go through update logic to look for new agents otherwise it will stop agent updates.
NOTE: This option is needed in e2e tests to control agent updates.
If True, the agent go through update logic to look for new agents to download otherwise it will stop agent updates.
NOTE: AutoUpdate.Enabled controls whether the Agent downloads new update and also whether any downloaded updates are started or not, while DownloadNewAgents controls only the former.
AutoUpdate.Enabled == false -> Agent preinstalled on the image will process extensions and will not update (regardless of DownloadNewAgents flag)
AutoUpdate.Enabled == true and DownloadNewAgents == true, any update already downloaded will be started, and agent look for future updates
AutoUpdate.Enabled == true and DownloadNewAgents == false, any update already downloaded will be started, but the agent will not look for future updates
"""
return conf.get_switch("GAUpdates.Enabled", True)
return conf.get_switch("Debug.DownloadNewAgents", True)


def get_cgroup_check_period(conf=__conf__):
Expand Down Expand Up @@ -637,7 +640,7 @@ def get_normal_upgrade_frequency(conf=__conf__):

def get_enable_ga_versioning(conf=__conf__):
"""
If True, the agent uses GA Versioning for auto-updating the agent vs automatically auto-updating to the highest version.
If True, the agent looks for rsm updates(checking requested version in GS) otherwise it will fall back to self-update and finds the highest version from PIR.
NOTE: This option is experimental and may be removed in later versions of the Agent.
"""
return conf.get_switch("Debug.EnableGAVersioning", True)
Expand Down
16 changes: 13 additions & 3 deletions azurelinuxagent/common/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import sys

import azurelinuxagent.common.conf as conf
from azurelinuxagent.common import logger
import azurelinuxagent.common.utils.shellutil as shellutil
from azurelinuxagent.common.utils.flexible_version import FlexibleVersion
from azurelinuxagent.common.future import ustr, get_linux_distribution
Expand Down Expand Up @@ -48,12 +49,21 @@ def get_daemon_version():
The value indicates the version of the daemon that started the current agent process or, if the current
process is the daemon, the version of the current process.
If the variable is not set (because the agent is < 2.2.53, or the process was not started by the daemon and
the process is not the daemon itself) the function returns "0.0.0.0"
the process is not the daemon itself) the function returns version of agent which started by the python
"""
if __DAEMON_VERSION_ENV_VARIABLE in os.environ:
return FlexibleVersion(os.environ[__DAEMON_VERSION_ENV_VARIABLE])
return FlexibleVersion("0.0.0.0")

else:
# The agent process which execute the extensions can have different version(after upgrades) and importing version from that process may provide wrong version for daemon.
# so launching new process with sys.executable python provides the correct version for daemon which preinstalled in the image.
try:
cmd = ["{0}".format(sys.executable), "-c", "\'from azurelinuxagent.common.version import AGENT_VERSION; print(AGENT_VERSION)\'"]
version = shellutil.run_command(cmd)
return FlexibleVersion(version)
except Exception as e: # Make the best effort to get the daemon version, but don't fail the update if we can't. So default to 2.2.53 as env variable is not set < 2.2.53
logger.warn("Failed to get the daemon version: {0}", ustr(e))
return FlexibleVersion("2.2.53")


def get_f5_platform():
"""
Expand Down
38 changes: 25 additions & 13 deletions azurelinuxagent/ga/agent_update_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from azurelinuxagent.common.future import ustr
from azurelinuxagent.common.logger import LogLevel
from azurelinuxagent.common.protocol.extensions_goal_state import GoalStateSource
from azurelinuxagent.common.protocol.restapi import VERSION_0, VMAgentUpdateStatuses, VMAgentUpdateStatus
from azurelinuxagent.common.protocol.restapi import VMAgentUpdateStatuses, VMAgentUpdateStatus
from azurelinuxagent.common.utils import fileutil, textutil
from azurelinuxagent.common.utils.flexible_version import FlexibleVersion
from azurelinuxagent.common.version import get_daemon_version, CURRENT_VERSION, AGENT_NAME, AGENT_DIR_PATTERN
Expand Down Expand Up @@ -37,6 +37,7 @@ def __init__(self):
self.last_attempted_requested_version_update_time = datetime.datetime.min
self.last_attempted_hotfix_update_time = datetime.datetime.min
self.last_attempted_normal_update_time = datetime.datetime.min
self.last_attempted_manifest_download_time = datetime.datetime.min


class AgentUpdateHandler(object):
Expand Down Expand Up @@ -86,6 +87,23 @@ def __update_last_attempt_update_times(self):
else:
self.update_state.last_attempted_normal_update_time = now
self.update_state.last_attempted_hotfix_update_time = now
self.update_state.last_attempted_manifest_download_time = now

def __should_agent_attempt_manifest_download(self):
"""
The agent should attempt to download the manifest if
the agent has not attempted to download the manifest in the last 1 hour
"""
now = datetime.datetime.now()

if self.update_state.last_attempted_manifest_download_time != datetime.datetime.min:
next_attempt_time = self.update_state.last_attempted_manifest_download_time + datetime.timedelta(seconds=conf.get_autoupdate_frequency())
else:
next_attempt_time = now

if next_attempt_time > now:
return False
return True

@staticmethod
def __get_agent_upgrade_type(requested_version):
Expand Down Expand Up @@ -231,7 +249,7 @@ def __proceed_with_update(self, requested_version):
# In case of an upgrade, we don't need to exclude anything as the daemon will automatically
# start the next available highest version which would be the target version
prefix = "upgrade"
raise AgentUpgradeExitException("Agent update found, Exiting current process to {0} to the new Agent version {1}".format(prefix, requested_version))
raise AgentUpgradeExitException("Agent update found, exiting current process to {0} to the new Agent version {1}".format(prefix, requested_version))

@staticmethod
def __get_available_agents_on_disk():
Expand All @@ -243,15 +261,6 @@ def __get_all_agents_on_disk():
path = os.path.join(conf.get_lib_dir(), "{0}-*".format(AGENT_NAME))
return [GuestAgent.from_installed_agent(path=agent_dir) for agent_dir in glob.iglob(path) if os.path.isdir(agent_dir)]

@staticmethod
def __get_daemon_version_for_update():
daemon_version = get_daemon_version()
if daemon_version != FlexibleVersion(VERSION_0):
return daemon_version
# We return 0.0.0.0 if daemon version is not specified. In that case,
# use the min version as 2.2.53 as we started setting the daemon version starting 2.2.53.
return FlexibleVersion("2.2.53")

@staticmethod
def __log_event(level, msg, success=True):
if level == LogLevel.INFO:
Expand All @@ -265,7 +274,7 @@ def __log_event(level, msg, success=True):
def run(self, goal_state):
try:
# Ignore new agents if update is disabled. The latter flag only used in e2e tests.
if not self._autoupdate_enabled or not conf.get_ga_updates_enabled():
if not self._autoupdate_enabled or not conf.get_download_new_agents():
return

self._gs_id = goal_state.extensions_goal_state.id
Expand All @@ -274,6 +283,9 @@ def run(self, goal_state):
agent_manifest = None # This is to make sure fetch agent manifest once per update
warn_msg = ""
if requested_version is None:
# Do not proceed with update if self-update needs to download the manifest again with in an hour
if not self.__should_agent_attempt_manifest_download():
return
if conf.get_enable_ga_versioning(): # log the warning only when ga versioning is enabled
warn_msg = "Missing requested version in agent family: {0} for incarnation: {1}, fallback to largest version update".format(self._ga_family, self._gs_id)
GAUpdateReportState.report_error_msg = warn_msg
Expand All @@ -299,7 +311,7 @@ def run(self, goal_state):
self.__log_event(LogLevel.WARNING, warn_msg)

try:
daemon_version = self.__get_daemon_version_for_update()
daemon_version = get_daemon_version()
if requested_version < daemon_version:
# Don't process the update if the requested version is less than daemon version,
# as historically we don't support downgrades below daemon versions. So daemon will not pickup that requested version rather start with
Expand Down
11 changes: 6 additions & 5 deletions tests/common/test_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,12 @@ def test_get_daemon_version_should_return_the_version_that_was_previously_set(se
finally:
os.environ.pop(DAEMON_VERSION_ENV_VARIABLE)

def test_get_daemon_version_should_return_zero_when_the_version_has_not_been_set(self):
self.assertEqual(
FlexibleVersion("0.0.0.0"), get_daemon_version(),
"The daemon version should not be defined. Environment={0}".format(os.environ)
)
def test_get_daemon_version_from_fallback_when_the_version_has_not_been_set(self):
with patch("azurelinuxagent.common.utils.shellutil.run_command", return_value=FlexibleVersion("2.2.53")):
self.assertEqual(
FlexibleVersion("2.2.53"), get_daemon_version(),
"The daemon version should not be defined. Environment={0}".format(os.environ)
)


class TestCurrentAgentName(AgentTestCase):
Expand Down
Loading

0 comments on commit c5809cb

Please sign in to comment.