# @package      hubzero-mw2-exec-service
# @file         firewall_readd
# @author       Pascal Meunier <pmeunier@purdue.edu>
# @copyright    Copyright (c) 2016-2017 HUBzero Foundation, LLC.
# @license      http://opensource.org/licenses/MIT MIT
#
# Copyright (c) 2016-2017 HUBzero Foundation, LLC.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# HUBzero is a registered trademark of HUBzero Foundation, LLC.
#

"""
  After the execution host's firewall rules have been reloaded, add again the
  dynamic firewall rules for containers, based on the user's groups
"""

import os
import sys
import stat
import subprocess
from hubzero.mw.log import log, setup_log
from hubzero.mw.constants import CONTAINER_K, SERVICE_LOG
# handle name change SERVICE_CONFIG_FILE vs EXEC_CONFIG_FILE
# because there's a service on execution hosts that isn't the same as the service on file servers
try:
  from hubzero.mw.constants import EXEC_CONFIG_FILE
except NameError:
  from hubzero.mw.constants import SERVICE_CONFIG_FILE
  EXEC_CONFIG_FILE = SERVICE_CONFIG_FILE
from hubzero.mw.user_account import User_account
from hubzero.mw.container import Container
import pwd

# variables set in EXEC_CONFIG_FILE
CONTAINER_CONF = {}

def in_group(veid, group):
  """ deprecated, return whether group is defined in /etc/group.  Crude and often incorrect way
  of determining if user is a member of a group.  Always incorrect since we started defining
  groups in /etc/group regardless of user membership."""
  # -c: count
  cmd = ["grep", "-c", '^' + group, "/var/lib/vz/root/%s/etc/group" % veid]
  try:
    return int(subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0]) >0
  except ValueError:
    return True

def groups(veid):
  """ find last user in /etc/passwd, and get the groups"""
  cmd = ["tail", "-n", '1', "/var/lib/vz/root/%s/etc/passwd" % veid]
  userline = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0]
  userparts = userline.split(':')
  # try to trigger a StandardError if user doesn't exist
  pwd.getpwnam(userparts[0])
  return User_account(userparts[0]).groups()

def main():
  """For each container, figure out firewall rules that need to be added."""

  # get list of active containers
  vzout = subprocess.Popen(["vzlist", "-1"], stdout=subprocess.PIPE).communicate()[0]
  ctids = vzout.split()
  for ctid in ctids:
    if int(ctid) < 1000:
      #print int(ctid)
      vps = Container(int(ctid), 0, CONTAINER_CONF)
      try:
        vps.firewall_by_group(groups(ctid), 'add')
      except StandardError:
        pass # probably a standby container without a valid user

# Load the configuration and override the default variables.
# First check that it is safe to do so
try:
  mode = os.lstat(EXEC_CONFIG_FILE)[stat.ST_MODE]
except OSError:
  print "The configuration file is not readable."
  sys.exit(1)

if mode & stat.S_IWOTH:
  print "configuration file is writable by others; exiting.\n"
  sys.exit(1)

execfile(EXEC_CONFIG_FILE)
setup_log(SERVICE_LOG, None) # no log id because the log file is unique to this script
log("re-adding container rules to firewall")
main()
