Esempio n. 1
0
 def getWeight(cls, database=DEFAULT_DB_ALIAS, **kwargs):
     for i in range(5):
         if ("odoo_read_%s" % i) in os.environ:
             cls.mode = i
             PlanTaskRegistry.addArguments(
                 exportstatic=True, source="odoo_%s" % i, skipLoad=True
             )
             return 1
     return -1
Esempio n. 2
0
 def getWeight(cls, database=DEFAULT_DB_ALIAS, **kwargs):
     for i in range(5):
         if ("odoo_read_%s" % i) in os.environ:
             cls.mode = i
             for stdLoad in PlanTaskRegistry.reg.steps:
                 if isinstance(stdLoad, (PlanTaskParallel, PlanTaskSequence)):
                     continue
                 if issubclass(stdLoad, LoadTask):
                     stdLoad.filter = (
                         "(source is null or source<>'odoo_%s')" % cls.mode
                     )
                     stdLoad.description += " - non-odoo source"
             PlanTaskRegistry.addArguments(exportstatic=True, source="odoo_%s" % i)
             return 1
     return -1
Esempio n. 3
0
 def getWeight(cls, database=DEFAULT_DB_ALIAS, **kwargs):
   for i in range(5):
     if ("odoo_read_%s" % i) in os.environ:
       cls.mode = i
       for idx in (100, 101, 110):
         stdLoad = PlanTaskRegistry.getTask(sequence=idx)
         if stdLoad:
           stdLoad.filter = "source is null or source<>'odoo_%s'" % cls.mode
           stdLoad.description = "Load non-Odoo data"
       return 1
   else:
     return -1
Esempio n. 4
0
 def getWeight(cls, database=DEFAULT_DB_ALIAS, **kwargs):
   for i in range(5):
     if ("odoo_read_%s" % i) in os.environ:
       cls.mode = i
       for idx in (100, 101, 110):
         stdLoad = PlanTaskRegistry.getTask(sequence=idx)
         if stdLoad:
           stdLoad.filter = "(source is null or source<>'odoo_%s')" % cls.mode
           stdLoad.description = "Load non-Odoo data"
       return 1
   else:
     return -1
Esempio n. 5
0
    def extra_context(reportclass, request, *args, **kwargs):
        try:
            constraint = int(request.session['constraint'])
        except:
            constraint = 15

        # Synchronize the scenario table with the settings
        Scenario.syncWithSettings()

        # Collect optional tasks
        PlanTaskRegistry.autodiscover()
        planning_options = PlanTaskRegistry.getLabels()

        # Loop over all accordion of all apps and directories
        accordions = set()
        accord = ''
        for commandname, appname in get_commands().items():
            try:
                accord = getattr(
                    import_module('%s.management.commands.%s' %
                                  (appname, commandname)), 'Command')
                if accord.index >= 0:
                    accordions.add(accord)
            except Exception as e:
                pass  # Silently ignore failures

        accordions = sorted(accordions, key=operator.attrgetter('index'))

        # Send to template
        return {
            'commandlist':
            accordions,
            'logfileslist':
            json.dumps(
                list(x for x in os.listdir(settings.FREPPLE_LOGDIR)
                     if x.endswith('.log')))
        }
Esempio n. 6
0
    def getHTML(request):

        if request.user.has_perm('auth.generate_plan'):
            # Collect optional tasks
            PlanTaskRegistry.autodiscover()
            planning_options = PlanTaskRegistry.getLabels()
            current_options = request.session.get(
                'env', [i[0] for i in planning_options])

            try:
                constraint = int(request.session['constraint'])
            except:
                constraint = 15

            context = RequestContext(
                request, {
                    'planning_options': planning_options,
                    'current_options': current_options,
                    'capacityconstrained': constraint & 4,
                    'materialconstrained': constraint & 2,
                    'leadtimeconstrained': constraint & 1,
                    'fenceconstrained': constraint & 8
                })

            template = Template('''
        {% load i18n %}
        <form role="form" method="post" action="{{request.prefix}}/execute/launch/frepple_run/">{% csrf_token %}
          <table>
          <tr>
            <td style="vertical-align:top; padding: 15px">
                <button type="submit" class="btn btn-primary">{% trans "launch"|capfirst %}</button>
            </td>
            <td  style="padding: 15px;">
				        {% blocktrans %}
										Load frePPLe from the database and live data sources...<br>
										and create a plan in frePPLe...<br>
										and export results.{% endblocktrans %}<br><br>
              {% if planning_options %}
              <p {% if planning_options|length <= 1 %}style="display: none"{% endif %}><b>{% trans "optional planning steps"|capfirst %}</b><br>
              {% for b in planning_options %}
              <label for="option_{{b.0}}"><input type="checkbox" name="env" {% if b.0 in current_options %}checked {% endif %}value="{{b.0}}" id="option_{{b.0}}"/>&nbsp;&nbsp;{{b.1}}</label><br>
              {% endfor %}
              </p>
              {% endif %}
              <p><b>Plan type</b><br>

              <input type="radio" id="plantype1" name="plantype" {% ifnotequal request.session.plantype '2' %}checked {% endifnotequal %}value="1"/>
              <label for="plantype1">{% blocktrans %}<span data-toggle="tooltip" data-placement="top" data-html="true" data-original-title="Generate a supply plan that respects all constraints.<br>In case of shortages the demand is planned late or short.">Constrained plan</span>{% endblocktrans %}
              <span class="fa fa-question-circle" style="display:inline-block;"></span></label><br>
              <input type="radio" id="plantype2" name="plantype" {% ifequal  request.session.plantype '2' %}checked {% endifequal %}value="2"/>
              <label for="plantype2">{% blocktrans %}<span data-toggle="tooltip" data-placement="top" data-html="true" data-original-title="Generate a supply plan that shows material, capacity and operation problems that prevent the demand from being planned in time.<br>The demand is always met completely and on time.">Unconstrained plan</span>{% endblocktrans %}
              <span class="fa fa-question-circle" style="display:inline-block;"></span></label><br>
              </p>
              <p>
              <b>{% trans "constraints"|capfirst %}</b><br>
              <label for="cb4"><input type="checkbox" name="constraint" {% if capacityconstrained %}checked {% endif %}value="4" id="cb4"/>&nbsp;&nbsp;{% trans "Capacity: respect capacity limits" %}</label><br>
              <label for="cb2"><input type="checkbox" name="constraint" {% if materialconstrained %}checked {% endif %}value="2" id="cb2"/>&nbsp;&nbsp;{% trans "Material: respect procurement limits" %}</label><br>
              <label for="cb1"><input type="checkbox" name="constraint" {% if leadtimeconstrained %}checked {% endif %}value="1" id="cb1"/>&nbsp;&nbsp;{% trans "Lead time: do not plan in the past" %}</label><br>
              <label for="cb8"><input type="checkbox" name="constraint" {% if fenceconstrained %}checked {% endif %}value="8" id="cb8"/>&nbsp;&nbsp;{% trans "Release fence: do not plan within the release time window" %}</label><br>
              </p>
            </td>
          </tr>
          </table>
        </form>
      ''')
            return template.render(context)
        else:
            return None
Esempio n. 7
0
    def extra_context(reportclass, request, *args, **kwargs):
        try:
            constraint = int(request.session['constraint'])
        except:
            constraint = 15

        # Synchronize the scenario table with the settings
        Scenario.syncWithSettings()

        # Collect optional tasks
        PlanTaskRegistry.autodiscover()
        planning_options = PlanTaskRegistry.getLabels()

        # Loop over all fixtures of all apps and directories
        fixtures = set()
        folders = list(settings.FIXTURE_DIRS)
        for app in get_apps():
            if app.__name__.startswith('django'):
                continue
            folders.append(
                os.path.join(os.path.dirname(app.__file__), 'fixtures'))
        for f in folders:
            try:
                for root, dirs, files in os.walk(f):
                    for i in files:
                        if i.endswith('.json'):
                            fixtures.add(i.split('.')[0])
            except:
                pass  # Silently ignore failures
        fixtures = sorted(fixtures)

        # Function to convert from bytes to human readabl format
        def sizeof_fmt(num):
            for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
                if abs(num) < 1024.0:
                    return "%3.1f%sB" % (num, unit)
                num /= 1024.0
            return "%.1f%sB" % (num, 'Yi')

        # List available data files
        filestoupload = []
        if 'FILEUPLOADFOLDER' in settings.DATABASES[request.database]:
            uploadfolder = settings.DATABASES[
                request.database]['FILEUPLOADFOLDER']
            if os.path.isdir(uploadfolder):
                for file in os.listdir(uploadfolder):
                    if file.endswith(('.csv', '.csv.gz', '.log')):
                        filestoupload.append([
                            file,
                            strftime(
                                "%Y-%m-%d %H:%M:%S",
                                localtime(
                                    os.stat(os.path.join(uploadfolder,
                                                         file)).st_mtime)),
                            sizeof_fmt(
                                os.stat(os.path.join(uploadfolder,
                                                     file)).st_size)
                        ])

        # Send to template
        return {
            'capacityconstrained':
            constraint & 4,
            'materialconstrained':
            constraint & 2,
            'leadtimeconstrained':
            constraint & 1,
            'fenceconstrained':
            constraint & 8,
            'scenarios':
            Scenario.objects.all(),
            'fixtures':
            fixtures,
            'openbravo':
            'freppledb.openbravo' in settings.INSTALLED_APPS,
            'planning_options':
            planning_options,
            'current_options':
            request.session.get('env', [i[0] for i in planning_options]),
            'filestoupload':
            filestoupload,
            'datafolderconfigured':
            'FILEUPLOADFOLDER' in settings.DATABASES[request.database]
        }
Esempio n. 8
0
    def handle(self, **options):
        # Pick up the options
        now = datetime.now()

        if "database" in options:
            database = options["database"] or DEFAULT_DB_ALIAS
        else:
            database = DEFAULT_DB_ALIAS
        if database not in settings.DATABASES:
            raise CommandError("No database settings known for '%s'" %
                               database)
        if "user" in options and options["user"]:
            try:
                user = User.objects.all().using(database).get(
                    username=options["user"])
            except:
                raise CommandError("User '%s' not found" % options["user"])
        else:
            user = None

        timestamp = now.strftime("%Y%m%d%H%M%S")
        if database == DEFAULT_DB_ALIAS:
            logfile = "frepple-%s.log" % timestamp
        else:
            logfile = "frepple_%s-%s.log" % (database, timestamp)

        task = None
        try:
            # Initialize the task
            if "task" in options and options["task"]:
                try:
                    task = Task.objects.all().using(database).get(
                        pk=options["task"])
                except:
                    raise CommandError("Task identifier not found")
                if (task.started or task.finished or task.status != "Waiting"
                        or task.name not in ("runplan", "frepple_run")):
                    raise CommandError("Invalid task identifier")
                task.status = "0%"
                task.started = now
                task.logfile = logfile
            else:
                task = Task(
                    name="runplan",
                    submitted=now,
                    started=now,
                    status="0%",
                    user=user,
                    logfile=logfile,
                )

            # Validate options
            if "constraint" in options:
                constraint = int(options["constraint"])
                if constraint < 0 or constraint > 15:
                    raise ValueError("Invalid constraint: %s" %
                                     options["constraint"])
            else:
                constraint = 15
            if "plantype" in options:
                plantype = int(options["plantype"])
            else:
                plantype = 1

            # Reset environment variables
            # TODO avoid having to delete the environment variables. Use options directly?
            PlanTaskRegistry.autodiscover()
            for i in PlanTaskRegistry.reg:
                if "env" in options:
                    # Options specified
                    if i.label and i.label[0] in os.environ:
                        del os.environ[i.label[0]]
                elif i.label:
                    # No options specified - default to activate them all
                    os.environ[i.label[0]] = "1"

            # Set environment variables
            if options["env"]:
                task.arguments = "--constraint=%d --plantype=%d --env=%s" % (
                    constraint,
                    plantype,
                    options["env"],
                )
                for i in options["env"].split(","):
                    j = i.split("=")
                    if len(j) == 1:
                        os.environ[j[0]] = "1"
                    else:
                        os.environ[j[0]] = j[1]
            else:
                task.arguments = "--constraint=%d --plantype=%d" % (
                    constraint,
                    plantype,
                )
            if options["background"]:
                task.arguments += " --background"

            # Log task
            # Different from the other tasks the frepple engine will write the processid
            task.save(using=database)

            # Locate commands.py
            import freppledb.common.commands

            cmd = freppledb.common.commands.__file__

            def setlimits():
                import resource

                if settings.MAXMEMORYSIZE:
                    resource.setrlimit(
                        resource.RLIMIT_AS,
                        (
                            settings.MAXMEMORYSIZE * 1024 * 1024,
                            (settings.MAXMEMORYSIZE + 10) * 1024 * 1024,
                        ),
                    )
                if settings.MAXCPUTIME:
                    resource.setrlimit(
                        resource.RLIMIT_CPU,
                        (settings.MAXCPUTIME, settings.MAXCPUTIME + 5),
                    )
                # Limiting the file size is a bit tricky as this limit not only applies to the log
                # file, but also to temp files during the export
                # if settings.MAXTOTALLOGFILESIZE:
                #  resource.setrlimit(
                #    resource.RLIMIT_FSIZE,
                #   (settings.MAXTOTALLOGFILESIZE * 1024 * 1024, (settings.MAXTOTALLOGFILESIZE + 1) * 1024 * 1024)
                #   )

            # Prepare environment
            os.environ["FREPPLE_PLANTYPE"] = str(plantype)
            os.environ["FREPPLE_CONSTRAINT"] = str(constraint)
            os.environ["FREPPLE_TASKID"] = str(task.id)
            os.environ["FREPPLE_DATABASE"] = database
            os.environ["FREPPLE_LOGFILE"] = logfile
            os.environ["FREPPLE_PROCESSNAME"] = settings.DATABASES[database][
                "NAME"].replace("demo", "")
            os.environ["PATH"] = (settings.FREPPLE_HOME + os.pathsep +
                                  os.environ["PATH"] + os.pathsep +
                                  settings.FREPPLE_APP)
            if os.path.isfile(
                    os.path.join(settings.FREPPLE_HOME, "libfrepple.so")):
                os.environ["LD_LIBRARY_PATH"] = settings.FREPPLE_HOME
            if "DJANGO_SETTINGS_MODULE" not in os.environ:
                os.environ["DJANGO_SETTINGS_MODULE"] = "freppledb.settings"
            os.environ["PYTHONPATH"] = os.path.normpath(settings.FREPPLE_APP)
            libdir = os.path.join(os.path.normpath(settings.FREPPLE_HOME),
                                  "lib")
            if os.path.isdir(libdir):
                # Folders used by the Windows version
                os.environ["PYTHONPATH"] += os.pathsep + libdir
                if os.path.isfile(os.path.join(libdir, "library.zip")):
                    os.environ["PYTHONPATH"] += os.pathsep + os.path.join(
                        libdir, "library.zip")

            if options["background"]:
                # Execute as background process on Windows
                if os.name == "nt":
                    subprocess.Popen(["frepple", cmd],
                                     creationflags=0x08000000)
                else:
                    # Execute as background process on Linux
                    subprocess.Popen(["frepple", cmd], preexec_fn=setlimits)
            else:
                if os.name == "nt":
                    # Execute in foreground on Windows
                    ret = subprocess.call(["frepple", cmd])
                else:
                    # Execute in foreground on Linux
                    ret = subprocess.call(["frepple", cmd],
                                          preexec_fn=setlimits)
                if ret != 0 and ret != 2:
                    # Return code 0 is a successful run
                    # Return code is 2 is a run cancelled by a user. That's shown in the status field.
                    raise Exception("Failed with exit code %d" % ret)

            # Reread the task from the database and update it
            if not options["background"]:
                task = Task.objects.all().using(database).get(pk=task.id)
                task.processid = None
                task.status = "Done"
                task.finished = datetime.now()
                task.save(using=database)

        except Exception as e:
            if task:
                task = Task.objects.all().using(database).get(pk=task.id)
                task.status = "Failed"
                task.message = "%s" % e
                task.finished = datetime.now()
                task.processid = None
                task.save(using=database)
            raise e
Esempio n. 9
0
    def getHTML(request):

        if request.user.has_perm("auth.generate_plan"):
            # Collect optional tasks
            PlanTaskRegistry.autodiscover()
            planning_options = PlanTaskRegistry.getLabels()

            plantype = "2"
            constraint = 15
            current_options = [i[0] for i in planning_options]
            lastrun = (Task.objects.all().using(request.database).filter(
                name="runplan").order_by("-id").only("arguments").first())
            if lastrun and lastrun.arguments:
                # Copy all settings from the previous run by this user
                for i in shlex.split(lastrun.arguments):
                    if "=" in i:
                        key, val = i.split("=")
                        key = key.strip("--")
                        if key == "constraint":
                            try:
                                constraint = int(val)
                            except:
                                pass
                        elif key == "plantype":
                            plantype = val
                        elif key == "env":
                            try:
                                current_options = val.split(",")
                            except:
                                pass

            context = RequestContext(
                request,
                {
                    "planning_options": planning_options,
                    "current_options": current_options,
                    "capacityconstrained": constraint & 4,
                    "materialconstrained": constraint & 2,
                    "leadtimeconstrained": constraint & 1,
                    "fenceconstrained": constraint & 8,
                    "plantype": plantype,
                },
            )

            template = Template("""
        {%% load i18n %%}
        <form role="form" method="post" action="{{request.prefix}}/execute/launch/runplan/">{%% csrf_token %%}
          <table>
          <tr>
            <td style="vertical-align:top; padding: 15px">
                <button type="submit" class="btn btn-primary">{%% trans "launch"|capfirst %%}</button>
            </td>
            <td  style="padding: 15px;">%s<br><br>
          {%% if planning_options %%}
          <p {%% if planning_options|length <= 1 %%}style="display: none"{%% endif %%}><b>{%% filter capfirst %%}%s{%% endfilter %%}</b><br>
          {%% for b in planning_options %%}
          <label for="option_{{b.0}}"><input type="checkbox" name="env" {%% if b.0 in current_options %%}checked {%% endif %%}value="{{b.0}}" id="option_{{b.0}}"/>&nbsp;&nbsp;{{b.1}}</label><br>
          {%% endfor %%}
          </p>
          {%% endif %%}
          <p><b>%s</b><br>
          <input type="radio" id="plantype1" name="plantype" {%% ifnotequal plantype '2' %%}checked {%% endifnotequal %%}value="1"/>
          <label for="plantype1">%s
          <span class="fa fa-question-circle" style="display:inline-block;"></span></label><br>
          <input type="radio" id="plantype2" name="plantype" {%% ifequal plantype '2' %%}checked {%% endifequal %%}value="2"/>
          <label for="plantype2">%s
              <span class="fa fa-question-circle" style="display:inline-block;"></span></label><br>
              </p>
              <p>
              <b>{%% filter capfirst %%}%s{%% endfilter %%}</b><br>
              <label for="cb4"><input type="checkbox" name="constraint" {%% if capacityconstrained %%}checked {%% endif %%}value="4" id="cb4"/>&nbsp;&nbsp;%s</label><br>
              <label for="cb1"><input type="checkbox" name="constraint" {%% if leadtimeconstrained %%}checked {%% endif %%}value="1" id="cb1"/>&nbsp;&nbsp;%s</label><br>
              <label for="cb8"><input type="checkbox" name="constraint" {%% if fenceconstrained %%}checked {%% endif %%}value="8" id="cb8"/>&nbsp;&nbsp;%s</label><br>
              </p>
            </td>
          </tr>
          </table>
        </form>
      """ % (
                force_text(
                    _("Load all input data, run the planning algorithm, and export the results."
                      )),
                force_text(_("optional planning steps")),
                force_text(_("Plan type")),
                force_text(
                    _('<span data-toggle="tooltip" data-placement="top" data-html="true" data-original-title="Generate a supply plan that respects all constraints.<br>In case of shortages the demand is planned late or short.">Constrained plan</span>'
                      )),
                force_text(
                    _('<span data-toggle="tooltip" data-placement="top" data-html="true" data-original-title="Generate a supply plan that shows material, capacity and operation problems that prevent the demand from being planned in time.<br>The demand is always met completely and on time.">Unconstrained plan</span>'
                      )),
                force_text(_("constraints")),
                force_text(_("Capacity: respect capacity limits")),
                force_text(_("Lead time: do not plan in the past")),
                force_text(
                    _("Release fence: do not plan within the release time window"
                      )),
            ))
            return template.render(context)
        else:
            return None
Esempio n. 10
0
    if "FREPPLE_TASKID" in os.environ:
        try:
            task = (
                Task.objects.all().using(database).get(pk=os.environ["FREPPLE_TASKID"])
            )
            task.processid = os.getpid()
            task.save(update_fields=["processid"], using=database)
        except Task.DoesNotExist:
            task = None
    else:
        task = None

    # Find all planning steps and execute them
    from freppledb.common.commands import PlanTaskRegistry as register

    register.autodiscover()
    newstatus = "Done"
    try:
        register.run(database=database)
    except Exception as e:
        print("Error during planning: %s" % e)
        newstatus = "Failed"
        raise
    finally:
        # Clear the processid
        if task:
            task = Task.objects.all().using(database).get(pk=task.id)
            task.processid = None
            task.status = newstatus
            task.save(update_fields=["processid", "status"], using=database)
Esempio n. 11
0
  def extra_context(reportclass, request, *args, **kwargs):
    try:
      constraint = int(request.session['constraint'])
    except:
      constraint = 15

    # Synchronize the scenario table with the settings
    Scenario.syncWithSettings()

    # Collect optional tasks
    PlanTaskRegistry.autodiscover()
    planning_options = PlanTaskRegistry.getLabels()

    # Loop over all fixtures of all apps and directories
    fixtures = set()
    folders = list(settings.FIXTURE_DIRS)
    for app in get_apps():
      if app.__name__.startswith('django'):
        continue
      folders.append(os.path.join(os.path.dirname(app.__file__), 'fixtures'))
    for f in folders:
      try:
        for root, dirs, files in os.walk(f):
          for i in files:
            if i.endswith('.json'):
              fixtures.add(i.split('.')[0])
      except:
        pass  # Silently ignore failures
    fixtures = sorted(fixtures)

    # Function to convert from bytes to human readabl format
    def sizeof_fmt(num):
      for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
        if abs(num) < 1024.0:
          return "%3.1f%sB" % (num, unit)
        num /= 1024.0
      return "%.1f%sB" % (num, 'Yi')

    # List available data files
    filestoupload = []
    if 'FILEUPLOADFOLDER' in settings.DATABASES[request.database]:
      uploadfolder = settings.DATABASES[request.database]['FILEUPLOADFOLDER']
      if os.path.isdir(uploadfolder):
        for file in os.listdir(uploadfolder):
          if file.endswith('.csv') or file.endswith('.log'):
            filestoupload.append([
              file,
              strftime("%Y-%m-%d %H:%M:%S",localtime(os.stat(os.path.join(uploadfolder, file)).st_mtime)),
              sizeof_fmt(os.stat(os.path.join(uploadfolder, file)).st_size)
              ])

    # Send to template
    return {
      'capacityconstrained': constraint & 4,
      'materialconstrained': constraint & 2,
      'leadtimeconstrained': constraint & 1,
      'fenceconstrained': constraint & 8,
      'scenarios': Scenario.objects.all(),
      'fixtures': fixtures,
      'openbravo': 'freppledb.openbravo' in settings.INSTALLED_APPS,
      'planning_options': planning_options,
      'current_options': request.session.get('env', [ i[0] for i in planning_options ]),
      'filestoupload': filestoupload,
      'datafolderconfigured': 'FILEUPLOADFOLDER' in settings.DATABASES[request.database]
      }
Esempio n. 12
0
  def handle(self, **options):
    # Pick up the options
    now = datetime.now()

    if 'database' in options:
      database = options['database'] or DEFAULT_DB_ALIAS
    else:
      database = DEFAULT_DB_ALIAS
    if database not in settings.DATABASES:
      raise CommandError("No database settings known for '%s'" % database )
    if 'user' in options and options['user']:
      try:
        user = User.objects.all().using(database).get(username=options['user'])
      except:
        raise CommandError("User '%s' not found" % options['user'] )
    else:
      user = None

    timestamp = now.strftime("%Y%m%d%H%M%S")
    if database == DEFAULT_DB_ALIAS:
      logfile = 'frepple-%s.log' % timestamp
    else:
      logfile = 'frepple_%s-%s.log' % (database, timestamp)

    task = None
    try:
      # Initialize the task
      if 'task' in options and options['task']:
        try:
          task = Task.objects.all().using(database).get(pk=options['task'])
        except:
          raise CommandError("Task identifier not found")
        if task.started or task.finished or task.status != "Waiting" or task.name not in ('runplan', 'frepple_run'):
          raise CommandError("Invalid task identifier")
        task.status = '0%'
        task.started = now
        task.logfile = logfile
      else:
        task = Task(name='runplan', submitted=now, started=now, status='0%', user=user, logfile=logfile)

      # Validate options
      if 'constraint' in options:
        constraint = int(options['constraint'])
        if constraint < 0 or constraint > 15:
          raise ValueError("Invalid constraint: %s" % options['constraint'])
      else:
        constraint = 15
      if 'plantype' in options:
        plantype = int(options['plantype'])
      else:
        plantype = 1

      # Reset environment variables
      # TODO avoid having to delete the environment variables. Use options directly?
      PlanTaskRegistry.autodiscover()
      for i in PlanTaskRegistry.reg:
        if 'env' in options:
          # Options specified
          if i.label and i.label[0] in os.environ:
            del os.environ[i.label[0]]
        elif i.label:
          # No options specified - default to activate them all
          os.environ[i.label[0]] = '1'

      # Set environment variables
      if options['env']:
        task.arguments = "--constraint=%d --plantype=%d --env=%s" % (constraint, plantype, options['env'])
        for i in options['env'].split(','):
          j = i.split('=')
          if len(j) == 1:
            os.environ[j[0]] = '1'
          else:
            os.environ[j[0]] = j[1]
      else:
        task.arguments = "--constraint=%d --plantype=%d" % (constraint, plantype)
      if options['background']:
        task.arguments += " --background"

      # Log task
      # Different from the other tasks the frepple engine will write the processid
      task.save(using=database)

      # Locate commands.py
      import freppledb.common.commands
      cmd = freppledb.common.commands.__file__

      def setlimits():
        import resource
        if settings.MAXMEMORYSIZE:
          resource.setrlimit(
            resource.RLIMIT_AS,
            (settings.MAXMEMORYSIZE * 1024 * 1024, (settings.MAXMEMORYSIZE + 10) * 1024 * 1024)
            )
        if settings.MAXCPUTIME:
          resource.setrlimit(
            resource.RLIMIT_CPU,
            (settings.MAXCPUTIME, settings.MAXCPUTIME + 5)
            )
        # Limiting the file size is a bit tricky as this limit not only applies to the log
        # file, but also to temp files during the export
        # if settings.MAXTOTALLOGFILESIZE:
        #  resource.setrlimit(
        #    resource.RLIMIT_FSIZE,
        #   (settings.MAXTOTALLOGFILESIZE * 1024 * 1024, (settings.MAXTOTALLOGFILESIZE + 1) * 1024 * 1024)
        #   )

      # Prepare environment
      os.environ['FREPPLE_PLANTYPE'] = str(plantype)
      os.environ['FREPPLE_CONSTRAINT'] = str(constraint)
      os.environ['FREPPLE_TASKID'] = str(task.id)
      os.environ['FREPPLE_DATABASE'] = database
      os.environ['FREPPLE_LOGFILE'] = logfile
      os.environ['FREPPLE_PROCESSNAME'] = settings.DATABASES[database]['NAME'].replace('demo', '')
      os.environ['PATH'] = settings.FREPPLE_HOME + os.pathsep + os.environ['PATH'] + os.pathsep + settings.FREPPLE_APP
      if os.path.isfile(os.path.join(settings.FREPPLE_HOME, 'libfrepple.so')):
        os.environ['LD_LIBRARY_PATH'] = settings.FREPPLE_HOME
      if 'DJANGO_SETTINGS_MODULE' not in os.environ:
        os.environ['DJANGO_SETTINGS_MODULE'] = 'freppledb.settings'
      os.environ['PYTHONPATH'] = os.path.normpath(settings.FREPPLE_APP)
      libdir = os.path.join(os.path.normpath(settings.FREPPLE_HOME), 'lib')
      if os.path.isdir(libdir):
        # Folders used by the Windows version
        os.environ['PYTHONPATH'] += os.pathsep + libdir
        if os.path.isfile(os.path.join(libdir, 'library.zip')):
          os.environ['PYTHONPATH'] += os.pathsep + os.path.join(libdir, 'library.zip')

      if options['background']:
        # Execute as background process on Windows
        if os.name == 'nt':
          subprocess.Popen(['frepple', cmd], creationflags=0x08000000)
        else:
          # Execute as background process on Linux
          subprocess.Popen(['frepple', cmd], preexec_fn=setlimits)
      else:
        if os.name == 'nt':
          # Execute in foreground on Windows
          ret = subprocess.call(['frepple', cmd])
        else:
          # Execute in foreground on Linux
          ret = subprocess.call(['frepple', cmd], preexec_fn=setlimits)
        if ret != 0 and ret != 2:
          # Return code 0 is a successful run
          # Return code is 2 is a run cancelled by a user. That's shown in the status field.
          raise Exception('Failed with exit code %d' % ret)

      # Reread the task from the database and update it
      if not options['background']:
        task = Task.objects.all().using(database).get(pk=task.id)
        task.processid = None
        task.status = 'Done'
        task.finished = datetime.now()
        task.save(using=database)

    except Exception as e:
      if task:
        task = Task.objects.all().using(database).get(pk=task.id)
        task.status = 'Failed'
        task.message = '%s' % e
        task.finished = datetime.now()
        task.processid = None
        task.save(using=database)
      raise e
Esempio n. 13
0
  def getHTML(request):

    if request.user.has_perm('auth.generate_plan'):
      # Collect optional tasks
      PlanTaskRegistry.autodiscover()
      planning_options = PlanTaskRegistry.getLabels()

      plantype = '2'
      constraint = 15
      current_options = [ i[0] for i in planning_options ]
      lastrun = Task.objects.all().using(request.database) \
        .filter(name="runplan") \
        .order_by("-id").only("arguments").first()
      if lastrun and lastrun.arguments:
        # Copy all settings from the previous run by this user
        for i in shlex.split(lastrun.arguments):
          if '=' in i:
            key, val = i.split('=')
            key = key.strip('--')
            if key == 'constraint':
              try:
                constraint = int(val)
              except:
                pass
            elif key == 'plantype':
              plantype = val
            elif key == 'env':
              try:
                current_options = val.split(',')
              except:
                pass

      context = RequestContext(request, {
        'planning_options': planning_options,
        'current_options': current_options,
        'capacityconstrained': constraint & 4,
        'materialconstrained': constraint & 2,
        'leadtimeconstrained': constraint & 1,
        'fenceconstrained': constraint & 8,
        'plantype': plantype
        })

      template = Template('''
        {%% load i18n %%}
        <form role="form" method="post" action="{{request.prefix}}/execute/launch/runplan/">{%% csrf_token %%}
          <table>
          <tr>
            <td style="vertical-align:top; padding: 15px">
                <button type="submit" class="btn btn-primary">{%% trans "launch"|capfirst %%}</button>
            </td>
            <td  style="padding: 15px;">%s<br><br>
          {%% if planning_options %%}
          <p {%% if planning_options|length <= 1 %%}style="display: none"{%% endif %%}><b>{%% filter capfirst %%}%s{%% endfilter %%}</b><br>
          {%% for b in planning_options %%}
          <label for="option_{{b.0}}"><input type="checkbox" name="env" {%% if b.0 in current_options %%}checked {%% endif %%}value="{{b.0}}" id="option_{{b.0}}"/>&nbsp;&nbsp;{{b.1}}</label><br>
          {%% endfor %%}
          </p>
          {%% endif %%}
          <p><b>%s</b><br>
          <input type="radio" id="plantype1" name="plantype" {%% ifnotequal plantype '2' %%}checked {%% endifnotequal %%}value="1"/>
          <label for="plantype1">%s
          <span class="fa fa-question-circle" style="display:inline-block;"></span></label><br>
          <input type="radio" id="plantype2" name="plantype" {%% ifequal plantype '2' %%}checked {%% endifequal %%}value="2"/>
          <label for="plantype2">%s
              <span class="fa fa-question-circle" style="display:inline-block;"></span></label><br>
              </p>
              <p>
              <b>{%% filter capfirst %%}%s{%% endfilter %%}</b><br>
              <label for="cb4"><input type="checkbox" name="constraint" {%% if capacityconstrained %%}checked {%% endif %%}value="4" id="cb4"/>&nbsp;&nbsp;%s</label><br>
              <label for="cb2"><input type="checkbox" name="constraint" {%% if materialconstrained %%}checked {%% endif %%}value="2" id="cb2"/>&nbsp;&nbsp;%s</label><br>
              <label for="cb1"><input type="checkbox" name="constraint" {%% if leadtimeconstrained %%}checked {%% endif %%}value="1" id="cb1"/>&nbsp;&nbsp;%s</label><br>
              <label for="cb8"><input type="checkbox" name="constraint" {%% if fenceconstrained %%}checked {%% endif %%}value="8" id="cb8"/>&nbsp;&nbsp;%s</label><br>
              </p>
            </td>
          </tr>
          </table>
        </form>
      ''' % (
        force_text(_('Load all input data, run the planning algorithm, and export the results.')),
        force_text(_("optional planning steps")),
        force_text(_("Plan type")),
        force_text(_('<span data-toggle="tooltip" data-placement="top" data-html="true" data-original-title="Generate a supply plan that respects all constraints.<br>In case of shortages the demand is planned late or short.">Constrained plan</span>')),
        force_text(_('<span data-toggle="tooltip" data-placement="top" data-html="true" data-original-title="Generate a supply plan that shows material, capacity and operation problems that prevent the demand from being planned in time.<br>The demand is always met completely and on time.">Unconstrained plan</span>')),
        force_text(_("constraints")),
        force_text(_("Capacity: respect capacity limits")),
        force_text(_("Material: respect procurement limits")),
        force_text(_("Lead time: do not plan in the past")),
        force_text(_("Release fence: do not plan within the release time window")),
        ))
      return template.render(context)
    else:
      return None
Esempio n. 14
0
    def handle(self, **options):
        # Pick up the options
        now = datetime.now()

        if 'database' in options:
            database = options['database'] or DEFAULT_DB_ALIAS
        else:
            database = DEFAULT_DB_ALIAS
        if database not in settings.DATABASES:
            raise CommandError("No database settings known for '%s'" %
                               database)
        if 'user' in options and options['user']:
            try:
                user = User.objects.all().using(database).get(
                    username=options['user'])
            except:
                raise CommandError("User '%s' not found" % options['user'])
        else:
            user = None

        timestamp = now.strftime("%Y%m%d%H%M%S")
        if database == DEFAULT_DB_ALIAS:
            logfile = 'frepple-%s.log' % timestamp
        else:
            logfile = 'frepple_%s-%s.log' % (database, timestamp)

        task = None
        try:
            # Initialize the task
            if 'task' in options and options['task']:
                try:
                    task = Task.objects.all().using(database).get(
                        pk=options['task'])
                except:
                    raise CommandError("Task identifier not found")
                if task.started or task.finished or task.status != "Waiting" or task.name != 'frepple_run':
                    raise CommandError("Invalid task identifier")
                task.status = '0%'
                task.started = now
                task.logfile = logfile
            else:
                task = Task(name='frepple_run',
                            submitted=now,
                            started=now,
                            status='0%',
                            user=user,
                            logfile=logfile)

            # Validate options
            if 'constraint' in options:
                constraint = int(options['constraint'])
                if constraint < 0 or constraint > 15:
                    raise ValueError("Invalid constraint: %s" %
                                     options['constraint'])
            else:
                constraint = 15
            if 'plantype' in options:
                plantype = int(options['plantype'])
            else:
                plantype = 1

            # Reset environment variables
            # TODO avoid having to delete the environment variables. Use options directly?
            PlanTaskRegistry.autodiscover()
            for i in PlanTaskRegistry.reg:
                if 'env' in options:
                    # Options specified
                    if i.label and i.label[0] in os.environ:
                        del os.environ[i.label[0]]
                elif i.label:
                    # No options specified - default to activate them all
                    os.environ[i.label[0]] = '1'

            # Set environment variables
            if options['env']:
                task.arguments = "--constraint=%d --plantype=%d --env=%s" % (
                    constraint, plantype, options['env'])
                for i in options['env'].split(','):
                    j = i.split('=')
                    if len(j) == 1:
                        os.environ[j[0]] = '1'
                    else:
                        os.environ[j[0]] = j[1]
            else:
                task.arguments = "--constraint=%d --plantype=%d" % (constraint,
                                                                    plantype)
            if options['background']:
                task.arguments += " --background"

            # Log task
            task.save(using=database)

            # Locate commands.py
            import freppledb.common.commands
            cmd = freppledb.common.commands.__file__

            # Prepare environment
            os.environ['FREPPLE_PLANTYPE'] = str(plantype)
            os.environ['FREPPLE_CONSTRAINT'] = str(constraint)
            os.environ['FREPPLE_TASKID'] = str(task.id)
            os.environ['FREPPLE_DATABASE'] = database
            os.environ['FREPPLE_LOGFILE'] = logfile
            os.environ[
                'PATH'] = settings.FREPPLE_HOME + os.pathsep + os.environ[
                    'PATH'] + os.pathsep + settings.FREPPLE_APP
            if os.path.isfile(
                    os.path.join(settings.FREPPLE_HOME, 'libfrepple.so')):
                os.environ['LD_LIBRARY_PATH'] = settings.FREPPLE_HOME
            if 'DJANGO_SETTINGS_MODULE' not in os.environ:
                os.environ['DJANGO_SETTINGS_MODULE'] = 'freppledb.settings'
            os.environ['PYTHONPATH'] = os.path.normpath(settings.FREPPLE_APP)

            if options['background']:
                # Execute as background process on Windows
                if os.name == 'nt':
                    subprocess.Popen(['frepple', cmd],
                                     creationflags=0x08000000)
                else:
                    # Execute as background process on Linux
                    subprocess.Popen(['frepple', cmd])
            else:
                # Execute in foreground
                ret = subprocess.call(['frepple', cmd])
                if ret != 0 and ret != 2:
                    # Return code 0 is a successful run
                    # Return code is 2 is a run cancelled by a user. That's shown in the status field.
                    raise Exception('Failed with exit code %d' % ret)

                # Task update
                task.status = 'Done'
                task.finished = datetime.now()

        except Exception as e:
            if task:
                task.status = 'Failed'
                task.message = '%s' % e
                task.finished = datetime.now()
            raise e

        finally:
            if task:
                task.save(using=database)
Esempio n. 15
0
  if 'FREPPLE_TEST' in os.environ:
    settings.DATABASES[database]['NAME'] = settings.DATABASES[database]['TEST']['NAME']

  # Make sure the debug flag is not set!
  # When it is set, the Django database wrapper collects a list of all sql
  # statements executed and their timings. This consumes plenty of memory
  # and cpu time.
  settings.DEBUG = False

  # Send the output to a logfile
  if database == DEFAULT_DB_ALIAS:
    frepple.settings.logfile = os.path.join(settings.FREPPLE_LOGDIR, 'frepple.log')
  else:
    frepple.settings.logfile = os.path.join(settings.FREPPLE_LOGDIR, 'frepple_%s.log' % database)

  # Welcome message
  print("FrePPLe with processid %s on %s using database '%s'" % (
    os.getpid(),
    sys.platform,
    database
    ))

  # Find all planning steps and execute them
  from freppledb.common.commands import PlanTaskRegistry as register
  register.autodiscover()
  try:
    register.run(database=database)
  except Exception as e:
    print("Error during planning: ", e)
    raise
Esempio n. 16
0
    # Update the task with my processid
    if "FREPPLE_TASKID" in os.environ:
        try:
            task = (Task.objects.all().using(database).get(
                pk=os.environ["FREPPLE_TASKID"]))
            task.processid = os.getpid()
            task.save(update_fields=["processid"], using=database)
        except Task.DoesNotExist:
            task = None
    else:
        task = None

    # Find all planning steps and execute them
    from freppledb.common.commands import PlanTaskRegistry as register

    newstatus = "Done"
    try:
        register.run(database=database)
    except Exception as e:
        logger.error("Error during planning: %s" % e)
        newstatus = "Failed"
        raise
    finally:
        # Clear the processid
        if task:
            task = Task.objects.all().using(database).get(pk=task.id)
            task.processid = None
            task.status = newstatus
            task.save(update_fields=["processid", "status"], using=database)
Esempio n. 17
0
  def handle(self, **options):
    # Pick up the options
    if 'database' in options:
      database = options['database'] or DEFAULT_DB_ALIAS
    else:
      database = DEFAULT_DB_ALIAS
    if database not in settings.DATABASES:
      raise CommandError("No database settings known for '%s'" % database )
    if 'user' in options and options['user']:
      try:
        user = User.objects.all().using(database).get(username=options['user'])
      except:
        raise CommandError("User '%s' not found" % options['user'] )
    else:
      user = None

    now = datetime.now()
    task = None
    try:
      # Initialize the task
      if 'task' in options and options['task']:
        try:
          task = Task.objects.all().using(database).get(pk=options['task'])
        except:
          raise CommandError("Task identifier not found")
        if task.started or task.finished or task.status != "Waiting" or task.name != 'generate plan':
          raise CommandError("Invalid task identifier")
        task.status = '0%'
        task.started = now
      else:
        task = Task(name='generate plan', submitted=now, started=now, status='0%', user=user)

      # Validate options
      if 'constraint' in options:
        constraint = int(options['constraint'])
        if constraint < 0 or constraint > 15:
          raise ValueError("Invalid constraint: %s" % options['constraint'])
      else:
        constraint = 15
      if 'plantype' in options:
        plantype = int(options['plantype'])
        if plantype < 1 or plantype > 2:
          raise ValueError("Invalid plan type: %s" % options['plantype'])
      else:
        plantype = 1

      # Reset environment variables
      # TODO avoid having to delete the environment variables. Use options directly?
      PlanTaskRegistry.autodiscover()
      for i in PlanTaskRegistry.reg:
        if options['env']:
          # Options specified
          if i.label and i.label[0] in os.environ:
            del os.environ[i.label[0]]
        elif i.label:
          # No options specified - default to activate them all
          os.environ[i.label[0]] = '1'

      # Set environment variables
      if options['env']:
        task.arguments = "--constraint=%d --plantype=%d --env=%s" % (constraint, plantype, options['env'])
        for i in options['env'].split(','):
          j = i.split('=')
          if len(j) == 1:
            os.environ[j[0]] = '1'
          else:
            os.environ[j[0]] = j[1]
      else:
        task.arguments = "--constraint=%d --plantype=%d" % (constraint, plantype)
      if options['background']:
        task.arguments += " --background"

      # Log task
      task.save(using=database)

      # Locate commands.py
      import freppledb.common.commands
      cmd = freppledb.common.commands.__file__

      # Prepare environment
      os.environ['FREPPLE_PLANTYPE'] = str(plantype)
      os.environ['FREPPLE_CONSTRAINT'] = str(constraint)
      os.environ['FREPPLE_TASKID'] = str(task.id)
      os.environ['FREPPLE_DATABASE'] = database
      os.environ['PATH'] = settings.FREPPLE_HOME + os.pathsep + os.environ['PATH'] + os.pathsep + settings.FREPPLE_APP
      if os.path.isfile(os.path.join(settings.FREPPLE_HOME, 'libfrepple.so')):
        os.environ['LD_LIBRARY_PATH'] = settings.FREPPLE_HOME
      if 'DJANGO_SETTINGS_MODULE' not in os.environ:
        os.environ['DJANGO_SETTINGS_MODULE'] = 'freppledb.settings'
      os.environ['PYTHONPATH'] = os.path.normpath(settings.FREPPLE_APP)

      if options['background']:
        # Execute as background process on Windows
        if os.name == 'nt':
          subprocess.Popen(['frepple', cmd], creationflags=0x08000000)
        else:
          # Execute as background process on Linux
          subprocess.Popen(['frepple', cmd])
      else:
        # Execute in foreground
        ret = subprocess.call(['frepple', cmd])
        if ret != 0 and ret != 2:
          # Return code 0 is a successful run
          # Return code is 2 is a run cancelled by a user. That's shown in the status field.
          raise Exception('Failed with exit code %d' % ret)

        # Task update
        task.status = 'Done'
        task.finished = datetime.now()

    except Exception as e:
      if task:
        task.status = 'Failed'
        task.message = '%s' % e
        task.finished = datetime.now()
      raise e

    finally:
      if task:
        task.save(using=database)