Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 2 additions & 2 deletions .github/workflows/mvsce.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ jobs:
docker run -d --rm --name mvs -p 8080:8080 -p 2121:2121 "$IMAGE"
start=$(date +%s)
for i in $(seq 1 180); do
v=$(curl -s -u IBMUSER:SYS1 'http://localhost:8080/zosmf/test?fn=version' || true)
case "$v" in *'"version"'*) break ;; esac
v=$(curl -s -u IBMUSER:SYS1 'http://localhost:8080/zosmf/info' || true)
case "$v" in *'"zosmf_full_version"'*) break ;; esac
if [ "$(docker inspect -f '{{.State.Status}}' mvs 2>/dev/null)" != running ]; then
echo "container stopped"; exit 1
fi
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ test-mvsce:
$(REGISTRY)/mvsce:$(TAG)
@echo "Waiting for MVS IPL and HTTPD..."
@rc=1; for i in $$(seq 1 60); do \
if curl -sf -u IBMUSER:SYS1 'http://localhost:8080/zosmf/test?fn=version'; then rc=0; break; fi; \
if curl -sf -u IBMUSER:SYS1 'http://localhost:8080/zosmf/info'; then rc=0; break; fi; \
sleep 5; \
done; \
[ $$rc -eq 0 ] || docker logs --tail 50 mvsce-test; \
Expand Down
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ docker run -d --rm --name mvs --network mvs-net \
ghcr.io/mvslovers/mvsce

# The mvsMF API is now reachable at http://mvs:8080 from within mvs-dev
curl -u IBMUSER:SYS1 'http://mvs:8080/zosmf/test?fn=version'
curl -u IBMUSER:SYS1 'http://mvs:8080/zosmf/info'
```

Set `MVSMF_HOST=mvs` and `MVSMF_PORT=8080` in your project's `.env` file.
Expand Down Expand Up @@ -289,7 +289,7 @@ image. The link `mvsce-builder/mvsce-target` is gone. Use
| [Hercules](https://github.com/SDL-Hercules-390/hyperion) (SDL-Hyperion, `develop`) | `a742398074` (4.10.0.11783) | `/home/hercules/herctest/herc4x`, replacing MVS/CE's |
| [UFSD](https://github.com/mvslovers/ufsd) | 1.4.0 | `MVSLOVER.UFSD.LOADLIB` |
| [HTTPD](https://github.com/mvslovers/httpd) | 4.5.1 | `HTTPD.LINKLIB` |
| [mvsMF](https://github.com/mvslovers/mvsmf) | 1.3.0 | `HTTPD.LINKLIB` |
| [mvsMF](https://github.com/mvslovers/mvsmf) | 1.4.1 | `HTTPD.LINKLIB` |
| [FTPD](https://github.com/mvslovers/ftpd) | 1.2.0 | `MVSLOVER.FTPD.LOADLIB` |
| [RAKF](https://github.com/MVS-sysgen/RAKF) | 2.0.0 (TK5 Update 6), replacing the older RAKF of the base image | `SYS1.LPALIB`, `SYS1.LINKLIB`, SMP4 FUNCTION `TRKF200` |

Expand Down Expand Up @@ -380,12 +380,19 @@ only:
other user's; it fails if either of the two is missing,
- adds `S UFSD` / `S HTTPD` / `S FTPD` to `SYS1.PARMLIB(COMMND00)`.

**No JESSPOOL profile is defined.** mvsMF 1.4.0 shows a user only its own
jobs unless a profile of the RAKF class `JESSPOOL` says otherwise, and the
image leaves the class empty. The FTPD and mvsMF suites that test the class
expect that: FTPD's test 18 stops on any `JESSPOOL` line in `PROFILES` and
creates its own profiles on a clean container.

It checks RAKF by content, not by return code, and **fails unless** the
installed `ICHSFR00` has the text `UNDEFINED CLASS` / `RAKF0012` and the
class descriptor table in `ICHSEC00` has the entry `JESSPOOL`, and the same
two are found in the storage of the CLPA-IPLed system. It then starts all
three servers and **fails unless** the `UFSD000I`/`HTTPD000I`/
`FTPD000I` banners and `/zosmf/test?fn=version` report the pinned versions,
`FTPD000I` banners and `/zosmf/info` (`zosmf_full_version`) report the pinned versions,
`/zosmf/restconsoles/v1/log` answers 401 without a login and 200 for `IBMUSER`,
neither server logs `RAKF0004`, `HTTPD004W`, `FTPD004W`, `HTTPD012E` or
`APF SETUP FAILED`, HTTPD logs `HTTPD002I AUTHORIZED BY`, FTPD
`FTPD004I STC IDENTITY SET TO FTPD/USER`, `FTPD001I READY` follows, an FTP
Expand Down Expand Up @@ -413,11 +420,11 @@ docker run -d --rm --name mvs-build \
ghcr.io/mvslovers/mvsce

# Wait for MVS to IPL and HTTPD to come up, then check the mvsMF level
curl -u IBMUSER:SYS1 'http://localhost:8080/zosmf/test?fn=version'
curl -u IBMUSER:SYS1 'http://localhost:8080/zosmf/info'
```

mvsMF answers before TSO is up: on an idle 4-CPU host the authenticated
`fn=version` returned 200 about 2 s after `docker run`, and `IKT005I TCAS IS
`/zosmf/info` returned 200 about 2 s after `docker run`, and `IKT005I TCAS IS
INITIALIZED` followed about 1.5 s later. Wait for each separately.
`/zosmf/info` answers 401 without credentials, so a readiness probe has to
authenticate.
Expand Down
2 changes: 1 addition & 1 deletion mvsce/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ ARG HERCULES_REF
ARG HERCULES_REPO
ARG UFSD_VERSION=1.4.0
ARG HTTPD_VERSION=4.5.1
ARG MVSMF_VERSION=1.3.0
ARG MVSMF_VERSION=1.4.1
ARG FTPD_VERSION=1.2.0
ARG RAKF_VERSION=2.0.0
# TK5INST.zip of the RAKF release: trkf200.xmi, the TK5 Update 6 install
Expand Down
4 changes: 2 additions & 2 deletions mvsce/mvsce-target
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
#
# Every instance carries the label io.mvslovers.target=NAME and goes away
# completely when it stops (Docker: --rm with its anonymous volumes).
# `up` returns once the authenticated mvsMF fn=version answers; it does not
# `up` returns once the authenticated mvsMF /zosmf/info answers; it does not
# wait for TSO or FTP (see the README for when those are ready).
#
# Environment: MVSCE_TARGET_HOST (= --host), MVSCE_TARGET_RUNTIME,
Expand Down Expand Up @@ -501,7 +501,7 @@ start_once() {
if [ -n "$addr" ] && [ -n "$port" ]; then
code=$(curl -s -m 5 -o /dev/null -w '%{http_code}' \
-u "$MVS_USER:$MVS_PASS" \
"http://$addr:$port/zosmf/test?fn=version" || true)
"http://$addr:$port/zosmf/info" || true)
fi
[ "$code" = 200 ] && break
state=$(rt_state "$c")
Expand Down
42 changes: 35 additions & 7 deletions mvsce/setup_mvsce.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@
FTPD_VERSION, no RAKF0004 / HTTPD004W / FTPD004W for either server,
no HTTPD012E and no APF SETUP FAILED, FTPD004I,
FTPD001I READY, an FTP login, FTPAUTH refusing the FTPD user, and
/zosmf/test?fn=version against MVSMF_VERSION.
/zosmf/info zosmf_full_version against MVSMF_VERSION (a release has no
/zosmf/test), and the console route
/zosmf/restconsoles/v1/log (401 without a login, 200 for IBMUSER).
A build that installed nothing therefore fails instead of publishing
the previous level.
10. Adds P FTPD / P HTTPD / P UFSD to MVS/CE's SCRIPTS/SHUTDOWN.RC, purges
Expand All @@ -86,6 +88,7 @@
import subprocess
import sys
import time
import urllib.error
import urllib.request
import zipfile

Expand Down Expand Up @@ -1038,21 +1041,45 @@ def check_ftpd(herc, expected, since, ftpd_pw):


def check_mvsmf(herc, expected):
log('Checking the running mvsMF level (/zosmf/test?fn=version)...')
log('Checking the running mvsMF level (/zosmf/info)...')
if not wait_for_port(HTTP_PORT, timeout=60):
fail(herc, f'HTTPD is not listening on port {HTTP_PORT}')
req = urllib.request.Request(
f'http://127.0.0.1:{HTTP_PORT}/zosmf/test?fn=version')
req = urllib.request.Request(f'http://127.0.0.1:{HTTP_PORT}/zosmf/info')
cred = base64.b64encode(f'{USER}:{PASSWORD}'.encode()).decode()
req.add_header('Authorization', f'Basic {cred}')
try:
with urllib.request.urlopen(req, timeout=30) as resp:
info = json.loads(resp.read().decode())
except Exception as e: # noqa: BLE001 - any failure fails the build
fail(herc, f'mvsMF version probe failed: {e}')
log(f' mvsMF {info.get("version")} build {info.get("build")}')
if expected and info.get('version', '').upper() != expected.upper():
fail(herc, f'mvsMF reports {info.get("version")}, expected {expected}')
version = info.get('zosmf_full_version', '')
log(f' mvsMF {version}')
if version.endswith('-dev'):
fail(herc, f'mvsMF {version} is a development build, not a release')
if expected and version.upper() != expected.upper():
fail(herc, f'mvsMF reports {version}, expected {expected}')


def check_console_route(herc):
log('Checking the console route (/zosmf/restconsoles/v1/log)...')
url = f'http://127.0.0.1:{HTTP_PORT}/zosmf/restconsoles/v1/log'
try:
urllib.request.urlopen(url, timeout=30)
fail(herc, 'console route answers without a login')
except urllib.error.HTTPError as e:
if e.code != 401:
fail(herc, f'console route without a login answers {e.code}, expected 401')
req = urllib.request.Request(url)
cred = base64.b64encode(f'{USER}:{PASSWORD}'.encode()).decode()
req.add_header('Authorization', f'Basic {cred}')
try:
with urllib.request.urlopen(req, timeout=30) as resp:
code = resp.status
except urllib.error.HTTPError as e:
code = e.code
if code != 200:
fail(herc, f'console route with a login answers {code}, expected 200')
log(' 401 without a login, 200 for IBMUSER')


SHUTDOWN_RC = '/MVSCE/SCRIPTS/SHUTDOWN.RC'
Expand Down Expand Up @@ -1221,6 +1248,7 @@ def main():
start_stc(herc, 'HTTPD', 'HTTPD000I', os.environ.get('HTTPD_VERSION'))
check_identity(herc, 'HTTPD', since, 'HTTPD001I')
check_mvsmf(herc, os.environ.get('MVSMF_VERSION'))
check_console_route(herc)
since = len(read_log())
start_stc(herc, 'FTPD', 'FTPD000I', os.environ.get('FTPD_VERSION'))
check_ftpd(herc, os.environ.get('FTPD_VERSION'), since, ftpd_pw)
Expand Down
Loading