Skip to content

Commit b12df7e

Browse files
Merge pull request #110 from KeckObservatory/dev
v3.0.5
2 parents e1a17ff + 1993f94 commit b12df7e

3 files changed

Lines changed: 65 additions & 66 deletions

File tree

README.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,9 @@ The schedule is filled based on your remote observing request, but this is a man
4545
- Generate ssh public/private key pair **(do not set a passphrase)**
4646
```
4747
cd ~/.ssh
48-
ssh-keygen -t rsa -b 4096
48+
ssh-keygen -t ed25519
4949
```
5050
51-
- Make sure that the resulting key is an RSA key. The **private** key should have a first line which looks like `-----BEGIN RSA PRIVATE KEY-----` (it should not be an OPENSSH key). If you do get an OPENSSH key (we've seen this on macOS and Ubuntu Linux), try generating the key with the `-m PEM` option: `ssh-keygen -t rsa -b 4096 -m PEM`
52-
5351
- Upload your **public** key file at your [Observer Login Page](https://www2.keck.hawaii.edu/inst/PILogin/login.php). Click on "Manage Your Remote Observing SSH Key" and follow the instructions.
5452
5553
- After you have uploaded the key, note the "API key". This will be a long string of letters and numbers. You will need this key to connect (see the section below titled "Configure Keck Remote Observing Software").
@@ -112,7 +110,10 @@ Note: The examples below assume sudo/root installation for all users and were or
112110
- **For macOS**: Install a VNC viewer application if needed.
113111
- [Tiger VNC](https://tigervnc.org) has the advantage of supporting automatic window positioning, but does not support scaling, and can not enter and exit view only mode interactively.
114112
- Real VNC's [VNC Viewer](https://www.realvnc.com/en/connect/download/viewer/) does not support automatic window positioning, but allows window scaling for use on small or high resolution monitors. In addition, it supports changing modes both interactively and on the command line (e.g. scaling and the toggling of view only mode). Note: this is the free software, you do not need VNC Viewer Plus.
115-
- It is also possible to use the built in VNC viewer on macOS, but we have seen a few instances where the screen freezes and the client needs to be closed and reopened to get an up to date screen.
113+
- Both Tiger VNC and Real VNC have the viewers available for install via the macOS [Homebrew package manager](https://brew.sh). This provides the same software as is available from the download links above, but may be an easier install for users who already use homebrew.
114+
- To install Real VNC Viewer: `brew install vnc-viewer`
115+
- To install Tiger VNC Viewer: `brew install tigervnc-viewer`
116+
- It is also possible to use the built in VNC viewer on macOS. The example configuration file has an example setup for this in the "VNC Viewer Command" section for users who want to try it. Be aware, however, that we have seen a few instances where the screen freezes and the client needs to be closed and reopened to get an up to date screen, so if you see that problem, please try another VNC Viewer client.
116117
117118
**--> Important! <--** If you are using TigerVNC on either OS, in the `~/.vnc` directory, create a file named `default.tigervnc` with these two lines:
118119
```
@@ -286,6 +287,14 @@ A more extreme version would be to only keep one or two sessions open at a time
286287
287288
VNC does not carry sounds, so we have a separate system for playing instrument sounds such as "exposure complete" indicators on the remote machine. This system has several moving parts, so troubleshooting can be challenging. The vast majority of sound problems however are local to the users machine. To play a test sound, type the `p` command. This will play a local sound file (it will need to be downloaded on the first instance of this). If you can't hear this test sound (the quality is poor and scratchy, but it sounds like a doorbell), then check your local machine's volume settings and speaker configuration. You may also not have configured your local `aplay` instance properly.
288289
290+
## No Sounds on macOS
291+
292+
The Remote Observing software triggers sounds using one of several `soundplay` executables packaged with the software (in the `soundplayer/` subdirectory). This has not been compiled on macOS for ARM (for "Apple Silicon") and relies on Apple's Rosetta software to convert an `x86_64` executable to something which can execute on modern Apple hardware.
293+
294+
Normally the need to run the executable through Rosetta is detected automatically, but since we are calling the executable within a python program, it appears this is not happening. Thus, if you are not getting sounds and everything else appears to be working, what may be happening is that the executable is not getting routed through Rosetta to be translated for Apple Silicon.
295+
296+
The workaround for this is to manually call the executable once from the command line. This attaches the proper metadata to the executable and it will work properly from within python thereafter. This means one should navigate to the `soundplayer/` directory and call `./soundplay.darwin.x86_64` once. Ignore the errors, and `control-c` out immediately. After that, future connections to sounds via the Remote Observing software should run normally.
297+
289298
# Upgrading the Software
290299
291300
The software does a simple check to see if it is the latest released version. You can see a log line with this information on startup, or you can get the saem result using the `v` command.

keck_vnc_launcher.py

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626

2727
## Module vars
28-
__version__ = '3.0.4'
28+
__version__ = '3.0.5'
2929
supportEmail = 'remote-observing@keck.hawaii.edu'
3030
KRO_API = 'https://www3.keck.hawaii.edu/api/kroApi/'
3131
SESSION_NAMES = ('control0', 'control1', 'control2',
@@ -91,8 +91,8 @@ def create_parser():
9191
## add options
9292
parser.add_argument("-c", "--config", dest="config", type=str,
9393
help="Path to local configuration file.")
94-
# parser.add_argument("--vncserver", type=str,
95-
# help="Name of VNC server to connect to. Takes precedence over all.")
94+
parser.add_argument("--vncserver", type=str,
95+
help="Name of VNC server to connect to. Takes precedence over all.")
9696
parser.add_argument( '--vncports', nargs='+', type=str,
9797
help="Numerical list of VNC ports to connect to. Takes precedence over all.")
9898

@@ -136,11 +136,12 @@ def create_logger(args):
136136
return
137137

138138
#create log file and log dir if not exist
139+
log_path = Path(__file__).parent / 'logs'
139140
try:
140-
Path('logs/').mkdir(parents=True, exist_ok=True)
141+
log_path.mkdir(parents=True, exist_ok=True)
141142
except PermissionError as error:
142143
print(str(error))
143-
print(f"ERROR: Unable to create logger at logs/")
144+
print(f"ERROR: Unable to create logger at {log_path}")
144145
print("Make sure you have write access to this directory.\n")
145146
log.info("EXITING APP\n")
146147
sys.exit(1)
@@ -168,7 +169,7 @@ def create_logger(args):
168169
except:
169170
# Works with older pyhon versions (>=3.9)
170171
ymd = datetime.datetime.utcnow().strftime('%Y%m%d_%H%M%S')
171-
logFile = Path(f'logs/keck-remote-log-utc-{ymd}.txt')
172+
logFile = log_path / f'keck-remote-log-utc-{ymd}.txt'
172173
logFileHandler = logging.FileHandler(logFile)
173174
logFileHandler.setLevel(logging.DEBUG)
174175
logFileHandler.setFormatter(logFormat_with_time)
@@ -234,6 +235,7 @@ def __init__(self, server, username, ssh_pkey, remote_port, local_port,
234235
ssh_additional_kex=None,
235236
ssh_additional_hostkeyalgo=None,
236237
ssh_additional_keytypes=None,
238+
ssh_command='ssh',
237239
proxy_jump=None):
238240
self.log = logging.getLogger('KRO')
239241
self.server = server
@@ -251,10 +253,6 @@ def __init__(self, server, username, ssh_pkey, remote_port, local_port,
251253
self.log.info(f"Opening SSH tunnel for {address_and_port} "
252254
f"on local port {local_port}.")
253255

254-
if re.match(r'svncserver\d.keck.hawaii.edu', server) is not None:
255-
self.log.debug('Extending timeout for svncserver connections')
256-
timeout = 60
257-
258256
# We now know everything we need to know in order to establish the
259257
# tunnel. Build the command line options and start the child process.
260258
# The -N and -T options below are somewhat exotic: they request that
@@ -263,9 +261,9 @@ def __init__(self, server, username, ssh_pkey, remote_port, local_port,
263261

264262
forwarding = f"{local_port}:localhost:{remote_port}"
265263
if proxy_jump is None:
266-
cmd = ['ssh', server, '-l', username, '-L', forwarding, '-N', '-T', '-x']
264+
cmd = [ssh_command, server, '-l', username, '-L', forwarding, '-N', '-T', '-x']
267265
else:
268-
cmd = ['ssh', '-J', f"{username}@{proxy_jump}", f"{username}@{server}", '-L', forwarding, '-N', '-T', '-x']
266+
cmd = [ssh_command, '-J', f"{username}@{proxy_jump}", f"{username}@{server}", '-L', forwarding, '-N', '-T', '-x']
269267
cmd.append('-oStrictHostKeyChecking=no')
270268
cmd.append('-oCompression=yes')
271269

@@ -335,6 +333,7 @@ def __init__(self, server, username, ssh_pkey, local_port,
335333
ssh_additional_kex=None,
336334
ssh_additional_hostkeyalgo=None,
337335
ssh_additional_keytypes=None,
336+
ssh_command='ssh',
338337
):
339338
self.log = logging.getLogger('KRO')
340339
self.server = server
@@ -353,7 +352,7 @@ def __init__(self, server, username, ssh_pkey, local_port,
353352
# the login process not execute any commands and that the server does
354353
# not allocate a pseudo-terminal for the established connection.
355354

356-
cmd = ['ssh', server, '-l', username, '-N', '-T', '-x', '-D', f"{local_port}"]
355+
cmd = [ssh_command, server, '-l', username, '-N', '-T', '-x', '-D', f"{local_port}"]
357356
cmd.append('-oStrictHostKeyChecking=no')
358357
cmd.append('-oCompression=yes')
359358

@@ -421,6 +420,7 @@ def __init__(self, args):
421420
#init vars we need to shutdown app properly
422421
self.config = None
423422
self.log = None
423+
self.ssh_command = 'ssh'
424424
self.sound = None
425425
self.ssh_tunnels = dict()
426426
self.vnc_threads = list()
@@ -429,9 +429,9 @@ def __init__(self, args):
429429
self.instrument = None
430430
self.vncserver = None
431431
self.ssh_key_valid = False
432-
self.ssh_additional_kex = '+diffie-hellman-group1-sha1'
433-
self.ssh_additional_hostkeyalgo = '+ssh-dss,ssh-rsa'
434-
self.ssh_additional_keytypes = '+ssh-dss,ssh-rsa'
432+
self.ssh_additional_kex = None
433+
self.ssh_additional_hostkeyalgo = None
434+
self.ssh_additional_keytypes = None
435435
self.exit = False
436436
self.geometry = list()
437437
self.tigervnc = None
@@ -466,6 +466,13 @@ def start(self):
466466
self.log.debug("\n***** PROGRAM STARTED *****")
467467
self.log.debug(f"Command: {' '.join(sys.argv)}")
468468

469+
##---------------------------------------------------------------------
470+
## Read configuration
471+
self.get_config()
472+
self.check_config()
473+
if self.args.authonly is False:
474+
self.get_vncviewer_properties()
475+
469476
##---------------------------------------------------------------------
470477
## Log basic system info
471478
self.log_system_info()
@@ -474,13 +481,6 @@ def start(self):
474481
if self.args.authonly is False:
475482
self.get_display_info()
476483

477-
##---------------------------------------------------------------------
478-
## Read configuration
479-
self.get_config()
480-
self.check_config()
481-
if self.args.authonly is False:
482-
self.get_vncviewer_properties()
483-
484484
##---------------------------------------------------------------------
485485
# Verify Tiger VNC Config
486486
if self.args.authonly is False:
@@ -594,9 +594,9 @@ def log_system_info(self):
594594
self.log.debug(trace)
595595

596596
try:
597-
whereisssh = subprocess.check_output(['which', 'ssh'])
597+
whereisssh = subprocess.check_output(['which', self.ssh_command])
598598
self.log.debug(f'SSH command is {whereisssh.decode().strip()}')
599-
sshversion = subprocess.check_output(['ssh', '-V'],
599+
sshversion = subprocess.check_output([self.ssh_command, '-V'],
600600
stderr=subprocess.STDOUT)
601601
self.log.debug(f'SSH version is {sshversion.decode().strip()}')
602602
except:
@@ -744,7 +744,7 @@ def get_config(self):
744744
# open file a second time to properly read config
745745
config = yaml.load(open(file), Loader=yaml.FullLoader)
746746

747-
for key in ['ssh_pkey', 'vncviewer', 'soundplayer', 'aplay']:
747+
for key in ['ssh_path', 'ssh_pkey', 'vncviewer', 'soundplayer', 'aplay']:
748748
if key in config.keys():
749749
config[key] = os.path.expanduser(config[key])
750750
config[key] = os.path.expandvars(config[key])
@@ -757,6 +757,7 @@ def get_config(self):
757757
self.config = config
758758

759759
# Load some values
760+
self.ssh_command = self.config.get('ssh_path', 'ssh')
760761
self.ssh_pkey = self.config.get('ssh_pkey', None)
761762
lps = self.config.get('local_port_start', None)
762763
self.local_port = self.LOCAL_PORT_START if lps is None else lps
@@ -993,7 +994,7 @@ def do_ssh_cmd(self, cmd, server, account):
993994
self.log.debug('Extending timeout for svncserver connections')
994995
timeout = 60
995996

996-
command = ['ssh', server, '-l', account, '-T', '-x']
997+
command = [self.ssh_command, server, '-l', account, '-T', '-x']
997998
if self.args.verbose is True:
998999
command.append('-v')
9991000
command.append('-v')
@@ -1080,9 +1081,9 @@ def get_vnc_server(self, account, instrument):
10801081
self.log.error(f'Could not determine VNC server from API')
10811082

10821083
#cmd line option
1083-
# if self.args.vncserver is not None:
1084-
# self.log.info("Using VNC server defined on command line")
1085-
# vncserver = self.args.vncserver
1084+
if self.args.vncserver is not None:
1085+
self.log.info("Using VNC server defined on command line")
1086+
vncserver = self.args.vncserver
10861087

10871088
if vncserver:
10881089
self.log.info(f"Got VNC server: '{vncserver}'")
@@ -1234,6 +1235,7 @@ def open_ssh_tunnel(self, server, username, ssh_pkey, remote_port,
12341235
if server in ['vm-k1obs.keck.hawaii.edu', 'vm-k2obs.keck.hawaii.edu']:
12351236
self.log.debug('Using proxy jump to open SSH tunnel')
12361237
t = SSHTunnel(server, username, ssh_pkey, remote_port, local_port,
1238+
ssh_command=self.ssh_command,
12371239
session_name=session_name,
12381240
timeout=self.config.get('ssh_timeout', 10),
12391241
ssh_additional_kex=self.ssh_additional_kex,
@@ -1242,6 +1244,7 @@ def open_ssh_tunnel(self, server, username, ssh_pkey, remote_port,
12421244
proxy_jump='mosfire.keck.hawaii.edu')
12431245
else:
12441246
t = SSHTunnel(server, username, ssh_pkey, remote_port, local_port,
1247+
ssh_command=self.ssh_command,
12451248
session_name=session_name,
12461249
timeout=self.config.get('ssh_timeout', 10),
12471250
ssh_additional_kex=self.ssh_additional_kex,
@@ -1268,6 +1271,7 @@ def open_ssh_for_proxy(self):
12681271
t = SSHProxy(proxy_server,
12691272
self.kvnc_account, self.ssh_pkey,
12701273
local_port,
1274+
ssh_command=self.ssh_command,
12711275
session_name='proxy',
12721276
timeout=self.config.get('ssh_timeout', 10),
12731277
ssh_additional_kex=self.ssh_additional_kex,
@@ -1955,21 +1959,6 @@ def test_ssh_key_format(self):
19551959
with open(self.ssh_pkey, 'r') as f:
19561960
contents = f.read()
19571961

1958-
# Check if this is an RSA key
1959-
# foundrsa = re.search('BEGIN RSA PRIVATE KEY', contents)
1960-
# if not foundrsa:
1961-
# self.log.error(f"Your private key does not appear to be an RSA key")
1962-
# failcount += 1
1963-
1964-
# Check if this is an OPENSSH key
1965-
foundopenssh = re.search('BEGIN OPENSSH PRIVATE KEY', contents)
1966-
if foundopenssh:
1967-
self.log.warning(f"Your SSH key may or may not be formatted correctly.")
1968-
self.log.warning(f"If no other tests fail and you can connect to the Keck VNCs,")
1969-
self.log.warning(f"then you can ignore this message. If you can not connect,")
1970-
self.log.warning(f"then try regenerating and uploading your SSH key and make")
1971-
self.log.warning(f"sure you use the `-m PEM` option when generating the key.")
1972-
19731962
# Check that there is no passphrase
19741963
foundencrypt = re.search(r'Proc-Type: \d,ENCRYPTED', contents)
19751964
if foundencrypt:

start_keck_viewers

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,35 @@
1-
#!/bin/bash
1+
#!/bin/bash -i
22

33
# If we're using conda python
4-
if [ "$CONDA_PREFIX" != "" ]; then
5-
# activate conda environment
6-
# NOTE: The KRO environment is created with:
7-
# conda env create -f environment.yaml
8-
source $CONDA_PREFIX/etc/profile.d/conda.sh
9-
conda deactivate
10-
conda activate KRO
4+
CONDAEXE=$(which conda)
5+
echo "CONDAEXE: $CONDAEXE"
6+
7+
if [ "$CONDAEXE" != "" ]; then
8+
CONDA_BASE=$(conda info --base)
9+
echo "CONDA_BASE: $CONDA_BASE"
10+
source $CONDA_BASE/etc/profile.d/conda.sh
11+
12+
KROLINE=$(conda info --envs | grep KRO)
13+
echo "KROLINE: $KROLINE"
1114

12-
#change to script dir (so we don't need full path to keck_vnc_launcher.py)
1315
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
14-
cd $DIR
16+
echo "DIR: $DIR"
1517

16-
# Launch the script
17-
if [ -e $CONDA_PREFIX/envs/KRO/bin/python3 ]; then
18-
# Launch using conda KRO environment
19-
$CONDA_PREFIX/envs/KRO/bin/python3 keck_vnc_launcher.py $@
18+
if [ "$KROLINE" != "" ]; then
19+
echo "Launching using conda KRO environment"
20+
conda activate KRO
2021
else
21-
# Try launching via conda base environment
22-
$CONDA_PREFIX/bin/python3 keck_vnc_launcher.py $@
22+
echo "Launching using conda current environment"
2323
fi
24+
python3 $DIR/keck_vnc_launcher.py -c $DIR/local_config.yaml $@
2425
else
2526
echo "We are unable to determine the correct python version to run the"
2627
echo "Remote Observing software. We will now try a generic python3 call,"
2728
echo "if this fails, simply execute the keck_vnc_launcher.py file using the"
2829
echo "correct python version for your system and use the same arguments you"
2930
echo "would use with the start_keck_viewers script. For example:"
3031
echo " /path/to/python3 keck_vnc_launcher.py numbered_account"
31-
echo "Of coure, you should use the proper path to your python executable"
32+
echo "Of course, you should use the proper path to your python executable"
3233
echo "and the correct numbered account."
3334

3435
# just try whatever is in the path and hope it works

0 commit comments

Comments
 (0)