Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Agentless #1289

Merged
merged 7 commits into from
Aug 8, 2018
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ A configuration file (/etc/waagent.conf) controls the actions of waagent. Blank
A sample configuration file is shown below:

```yml
Extensions.Enabled=y
Provisioning.Enabled=y
Provisioning.UseCloudInit=n
Provisioning.DeleteRootPassword=n
Expand Down Expand Up @@ -213,6 +214,18 @@ may be used for some string type configuration entries as detailed below.

### Configuration File Options

#### __Extensions.Enabled__

_Type: Boolean_
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add this to the various waagent.conf versions in the tree. I think people are more likely to read that file than they are the web site.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, updated

_Default: y_

This allows the user to enable or disable the extension handling functionality in the
agent. Valid values are "y" or "n". If extension handling is disabled, the goal state
will still be processed and VM status is still reported, but only every 5 minutes.
Extension config within the goal state will be ignored. Note that functionality such
as password reset, ssh key updates and backups depend on extensions. Only disable this
if you do not need extensions at all.

#### __Provisioning.Enabled__

_Type: Boolean_
Expand Down
123 changes: 79 additions & 44 deletions azurelinuxagent/common/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import azurelinuxagent.common.utils.fileutil as fileutil
from azurelinuxagent.common.exception import AgentConfigError

DISABLE_AGENT_FILE = 'disable_agent'


class ConfigurationProvider(object):
"""
Expand Down Expand Up @@ -85,57 +87,59 @@ def load_conf_from_file(conf_file_path, conf=__conf__):
raise AgentConfigError(("Failed to load conf file:{0}, {1}"
"").format(conf_file_path, err))


__SWITCH_OPTIONS__ = {
"OS.AllowHTTP" : False,
"OS.EnableFirewall" : False,
"OS.EnableFIPS" : False,
"OS.EnableRDMA" : False,
"OS.UpdateRdmaDriver" : False,
"OS.CheckRdmaDriver" : False,
"Logs.Verbose" : False,
"Provisioning.Enabled" : True,
"Provisioning.UseCloudInit" : False,
"Provisioning.AllowResetSysUser" : False,
"Provisioning.RegenerateSshHostKeyPair" : False,
"Provisioning.DeleteRootPassword" : False,
"Provisioning.DecodeCustomData" : False,
"Provisioning.ExecuteCustomData" : False,
"Provisioning.MonitorHostName" : False,
"DetectScvmmEnv" : False,
"ResourceDisk.Format" : False,
"DetectScvmmEnv" : False,
"ResourceDisk.Format" : False,
"ResourceDisk.EnableSwap" : False,
"AutoUpdate.Enabled" : True,
"EnableOverProvisioning" : True
"OS.AllowHTTP": False,
"OS.EnableFirewall": False,
"OS.EnableFIPS": False,
"OS.EnableRDMA": False,
"OS.UpdateRdmaDriver": False,
"OS.CheckRdmaDriver": False,
"Logs.Verbose": False,
"Extensions.Enabled": True,
"Provisioning.Enabled": True,
"Provisioning.UseCloudInit": False,
"Provisioning.AllowResetSysUser": False,
"Provisioning.RegenerateSshHostKeyPair": False,
"Provisioning.DeleteRootPassword": False,
"Provisioning.DecodeCustomData": False,
"Provisioning.ExecuteCustomData": False,
"Provisioning.MonitorHostName": False,
"DetectScvmmEnv": False,
"ResourceDisk.Format": False,
"ResourceDisk.EnableSwap": False,
"AutoUpdate.Enabled": True,
"EnableOverProvisioning": True
}


__STRING_OPTIONS__ = {
"Lib.Dir" : "/var/lib/waagent",
"DVD.MountPoint" : "/mnt/cdrom/secure",
"Pid.File" : "/var/run/waagent.pid",
"Extension.LogDir" : "/var/log/azure",
"OS.OpensslPath" : "/usr/bin/openssl",
"OS.SshDir" : "/etc/ssh",
"OS.HomeDir" : "/home",
"OS.PasswordPath" : "/etc/shadow",
"OS.SudoersDir" : "/etc/sudoers.d",
"OS.RootDeviceScsiTimeout" : None,
"Provisioning.SshHostKeyPairType" : "rsa",
"Provisioning.PasswordCryptId" : "6",
"HttpProxy.Host" : None,
"ResourceDisk.MountPoint" : "/mnt/resource",
"ResourceDisk.MountOptions" : None,
"ResourceDisk.Filesystem" : "ext3",
"AutoUpdate.GAFamily" : "Prod"
"Lib.Dir": "/var/lib/waagent",
"DVD.MountPoint": "/mnt/cdrom/secure",
"Pid.File": "/var/run/waagent.pid",
"Extension.LogDir": "/var/log/azure",
"OS.OpensslPath": "/usr/bin/openssl",
"OS.SshDir": "/etc/ssh",
"OS.HomeDir": "/home",
"OS.PasswordPath": "/etc/shadow",
"OS.SudoersDir": "/etc/sudoers.d",
"OS.RootDeviceScsiTimeout": None,
"Provisioning.SshHostKeyPairType": "rsa",
"Provisioning.PasswordCryptId": "6",
"HttpProxy.Host": None,
"ResourceDisk.MountPoint": "/mnt/resource",
"ResourceDisk.MountOptions": None,
"ResourceDisk.Filesystem": "ext3",
"AutoUpdate.GAFamily": "Prod"
}


__INTEGER_OPTIONS__ = {
"OS.SshClientAliveInterval" : 180,
"Provisioning.PasswordCryptSaltLength" : 10,
"HttpProxy.Port" : None,
"ResourceDisk.SwapSizeMB" : 0,
"Autoupdate.Frequency" : 3600
"OS.SshClientAliveInterval": 180,
"Provisioning.PasswordCryptSaltLength": 10,
"HttpProxy.Port": None,
"ResourceDisk.SwapSizeMB": 0,
"Autoupdate.Frequency": 3600
}


Expand All @@ -152,17 +156,21 @@ def get_configuration(conf=__conf__):

return options


def enable_firewall(conf=__conf__):
return conf.get_switch("OS.EnableFirewall", False)


def enable_rdma(conf=__conf__):
return conf.get_switch("OS.EnableRDMA", False) or \
conf.get_switch("OS.UpdateRdmaDriver", False) or \
conf.get_switch("OS.CheckRdmaDriver", False)


def enable_rdma_update(conf=__conf__):
return conf.get_switch("OS.UpdateRdmaDriver", False)


def get_logs_verbose(conf=__conf__):
return conf.get_switch("Logs.Verbose", False)

Expand All @@ -186,44 +194,57 @@ def get_agent_pid_file_path(conf=__conf__):
def get_ext_log_dir(conf=__conf__):
return conf.get("Extension.LogDir", "/var/log/azure")


def get_fips_enabled(conf=__conf__):
return conf.get_switch("OS.EnableFIPS", False)


def get_openssl_cmd(conf=__conf__):
return conf.get("OS.OpensslPath", "/usr/bin/openssl")


def get_ssh_client_alive_interval(conf=__conf__):
return conf.get("OS.SshClientAliveInterval", 180)


def get_ssh_dir(conf=__conf__):
return conf.get("OS.SshDir", "/etc/ssh")


def get_home_dir(conf=__conf__):
return conf.get("OS.HomeDir", "/home")


def get_passwd_file_path(conf=__conf__):
return conf.get("OS.PasswordPath", "/etc/shadow")


def get_sudoers_dir(conf=__conf__):
return conf.get("OS.SudoersDir", "/etc/sudoers.d")


def get_sshd_conf_file_path(conf=__conf__):
return os.path.join(get_ssh_dir(conf), "sshd_config")


def get_ssh_key_glob(conf=__conf__):
return os.path.join(get_ssh_dir(conf), 'ssh_host_*key*')


def get_ssh_key_private_path(conf=__conf__):
return os.path.join(get_ssh_dir(conf),
'ssh_host_{0}_key'.format(get_ssh_host_keypair_type(conf)))


def get_ssh_key_public_path(conf=__conf__):
return os.path.join(get_ssh_dir(conf),
'ssh_host_{0}_key.pub'.format(get_ssh_host_keypair_type(conf)))


def get_root_device_scsi_timeout(conf=__conf__):
return conf.get("OS.RootDeviceScsiTimeout", None)


def get_ssh_host_keypair_type(conf=__conf__):
keypair_type = conf.get("Provisioning.SshHostKeyPairType", "rsa")
if keypair_type == "auto":
Expand All @@ -234,15 +255,23 @@ def get_ssh_host_keypair_type(conf=__conf__):
return "rsa"
return keypair_type


def get_ssh_host_keypair_mode(conf=__conf__):
return conf.get("Provisioning.SshHostKeyPairType", "rsa")


def get_provision_enabled(conf=__conf__):
return conf.get_switch("Provisioning.Enabled", True)


def get_extensions_enabled(conf=__conf__):
return conf.get_switch("Extensions.Enabled", True)


def get_provision_cloudinit(conf=__conf__):
return conf.get_switch("Provisioning.UseCloudInit", False)


def get_allow_reset_sys_user(conf=__conf__):
return conf.get_switch("Provisioning.AllowResetSysUser", False)

Expand Down Expand Up @@ -322,8 +351,14 @@ def get_autoupdate_enabled(conf=__conf__):
def get_autoupdate_frequency(conf=__conf__):
return conf.get_int("Autoupdate.Frequency", 3600)


def get_enable_overprovisioning(conf=__conf__):
return conf.get_switch("EnableOverProvisioning", True)


def get_allow_http(conf=__conf__):
return conf.get_switch("OS.AllowHTTP", False)


def get_disable_agent_file_path(conf=__conf__):
return os.path.join(get_lib_dir(conf), DISABLE_AGENT_FILE)
13 changes: 13 additions & 0 deletions azurelinuxagent/daemon/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ def check_pid(self):

fileutil.write_file(pid_file, ustr(os.getpid()))

def sleep_if_disabled(self):
agent_disabled_file_path = conf.get_disable_agent_file_path()
if os.path.exists(agent_disabled_file_path):
import threading
logger.warn("Disabling the guest agent by sleeping forever; "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no API to disable the agent, there's just a file on disk?

I assumed we would just stop the service, and no code would be running.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API is in CRP, exposed through ARM/SDK/CLI. Cloud-init will honor this flag by stopping/disabling the service, but for distros without cloud-init support, I believe this is the best we can do.

"to re-enable, remove {0} and restart"
.format(agent_disabled_file_path))
self.running = False
disable_event = threading.Event()
disable_event.wait()

def initialize_environment(self):
# Create lib dir
if not os.path.isdir(conf.get_lib_dir()):
Expand Down Expand Up @@ -149,5 +160,7 @@ def daemon(self, child_args=None):
else:
logger.info("RDMA capabilities are not enabled, skipping")

self.sleep_if_disabled()

while self.running:
self.update_handler.run_latest(child_args=child_args)
4 changes: 4 additions & 0 deletions azurelinuxagent/ga/exthandlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,10 @@ def cleanup_outdated_handlers(self):
logger.warn("Failed to remove extension package {0}: {1}".format(pkg, e.strerror))

def handle_ext_handlers(self, etag=None):
if not conf.get_extensions_enabled():
logger.verbose("Extension handling is disabled")
return

if self.ext_handlers.extHandlers is None or \
len(self.ext_handlers.extHandlers) == 0:
logger.verbose("No extension handler config found")
Expand Down
7 changes: 6 additions & 1 deletion azurelinuxagent/ga/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
MAX_FAILURE = 3 # Max failure allowed for agent before blacklisted

GOAL_STATE_INTERVAL = 3
GOAL_STATE_INTERVAL_DISABLED = 5 * 60

ORPHAN_WAIT_INTERVAL = 15 * 60

Expand Down Expand Up @@ -274,6 +275,10 @@ def run(self):
self._ensure_partition_assigned()
self._ensure_readonly_files()

goal_state_interval = GOAL_STATE_INTERVAL \
if conf.get_extensions_enabled() \
else GOAL_STATE_INTERVAL_DISABLED

while self.running:
if self._is_orphaned:
logger.info("Agent {0} is an orphan -- exiting",
Expand Down Expand Up @@ -320,7 +325,7 @@ def run(self):
duration=duration,
message="Incarnation {0}".format(exthandlers_handler.last_etag))

time.sleep(GOAL_STATE_INTERVAL)
time.sleep(goal_state_interval)

except Exception as e:
msg = u"Agent {0} failed with exception: {1}".format(CURRENT_AGENT, ustr(e))
Expand Down
5 changes: 1 addition & 4 deletions azurelinuxagent/pa/provision/cloudinit.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,7 @@ def wait_for_ovfenv(self, max_retry=1800, sleep_time=1):
if os.path.isfile(ovf_file_path):
try:
ovf_env = OvfEnv(fileutil.read_file(ovf_file_path))
self.report_event(message=ovf_env.provision_guest_agent,
is_success=True,
duration=0,
operation=WALAEventOperation.ProvisionGuestAgent)
self.handle_provision_guest_agent(ovf_env.provision_guest_agent)
return
except ProtocolError as pe:
raise ProvisionError("OVF xml could not be parsed "
Expand Down
20 changes: 15 additions & 5 deletions azurelinuxagent/pa/provision/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,14 @@ def run(self):
is_success=True,
duration=elapsed_milliseconds(utc_start))

self.report_event(message=ovf_env.provision_guest_agent,
is_success=True,
duration=0,
operation=WALAEventOperation.ProvisionGuestAgent)
self.handle_provision_guest_agent(ovf_env.provision_guest_agent)

self.report_ready(thumbprint)
logger.info("Provisioning complete")

except (ProtocolError, ProvisionError) as e:
self.report_not_ready("ProvisioningFailed", ustr(e))
self.report_event(ustr(e))
self.report_event(ustr(e), is_success=False)
logger.error("Provisioning failed: {0}", ustr(e))
return

Expand Down Expand Up @@ -205,6 +202,19 @@ def write_provisioned(self):
self.provisioned_file_path(),
get_osutil().get_instance_id())

@staticmethod
def write_agent_disabled():
logger.warn("Disabling guest agent in accordance with ovf-env.xml")
fileutil.write_file(conf.get_disable_agent_file_path(), '')

def handle_provision_guest_agent(self, provision_guest_agent):
self.report_event(message=provision_guest_agent,
is_success=True,
duration=0,
operation=WALAEventOperation.ProvisionGuestAgent)
if provision_guest_agent and provision_guest_agent.lower() == 'false':
self.write_agent_disabled()

def provision(self, ovfenv):
logger.info("Handle ovf-env.xml.")
try:
Expand Down
4 changes: 4 additions & 0 deletions config/alpine/waagent.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
# Enable instance creation
Provisioning.Enabled=y

# Enable extension handling. Do not disable this unless you do not need password reset,
# backup, monitoring, or any extension handling whatsoever.
Extensions.Enabled=y

# Rely on cloud-init to provision
Provisioning.UseCloudInit=n

Expand Down
4 changes: 4 additions & 0 deletions config/bigip/waagent.conf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ Role.TopologyConsumer=None
# Enable instance creation
Provisioning.Enabled=y

# Enable extension handling. Do not disable this unless you do not need password reset,
# backup, monitoring, or any extension handling whatsoever.
Extensions.Enabled=y

# Rely on cloud-init to provision
Provisioning.UseCloudInit=n

Expand Down
Loading