def handle(self, *args, dry_run=False, **options):
        remote_settings = RemoteSettings()

        local_recipes = Recipe.objects.filter(
            approved_revision__enabled_state__enabled=True)
        remote_records = remote_settings.published_recipes()

        # Compare the two sets: local recipes that are missing remotely will
        # be published, recipes that differ will be updated, and recipes that
        # are only on the remote server will be unpublished.
        to_publish = []
        to_update = []
        local_by_id = {str(r.id): r for r in local_recipes}
        remote_by_id = {r["id"]: r for r in remote_records}
        for rid, local_recipe in local_by_id.items():
            if rid in remote_by_id:
                remote_record = remote_by_id.pop(rid)
                if not compare_remote(local_recipe, remote_record):
                    to_update.append(local_recipe)
            else:
                to_publish.append(local_recipe)
        # Lookup locally the recipes that are published but should not.
        to_unpublish = []
        for rid in remote_by_id.keys():
            try:
                to_unpublish.append(Recipe.objects.get(id=rid))
            except Recipe.DoesNotExist:
                to_unpublish.append(Recipe(id=rid))

        # If there is nothing to do, exit.
        if not to_publish and not to_update and not to_unpublish:
            self.stdout.write(self.style.SUCCESS("Sync OK. Nothing to do."))
            return

        # Show differences on stdout, and un/publish if not dry-run.
        style = self.style.SUCCESS if not to_publish else self.style.MIGRATE_LABEL
        self.stdout.write(style(f"{len(to_publish)} recipes to publish:"))
        for r in to_publish:
            self.stdout.write(f" * {r.approved_revision.name!r} (id={r.id!r})")
            if not dry_run:
                remote_settings.publish(r)

        style = self.style.SUCCESS if not to_update else self.style.MIGRATE_LABEL
        self.stdout.write(style(f"{len(to_update)} recipes to update:"))
        for r in to_update:
            self.stdout.write(f" * {r.approved_revision.name!r} (id={r.id!r})")
            if not dry_run:
                remote_settings.publish(r)

        style = self.style.SUCCESS if not to_unpublish else self.style.MIGRATE_LABEL
        self.stdout.write(style(f"{len(to_unpublish)} recipes to unpublish:"))
        for r in to_unpublish:
            name = (r.approved_revision.name if r.approved_revision else
                    self.style.WARNING("Unknown locally"))
            self.stdout.write(f" * {name!r} (id={r.id!r})")
            if not dry_run:
                remote_settings.unpublish(r)
Exemple #2
0
    def disable(self, user):
        if not self.enabled:
            raise EnabledState.NotActionable(
                "This revision is already disabled.")

        self._create_new_enabled_state(creator=user, enabled=False)

        RemoteSettings().unpublish(self.recipe)
    def handle(self, *args, dry_run=False, **options):
        remote_settings = RemoteSettings()

        local_recipes = Recipe.objects.filter(approved_revision__enabled_state__enabled=True)
        remote_records = remote_settings.published_recipes()

        # Compare the two sets: local recipes that are missing remotely will
        # be published, recipes that differ will be updated, and recipes that
        # are only on the remote server will be unpublished.
        to_publish = []
        to_update = []
        local_by_id = {str(r.id): r for r in local_recipes}
        remote_by_id = {r["id"]: r for r in remote_records}
        for rid, local_recipe in local_by_id.items():
            if rid in remote_by_id:
                remote_record = remote_by_id.pop(rid)
                if not compare_remote(local_recipe, remote_record):
                    to_update.append(local_recipe)
            else:
                to_publish.append(local_recipe)
        # Lookup locally the recipes that are published but should not.
        to_unpublish = []
        for rid in remote_by_id.keys():
            try:
                to_unpublish.append(Recipe.objects.get(id=rid))
            except Recipe.DoesNotExist:
                to_unpublish.append(Recipe(id=rid))

        # If there is nothing to do, exit.
        if not to_publish and not to_update and not to_unpublish:
            self.stdout.write(self.style.SUCCESS("Sync OK. Nothing to do."))
            return

        # Show differences on stdout, and un/publish if not dry-run.
        style = self.style.SUCCESS if not to_publish else self.style.MIGRATE_LABEL
        self.stdout.write(style(f"{len(to_publish)} recipes to publish:"))
        for r in to_publish:
            self.stdout.write(f" * {r.name!r} (id={r.id!r})")
            if not dry_run:
                remote_settings.publish(r)

        style = self.style.SUCCESS if not to_update else self.style.MIGRATE_LABEL
        self.stdout.write(style(f"{len(to_update)} recipes to update:"))
        for r in to_update:
            self.stdout.write(f" * {r.name!r} (id={r.id!r})")
            if not dry_run:
                remote_settings.publish(r)

        style = self.style.SUCCESS if not to_unpublish else self.style.MIGRATE_LABEL
        self.stdout.write(style(f"{len(to_unpublish)} recipes to unpublish:"))
        for r in to_unpublish:
            name = r.name if r.name else self.style.WARNING("Unknown locally")
            self.stdout.write(f" * {name!r} (id={r.id!r})")
            if not dry_run:
                remote_settings.unpublish(r)
Exemple #4
0
    def enable(self, user, carryover_from=None):
        if self.enabled:
            raise EnabledState.NotActionable(
                "This revision is already enabled.")

        self._create_new_enabled_state(creator=user,
                                       enabled=True,
                                       carryover_from=carryover_from)

        RemoteSettings().publish(self.recipe)
Exemple #5
0
    def enable(self, user, carryover_from=None):
        if self.enabled:
            raise EnabledState.NotActionable(
                "This revision is already enabled.")

        self._validate_preference_rollout_rollback_enabled_invariance()

        self._create_new_enabled_state(creator=user,
                                       enabled=True,
                                       carryover_from=carryover_from)

        RemoteSettings().publish(self.recipe)
    def handle(self, *args, force=False, **options):
        remote_settings = RemoteSettings()

        if force:
            recipes_to_update = Recipe.objects.only_enabled()
        else:
            recipes_to_update = self.get_outdated_recipes()

        count = recipes_to_update.count()
        if count == 0:
            self.stdout.write("No out of date recipes to sign")
        else:
            self.stdout.write(f"Signing {count} recipes:")
            for recipe in recipes_to_update:
                self.stdout.write(" * " + recipe.approved_revision.name)
                recipe.update_signature()
                recipe.save()
                remote_settings.publish(recipe, approve_changes=False)
            # Approve all Remote Settings changes.
            remote_settings.approve_changes()

        metrics.gauge("signed", count, tags=["force"] if force else [])

        recipes_to_unsign = Recipe.objects.only_disabled().exclude(
            signature=None)
        count = recipes_to_unsign.count()
        if count == 0:
            self.stdout.write("No disabled recipes to unsign")
        else:
            self.stdout.write(f"Unsigning {count} disabled recipes:")
            for recipe in recipes_to_unsign:
                self.stdout.write(" * " + recipe.approved_revision.name)
                sig = recipe.signature
                recipe.signature = None
                recipe.save()
                sig.delete()

        metrics.gauge("unsigned", count, tags=["force"] if force else [])
        self.stdout.write("all signing done")
Exemple #7
0
 def ready(self):
     checks.register()
     RemoteSettings().check_config()
     load_geoip_database()