pyobs-archive

pyobs-archive is a stand-alone archive for FITS images. It provides a general look&feel and an REST API similar to the one used by the LCO archive.

Installation

While it is definitely possible to run pyobs-weather without Docker, we highly recommend it for its simplicity.

First, build the image:

cd https://github.com/pyobs/pyobs-archive.git
cd pyobs-archive
docker build . -t pyobs-archive

pyobs-archive requires a database for storing its data and nginx for serving static files. Easiest way to deploy everything is using docker-compose.

A typical docker-compose.yml looks like this:

version: '3'

services:
  db:
    image: postgres:11
    volumes:
      - pgdata:/var/lib/postgresql/data
    restart: always

  archive:
    image: pyobs-archive
    volumes:
      - /local_data/:/data/
      - ./local_settings.py:/archive/pyobs_archive/local_settings.py
      - static:/archive/static
    depends_on:
      - db
    restart: always
    command: bash -c "python manage.py collectstatic --no-input && python manage.py makemigrations && python manage.py migrate && gunicorn --workers=3 pyobs_archive.wsgi -b 0.0.0.0:8000"

  nginx:
    image: nginx
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
      - static:/static/static
    ports:
      - 8001:80
    restart: always

volumes:
  pgdata:
  static:

The configuration for the “archive” container contains a volume that points to the local directory /local_data/. This will be the directory where the archive stores its files. Please adjust as necessary.

In this example, nginx needs a configuration file nginx.conf in the same directory, which might look like this:

server {
    listen 80;
    server_name  127.0.0.1;
    client_max_body_size 50M;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
        if (!-f $request_filename) {
            proxy_pass http://archive:8000;
            break;
        }
    }

    location /static/ {
        root /static;
    }
}

And pyobs-archive itself needs a configuration file called local_settings.py. Here is the file for MONET/S as an example:

# disable debug
DEBUG = False

# we're reverse proxying, so only localhost is allowed to access
ALLOWED_HOSTS = ['localhost']

# settings for archive
ARCHIV_SETTINGS = {
    'HTTP_ROOT': 'https://archive.example.com/',
    'ARCHIVE_ROOT': '/data/',
    'PATH_FORMATTER': '{SITEID}/{DAY-OBS}/',
    'FILENAME_FORMATTER': None,
}

You have to adjust the settings in ARCHIV_SETTINGS as necessary:

  • HTTP_ROOT is the URL the archive will be accessible at.

  • ARCHIVE_ROOT is the internal data directory and is mapped in the docker-compose file to a local directory. Should be left as it is.

  • PATH_FORMATTER: A format for the pathes to store the image in. Uses FITS header keywords as placeholders.

  • FILENAME_FORMATTER: Same as the PATH_FORMATTER, but for the filename. If None, filenames won’t be changed.

With all three files in one directory, you can easily do:

docker-compose up -d

and the whole system should be up and running within a minute.

Finally, you need to get into the container and create a superuser:

docker exec -it weather_weather_1 bash
./manage.py createsuperuser

The web frontend should now be accessible via web browser at http://localhost:8001/ and the admin panel at http://localhost:8001/admin.

REST API Reference

Authentication

All requests to the REST API must contain a HTTP header of the form:

Authentication: Token <token>

Where <token> is an auth token that can be obtained by calling the /api-token-auth/ endpoint with valid credentials.

As an example, you can get a token like this:

http https://archive.example.com/api-token-auth/ username=husser password=topsecret

Which might return something like this:

{"token":"3d46d6b98edef947402e032e73eca7b54661c968"}

The token can now be used in other requests:

http https://archive.example.com/frames/ "Authorization: Token 3d46d6b98edef947402e032e73eca7b54661c968"

List images

Images in the archive can easily be listed using the /frames/ endpoint. It accepts HTTP GET parameters for filtering. A typical example would be:

http https://archive.example.com/frames/?night=2020-02-01

for getting a list of all images taken in the night of 1 Feb, 2020.

Other possible filter parameters are:

  • IMAGETYPE: Type of image (see Filter options for details).

  • binning: Binning of image (see Filter options for details).

  • SITE: Site the image was taken (see Filter options for details).

  • TELESCOPE: Telescope the image was taken with (see Filter options for details).

  • INSTRUMENT: Instrument the image was taken with (see Filter options for details).

  • FILTER: Filter the image was taken with (see Filter options for details).

  • RLEVEL: Reduction level (0=unreduced, 1=reduced).

  • OBJECT: Name of observed object.

  • EXPTIME: Exposure time in seconds.

  • night: Night of observation in yyyy-mm-dd format.

  • basename: Name of FITS file.

  • REQNUM: Request number from robotic system.

  • start: Limit to images taken after this, given in isot format.

  • end: Limit to images taken before this, given in isot format.

  • RA: If RA/DEC are given, limit search to 10’ around position

  • DEC: See above.

  • limit: Maximum number of images to return.

  • offset: Offset for list of images to return, use for pagination together with limit above.

  • order: Order results using this column.

  • asc: If given, order ascending instead of descending.

Filter options

A call to the /frames/aggregate/ endpoint gives possible choices for some of the filter options:

http https://archive.example.com/frames/aggregate/

Might result in something like:

{
    "binnings": ["1x1", "3x3"],
    "filters": ["B", "V", "R"],
    "imagetypes": ["bias", "dark", "object", "skyflat"],
    "instruments": ["instr1", "instr2"],
    "sites": ["Paranal", "Mauna Kea"],
    "telescopes": ["39m0","30m0"]
}

Image information

Information about a single image can be retrieved using the /frames/image/ endpoint, e.g.:

http https://archive.example.com/frames/1000/

More specific information can be obtaines using:

# for a list of related images.
http https://archive.example.com/frames/1000/related/

# for the FITS headers in JSON format.
http https://archive.example.com/frames/1000/headers/

# for a preview image.
http https://archive.example.com/frames/1000/preview/

A single image can be downloaded via:

wget https://archive.example.com/frames/1000/download/

Downloading images

A whole bunch of images can be downloaded via /zip/ and listing the frames in the body, e.g.:

wget https://archive.example.com/frames/zip/ --post-data="auth_token=<token>&frame_ids[]=1000&frame_ids[]=1001" -O data.zip

The auth token needs to go into the POST body in this case, and a list of image IDs can be added using “frame_ids[]”.

Uploading images

A registered admin user may send new files to the /create/ endpoint for automatically inserting images into the archive.