示例#1
0
async def make_crontab(collector, target, reference, artifact, **kwargs):
    """
    Make a crontab file executing our day dusk options.

    Usage is::

        ./generate-crontab.py
    """
    collector.register_converters(
        {"daydusk": DayDusk.FieldSpec(formatter=MergedOptionStringFormatter)})
    daydusk = collector.configuration["daydusk"]

    spec = sb.set_options(path=sb.defaulted(sb.string_spec(),
                                            '/config/daydusk.crontab'),
                          lifx_script=sb.defaulted(sb.string_spec(),
                                                   '/usr/local/bin/lifx'))
    extra = collector.configuration["photons_app"].extra_as_json
    kwargs = {
        k: v
        for k, v in spec.normalise(Meta.empty(), extra).items()
        if v is not sb.NotSpecified
    }

    cronfile = kwargs['path']
    lifx_script = kwargs['lifx_script']

    if not daydusk.schedules:
        raise NoSchedules()

    cron = CronTab()

    extra_script_args = ["--silent"]

    for name, options in daydusk.schedules.items():
        script_args = {**options.hsbk, **options.extra}
        command = [
            lifx_script,
            options.task,
            options.reference,
            *extra_script_args,
            "--",
            json.dumps(script_args),
        ]

        command = str(" ".join([shlex.quote(part) for part in command]))

        job = cron.new(command=command)
        job.dow.on(*options.dow)
        job.minute.on(options.minute)
        job.hour.on(options.hour)

    if os.path.exists(cronfile):
        os.remove(cronfile)

    cron.write(cronfile)
    print(f"Generated crontab at {cronfile}")
示例#2
0
文件: addon.py 项目: delfick/photons
    async def execute_task(self, **kwargs):
        broadcast = True
        if self.artifact is not sb.NotSpecified:
            broadcast = self.artifact

        options = sb.set_options(
            cli_output=sb.defaulted(sb.boolean(), None),
            env_output=sb.defaulted(sb.boolean(), False),
            settings_output=sb.defaulted(sb.boolean(), False),
        ).normalise(Meta.empty(), self.collector.photons_app.extra_as_json)

        if options["env_output"] is False and options[
                "settings_output"] is False:
            if options["cli_output"] is None:
                options["cli_output"] = True

        env_output = options["env_output"]
        cli_output = options["cli_output"]
        settings_output = options["settings_output"]

        ips = {}

        async with self.target.session() as sender:
            found, serials = await self.reference.find(sender,
                                                       timeout=20,
                                                       broadcast=broadcast)
            for serial in serials:
                services = found[binascii.unhexlify(serial)]
                if Services.UDP in services:
                    ip = services[Services.UDP].host
                    ips[serial] = ip

        sorted_ips = sorted(ips.items(),
                            key=lambda item: ipaddress.ip_address(item[1]))

        if cli_output:
            for serial, ip in sorted_ips:
                print(f"{serial}: {ip}")

        if cli_output and (env_output or settings_output):
            print()

        if env_output:
            print(f"export HARDCODED_DISCOVERY='{json.dumps(sorted_ips)}'")
            if settings_output:
                print()

        if settings_output:
            print("discovery_options:")
            print("  hardcoded_discovery:")

            for serial, ip in sorted_ips:
                print(f'    {serial}: "{ip}"')
示例#3
0
    def make_command(self, meta, val, existing):
        v = sb.set_options(path=sb.required(sb.string_spec()),
                           allow_ws_only=sb.defaulted(sb.boolean(),
                                                      False)).normalise(
                                                          meta, val)

        path = v["path"]
        allow_ws_only = v["allow_ws_only"]

        if path not in self.paths:
            raise NoSuchPath(path, sorted(self.paths))

        val = sb.set_options(body=sb.required(
            sb.set_options(args=sb.dictionary_spec(),
                           command=sb.required(sb.string_spec())))).normalise(
                               meta, val)

        args = val["body"]["args"]
        name = val["body"]["command"]

        if existing:
            name = val["body"]["command"] = f"{existing['path']}:{name}"

        extra_context = {}
        if existing:
            extra_context["_parent_command"] = existing["command"]

        everything = meta.everything
        if isinstance(meta.everything, MergedOptions):
            everything = meta.everything.wrapped()
        everything.update(extra_context)
        meta = Meta(everything, []).at("body")

        available_commands = self.paths[path]

        if name not in available_commands:
            raise BadSpecValue(
                "Unknown command",
                wanted=name,
                available=self.available(available_commands,
                                         allow_ws_only=allow_ws_only),
                meta=meta.at("command"),
            )

        command = available_commands[name]["spec"].normalise(
            meta.at("args"), args)

        if not allow_ws_only and command.__whirlwind_ws_only__:
            raise BadSpecValue(
                "Command is for websockets only",
                wanted=name,
                available=self.available(available_commands,
                                         allow_ws_only=allow_ws_only),
                meta=meta.at("command"),
            )

        return command, name
示例#4
0
class MemoryTarget(Target):
    """
    Knows how to talk to fake devices as if they were on the network.
    """

    devices = dictobj.Field(sb.listof(sb.any_spec()), wrapper=sb.required)
    default_broadcast = dictobj.Field(
        sb.defaulted(sb.string_spec(), "255.255.255.255"))

    session_kls = makeMemorySession(NetworkSession)
示例#5
0
class LanTarget(Target):
    """
    Knows how to talk to a device over the local network. It's one configuration
    option is default_broadcast which says what address to broadcast discovery
    if broadcast is given to run calls as True.
    """

    default_broadcast = dictobj.Field(
        sb.defaulted(sb.string_spec(), "255.255.255.255"))
    discovery_options = dictobj.Field(discovery_options_spec)

    session_kls = NetworkSession
示例#6
0
class MemoryTarget(LanTarget):
    """
    Knows how to talk to fake devices as if they were on the network.
    """

    gaps = dictobj.Field(
        Gaps(gap_between_results=0.05,
             gap_between_ack_and_res=0.05,
             timeouts=[(0.2, 0.2)]))
    io_service = dictobj.Field(sb.any_spec, default=MemoryService)
    transport_kls = dictobj.Field(sb.any_spec, default=MemoryTransport)

    devices = dictobj.Field(sb.listof(sb.any_spec()), wrapper=sb.required)
    default_broadcast = dictobj.Field(
        sb.defaulted(sb.string_spec(), "255.255.255.255"))

    session_kls = makeMemorySession(NetworkSession)
示例#7
0
    def normalise_empty(self, meta):
        env = os.environ.get("NOISY_NETWORK_LIMIT")
        if env:
            if env == "true":
                env = 2
            elif env == "null":
                env = 0
            return sb.integer_spec().normalise(meta, env)

        animation_options = sb.set_options(
            noisy_network_limit=sb.defaulted(sb.integer_spec(), 0)).normalise(
                meta,
                meta.everything.get("animation_options") or {})

        if animation_options["noisy_network_limit"]:
            return animation_options["noisy_network_limit"]

        return 0
示例#8
0
class LanTarget(Target):
    """
    Knows how to talk to a device over the local network. It's one configuration
    option is default_broadcast which says what address to broadcast discovery
    if broadcast is given to sender calls as True.
    """

    gaps = dictobj.Field(
        Gaps(
            gap_between_results=0.4,
            gap_between_ack_and_res=0.2,
            timeouts=[(0.2, 0.2), (0.1, 0.5), (0.2, 1), (1, 5)],
        ))

    default_broadcast = dictobj.Field(
        sb.defaulted(sb.string_spec(), "255.255.255.255"))
    discovery_options = dictobj.Field(discovery_options_spec)

    session_kls = NetworkSession
示例#9
0
    def normalise_filled(self, meta, val):
        options_spec = sb.set_options(
            filename=sb.required(sb.string_spec()), optional=sb.defaulted(sb.boolean(), False)
        )
        lst_spec = sb.listof(sb.or_spec(sb.string_spec(), options_spec))

        if isinstance(val, list):
            val = {"after": lst_spec.normalise(meta, val)}

        val = sb.set_options(after=lst_spec, before=lst_spec).normalise(meta, val)

        formatted = sb.formatted(sb.string_spec(), formatter=MergedOptionStringFormatter)

        for key in ("after", "before"):
            result = []

            for i, thing in enumerate(val[key]):
                filename = thing
                optional = False
                if isinstance(thing, dict):
                    filename = thing["filename"]
                    optional = thing["optional"]

                filename = formatted.normalise(meta.at(key).indexed_at(i), filename)
                if optional and not os.path.exists(filename):
                    log.warning(hp.lc("Ignoring optional configuration", filename=filename))
                    continue

                if not os.path.exists(filename):
                    raise BadConfiguration(
                        "Specified extra file doesn't exist",
                        source=self.source,
                        filename=filename,
                        meta=meta,
                    )

                result.append(filename)

            val[key] = result

        return self.extras_spec.normalise(meta, val)
示例#10
0
    it "knows about boolean":
        self.assertSignature(sb.boolean(), "boolean")

    it "knows about dictionary_spec":
        self.assertSignature(sb.dictionary_spec(), "dictionary")

    it "knows about string_choice_spec":
        self.assertSignature(sb.string_choice_spec(["one", "two"]), "choice of (one | two)")

    it "knows about optional_spec":
        self.assertSignature(sb.optional_spec(sb.integer_spec()), "integer (optional)")
        self.assertSignature(sb.optional_spec(sb.any_spec()), "(optional)")

    it "knows about defaulted":
        self.assertSignature(sb.defaulted(sb.integer_spec(), 20), "integer (default 20)")
        self.assertSignature(sb.defaulted(sb.any_spec(), True), "(default True)")

    it "knows about required":
        self.assertSignature(sb.required(sb.integer_spec()), "integer (required)")
        self.assertSignature(sb.required(sb.any_spec()), "(required)")

    it "knows about listof":
        self.assertSignature(sb.listof(sb.integer_spec()), "[ integer , ... ]")
        self.assertSignature(sb.listof(sb.any_spec()), "[ <item> , ... ]")

    it "knows about dictof":
        self.assertSignature(sb.dictof(sb.string_spec(), sb.integer_spec()), "{ string : integer }")
        self.assertSignature(sb.dictof(sb.string_spec(), sb.any_spec()), "{ string : <item> }")

    it "knows about container_spec":