#!/bin/bash

# Check and replace limits file that caps TCP bandwidth to 50mbps introduced in 4.1


#New installs should be safe
if [ "$1" == "new" ]; then
    exit 0;
fi

#if not limits file, then exit
if [ ! -f /etc/pscheduler/limits.conf ]; then
    exit 0
fi

#Create a temp of the old file
TEMPFILE=$(mktemp)
cat >$TEMPFILE <<EOF
{
    "#": "-------------------------------------------------------------------",
    "#": "                 PSCHEDULER LIMIT CONFIGURATION                    ",
    "#": "                                                                   ",
    "#": "This file is a sample which contains fairly sane defaults.  It     ",
    "#": "should be customized according to the needs of your site.          ",
    "#": "-------------------------------------------------------------------",

    "schema": 3,

    "#": "-------------------------------------------------------------------",
    "#": "IDENTIFIERS:  WHO'S ASKING?                                        ",
    "#": "                                                                   ",
    "#": "These identify who's asking to run the test.  One requester can    ",
    "#": "map to zero or more identifiers.                                   ",
    "#": "-------------------------------------------------------------------",

    "identifiers": [
	{
	    "name": "everybody",
	    "description": "An identifier that always identifies",
	    "type": "always",
	    "data": { }
	},
	{
	    "name": "local-interfaces",
	    "description": "Requests coming from this system",
	    "type": "localif",
	    "data": { }
	},
        {
            "#": "NOTE: This only works if the host can resolve DNS",
            "#": "on the public Internet.",

            "name": "bogons",
            "description": "Bogon/Martian IPv4 addresses without private networks",
            "type": "ip-cymru-bogon",
            "data": {
                "exclude": [
                    "10.0.0.0/8",
                    "127.0.0.0/8",
                    "172.16.0.0/12",
                    "192.168.0.0/16",
		    "169.254.0.0/16",
                    "::/8",
		    "fe80::/10"
                    ],
                "timeout": "PT1S",
                "fail-result": false
            }
        },
	{
	    "name": "hackers",
	    "description": "Blocks that have tried to hack us (actually TEST-NET-2)",
	    "type": "ip-cidr-list",
	    "data": {
		"cidrs": [ "198.51.100.0/24" ]
	    }
	}
    ],


    "#": "-------------------------------------------------------------------",
    "#": "CLASSIFIERS:  HOW DO WE CLASSIFY THE IDENTIFIERS?                  ",
    "#": "                                                                   ",
    "#": "These collect identifiers into groups.                             ",
    "#": "-------------------------------------------------------------------",

    "classifiers": [
	{
	    "name": "default",
	    "description": "Everybody",
	    "identifiers": [ "everybody" ]
	},
	{
	    "name": "friendlies",
	    "description": "Identifiers we find friendly",
	    "identifiers": [ "local-interfaces" ]
	},
	{
	    "name": "hostiles",
	    "description": "Identifiers we find unfriendly",
	    "identifiers": [ "hackers", "bogons" ]
	}
    ],


    "#": "-------------------------------------------------------------------",
    "#": "REWRITE:  WHAT CHANGES ARE MADE TO INCOMING TASKS?                 ",
    "#": "                                                                   ",
    "#": "This is a jq transform that makes changes to incoming tasks prior  ",
    "#": "to limit enforcement.                                              ",
    "#": "-------------------------------------------------------------------",

    "rewrite": {
	"script": [
	    "import \"pscheduler/iso8601\" as iso;",

	    "# This does nothing but is recommended so the statements below",
	    "# all begin with |.  (This makes editing easier.)",
            ".",

	    "# Hold this for use later.",
	    "| .test.type as \$testtype",

            "# Make some tests run a minimum of 5 seconds",
            "| if ( [\"idle\", \"idlebgm\", \"idleex\", \"latency\", \"latencybg\", \"throughput\" ]",
	    "       | contains([\$testtype]) )",
            "    and .test.spec.duration != null",
            "    and iso::duration_as_seconds(.test.spec.duration) < 5",
            "  then",
            "    .test.spec.duration = \"PT5S\"",
            "    | change(\"Bumped duration to 5-second minimum\")",
            "  else",
            "    .",
            "  end",

	    "# The end.  (This takes care of the no-comma-at-end problem)"
        ]
    },



    "#": "-------------------------------------------------------------------",
    "#": "LIMITS:  WHAT ARE THE RESTRICTIONS?                                ",
    "#": "                                                                   ",
    "#": "These are comparisons made against the type of test being proposed,",
    "#": "the paramaters for the run and when it is proposed to be run.      ",
    "#": "-------------------------------------------------------------------",

    "limits": [
        {
	    "name": "always",
	    "description": "Always passes",
	    "type": "pass-fail",
	    "data": {
	        "pass": true
	    }
	},
        {
	    "name": "never",
	    "description": "Always fails",
	    "type": "pass-fail",
	    "data": {
	        "pass": false
	    }
	},
	{
            "#": "This prevents denial of service by scheduling long tasks.",
	    "name": "idleex-default",
	    "description": "Default limits for idleex",
	    "type": "test",
	    "data": {
		"test": "idleex",
		"limit": {
		    "duration": {
                        "range": {
                            "lower": "PT1S",
                            "upper": "PT2S"
                        }
                     }
		}
	    }
	},

	{
	    "name": "innocuous-tests",
	    "description": "Tests considered harmless",
	    "type": "test-type",
	    "data": {
	        "#": "Resource hogs, which will be inverted below",
		"types": [ "throughput", "idleex" ]
	    },
	    "invert": true
	},
	{
	    "name": "throughput-default-time",
	    "description": "Throughput time limits",
	    "type": "test",
	    "data": {
		"test": "throughput",
		"limit": {
		    "duration": {
                        "range": {
                            "lower": "PT5S",
                            "upper": "PT60S"
                        }
                     },
                     "udp":{
                         "match":false
                     }
		}
	    }
	},
        {
            "name": "throughput-default-udp",
            "description": "Throughput UDP limits",
            "type": "test",
            "data": {
                "test": "throughput",
                "limit": {
                    "bandwidth": {
                        "range": {
                            "lower": "1",
                            "upper": "50M"
                        }
                     },
                     "duration": {
                        "range": {
                            "lower": "PT5S",
                            "upper": "PT60S"
                        }
                     },
                     "udp":{
                         "match":true
                     }
                }
            }
        }
    ],


    "#": "-------------------------------------------------------------------",
    "#": "APPLICATIONS:  TO WHOM DO WE APPLY THE LIMITS?                     ",
    "#": "                                                                   ",
    "#": "These are processed in order until one passes all of the           ",
    "#": "requirements.  The run will be rejected if one fails with          ",
    "#": "stop-on-failure set to true or none of them passes.                ",
    "#": "-------------------------------------------------------------------",

    "applications": [
	{
	    "description": "Hosts we don't want running any tests",
	    "classifier": "hostiles",
	    "apply": [
		{ "require": "all", "limits": [ "never" ] }
	    ],
	    "stop-on-failure": true
	},
	{
	    "description": "Hosts we trust to do everything",
	    "classifier": "friendlies",
	    "apply": [
		{ "require": "all", "limits": [ "always" ] }
	    ]
	},
	{
	    "description": "Defaults applied to non-friendly hosts",
	    "classifier": "default",
	    "apply": [
		{
		    "require": "any",
		    "limits": [
			"innocuous-tests",
                        "throughput-default-time",
                        "throughput-default-udp",
			"idleex-default"
		    ]
		}
	    ]
	}
    ],


    "#": "-------------------------------------------------------------------",
    "#": "PRIORITY:  HOW DO WE PRIORITIZE RUNS OF TASKS?                     ",
    "#": "                                                                   ",
    "#": "This is a jq transform that examines a proposed run of a task and  ",
    "#": "produces an integer value indicating its priority.  If this is not ",
    "#": "present, the neutral priority value of 0 will be used.             ",
    "#": "-------------------------------------------------------------------",

    "priority": {
	"script": [
            ".",

            "# Start with the lower of the requested and default priorities",
            "| set(default; \"Initial priority\")",

	    "# This is where decisions to change priority would be made,",
	    "# as in this commented-out example:",

	    "# # Friendly requesters get a small bump in priority.",
	    "# | if classifiers_has(\"friendlies\")",
            "#   then adjust(5; \"Friendly requester\") else . end",

	    "# The two blocks below implement recommended standard behavior.",

	    "# If the requested priority was lower than what we came up",
	    "# with, force that.",
	    "| if requested != null and requested < priority",
	    "  then set(requested; \"Lower requested priority\")",
            "  else . end",

	    "# Allow at least the requested priority for those who are",
	    "# allowed to do so.  Do this last in case things done",
	    "# above push the priority higher than was requested",
	    "| if requested != null",
	    "     and requested > default",
	    "     and requested > priority",
	    "     and classifiers_has(\"priority-positive\")",
	    "  then set(requested; \"Higher requested priority\")",
            "  else . end",

	    "# The end.  (This takes care of the no-comma-at-end problem)"
        ]
    }

}
EOF

#compare and replace if same
cmp --quiet /etc/pscheduler/limits.conf $TEMPFILE
if [ $? -eq 0 ]; then
    cp -f /etc/perfsonar/toolkit/default_service_configs/pscheduler_limits.conf /etc/pscheduler/limits.conf
fi
rm -f $TEMPFILE
