The default way to add a Management Agent in Enterprise Manager is the Add Host Targets Wizard: point the console at a host, hand it credentials, and let the OMS push the software out. It works often enough that most of us never learn what it is actually doing underneath. Then you hit a host where it cannot work, and you find out.

The constraint that started it

target01.example.com has /tmp mounted noexec. That is a reasonable hardening choice and a common one, and it rules out the default push deployment outright, because Oracle’s push tooling stages files under /tmp on the remote host and then executes them from there. No execute permission on the staging filesystem, no deployment.

There is a documented workaround. The Add Host Targets Wizard accepts a SCRATCHPATH additional parameter that redirects the installer’s staging location somewhere other than /tmp. On paper that is the whole answer.

One callout before you lean on it: there is a known Oracle bug in which SCRATCHPATH is silently ignored during Gold Image agent updates specifically. Silently, meaning the deployment proceeds and stages to /tmp anyway. If you are relying on SCRATCHPATH to get around noexec, confirm you are running a fresh push and not a Gold Image operation, because the parameter you think is protecting you may not be doing anything at all in that path.

The push failure I never explained

On a second target, target02.example.com, push deployment failed during Remote Prerequisite Checks. The visible error on the OMS side was:

unzip: cannot find or open [archive].zip

That one is a symptom, not a cause. Tracing it back showed the archive was never created on the remote side in the first place. The OMS was unzipping something that had never arrived, and the unzip failure was the first point at which anybody noticed.

The deploy log had its own opinion about why. Its built-in diagnostic logic flagged a privilege problem on the target:

User oracle does not have sudo privileges on host target02.example.com

That reads like an answer. It is specific, it names the user, it names the host, and it points at a mechanism that would plausibly break remote staging. It was also wrong, or at least not the discriminating factor. The identical unzip error and the identical sudo-check output appeared in the log of a different target host that went on to deploy successfully. Same message, same check, opposite outcome.

So the root cause was never conclusively identified. I am stating that plainly rather than reverse-engineering a tidy explanation, because the honest finding here is the methodological one: a log’s own self-diagnosis is a hypothesis, not a verdict. It is generated by a heuristic somebody wrote, running against a situation that heuristic may not cover. The only cheap way to test it is to pull the same log from a known-good run and see whether the incriminating line shows up there too. In this case it did, which cost the sudo theory its entire value as evidence.

At that point the decision was not technical, it was about where to spend time. An intermittent failure with no isolated cause, on a mechanism I already knew was blocked on the primary target by noexec, was not worth chasing further when a fully supported silent install path was available. Push deployment was abandoned.

Switching to the silent path

The alternative is to stop pushing and start pulling: get the agent software onto the target host directly, then run the installer locally as the oracle user. That sidesteps the push mechanism entirely, along with its dependency on remote staging under /tmp. The OMS-side half is emcli get_agentimage, which produces a platform-specific agent image zip. The target-side half is agentDeploy.sh, which ships inside that zip.

It works. Getting there took two invocation gotchas and one genuinely odd failure.

Gotcha A: two different credentials that are easy to conflate

AgentPull.sh, used in the variant where you pull the software down from the OMS over curl rather than staging it with emcli get_agentimage, requires LOGIN_USER and LOGIN_PASSWORD in the response file. These are real EM console credentials, and they exist to authenticate the software download itself. Leave LOGIN_USER out and you get:

ERROR: Invalid invocation. Enterprise Manager Login Username is empty.

This is not the same credential as AGENT_REGISTRATION_PASSWORD, and conflating them is easy because both are EM secrets that live in the same response file. They are used at different times by different components for different purposes. LOGIN_USER and LOGIN_PASSWORD authenticate you to the OMS so it will hand over the software. AGENT_REGISTRATION_PASSWORD is what the installed agent presents to the OMS afterward, during registration, to prove it is allowed to join. One gets you the bits, the other gets the agent accepted once the bits are installed.

Gotcha B: AGENT_BASE_DIR cannot live in the response file

OMS_HOST belongs in the response file. EM_UPLOAD_PORT belongs in the response file. AGENT_REGISTRATION_PASSWORD, AGENT_PORT, and the rest of the usual set all belong in the response file. AGENT_BASE_DIR does not, and putting it there does not work at all. It has to be passed on the command line:

ERROR: Invalid invocation. AGENT_BASE_DIR is mandatory.

The error is unhelpful in a specific way. “Mandatory” implies “you did not supply it,” which sends you to look at a response file where you can plainly see it sitting there. The accurate reading is “mandatory on the command line,” and the value in the response file is simply not consulted.

The invocation that agentcore.bin rejected

Then came the part that actually cost time.

With a minimal, hand-typed response file and ORACLE_HOSTNAME passed on the command line, agentDeploy.sh built its internal call to agentcore.bin, the prerequisite checker, and the call was malformed. OMS_HOST and the upload port each appeared three times in the generated command: once correctly, attached to its proper flag, and twice more as bare unflagged tokens trailing the end of the command line. agentcore.bin refused it:

Invalid argument(s): [host],[host],[port],[port]

Four rejected tokens, which is exactly the two spurious copies each of the host and the port. No log file was written anywhere, because the failure happened before the prerequisite checker started doing any work. There was nothing to read except the command line itself.

The obvious hypothesis is that the duplication is the bug. It is not, or at least not by itself. Here is the red herring worth naming: duplication in these auto-generated Oracle installer command lines is sometimes normal and entirely non-fatal. An older, confirmed-working EM 13c deployment reference I had on hand showed the same pattern, with AGENT_BASE_DIR=… AGENT_BASE_DIR=… appearing back to back in the generated invocation, and that deployment installed successfully. The generator emits repeated values as a matter of course and the downstream binaries usually tolerate it.

So the presence of duplication was not the tell. Something about this particular invocation was, specifically the bare unflagged trailing form, which agentcore.bin has no way to interpret.

What actually fixed it

The useful move was to stop staring at the broken invocation and start diffing it against the working reference. Two real differences fell out.

First, the working reference used the full agent.rsp template that ships inside the downloaded agent software, edited in place, rather than a minimal response file typed by hand. That template is substantial. It carries a large number of keys, most of them blank or defaulted, and evidently the installer’s command-line generator expects to be reading from it rather than from a stripped-down file containing only the handful of values a human considers interesting.

Second, ORACLE_HOSTNAME lived inside that response file, not on the command line.

Matching both collapsed the generated invocation down to something agentcore.bin accepted, and the deployment ran clean. The command line at that point was two arguments, AGENT_BASE_DIR and RESPONSE_FILE, with every other value including ORACLE_HOSTNAME set inside the file.

I did not isolate which of the two changes was load-bearing, or why the generator mangles the command line under the other configuration. Both were applied together, the deployment succeeded, and the environment needed the agent more than I needed the answer. The operational rule I took from it is narrow but reliable: use the shipped agent.rsp template as your starting point and keep the command line to AGENT_BASE_DIR and RESPONSE_FILE. Push values onto the command line and you are exercising a code path in the installer that is evidently less well travelled than the one Oracle’s own documentation examples use.

One environmental factor: fapolicyd

On hardened OL8 and OL9 with fapolicyd running, stop it before the deploy and start it afterward. fapolicyd is execution allowlisting, and it can block execve() calls during the install with no SELinux audit trail to point at, just a plain EPERM. There is no AVC denial to grep for, because SELinux is not what denied it.

This is not specific to agent deployment. It is a known pattern in this environment and has shown up before during unrelated Oracle Home relinking work. It is worth listing in the procedure anyway, because the failure mode it produces is quiet and the diagnosis is not obvious the first time you meet it.

The procedure that worked

From the OMS server, as oracle:

export OMS_HOME=<oms Oracle home path>
export PATH=$OMS_HOME/bin:$PATH

emcli login -username=sysman
emcli sync
emcli get_supported_platforms

mkdir /tmp/soft
emcli get_agentimage -destination=/tmp/soft -platform="Linux x86-64" -version=24.1.0.0.0

Transfer the resulting agent image zip to the target host over NFS or scp.

On the target host, as root:

systemctl stop fapolicyd

As oracle:

mkdir /tmp/agtImg
unzip -q <agentimage>.zip -d /tmp/agtImg
cd /tmp/agtImg/
vi agent.rsp
./agentDeploy.sh AGENT_BASE_DIR=<agent base dir> RESPONSE_FILE=/tmp/agtImg/agent.rsp

Edit the shipped agent.rsp template in place. Set OMS_HOST, EM_UPLOAD_PORT, AGENT_REGISTRATION_PASSWORD, AGENT_PORT, and ORACLE_HOSTNAME there. Do not move any of them to the command line, ORACLE_HOSTNAME included.

Then as root:

<agent base dir>/agent_24.1.0.0.0/root.sh
systemctl start fapolicyd

Note that the agent image is unpacked under /tmp here on a host where that is fine. On the noexec host, unpack somewhere that permits execution. The whole point of this path is that you control where the software lands, which is precisely what the push method takes away from you.

If target promotion fails at the end

One tail-end failure is worth knowing about in advance, though it does not always happen. A deployment of this kind can complete the software install successfully and then fail at the very last step with:

Promoting agent and its related targets to Management Service failed

The agent is installed. What did not finish is the registration and target promotion handshake with the OMS. If you see it, run the following on the target host:

emctl start agent
emctl config agent addinternaltargets

That starts the agent and registers its internal targets with the Management Service, which is the work the failed promotion step was supposed to do.

What I would tell the next person

Two things carried over from this one.

A log that diagnoses itself is offering you a theory. Before you spend an afternoon on it, pull the same log from a run that succeeded and check whether the incriminating line is sitting in there too. That check is cheap and it killed the sudo theory here in about five minutes.

And when an Oracle installer generates a command line you did not write and that command line is broken, the fastest route is usually not to understand the generator. It is to find a configuration known to produce a working invocation and converge on it. That does leave you without a root cause, which is uncomfortable. It also gets the agent installed.