Beispiel #1
0
def test_two_packages(request) -> ["Package"]:
    yield [
        Package(
            "Firefox",
            Package.str_to_version(request.param[0]),
            Catalog.TESTING,
            datetime.strptime("10:05:55 01.01.2020", "%H:%M:%S %d.%m.%Y"),
            JiraAutopromote.NOPROMOTE,
            Present.PRESENT,
            JiraBoardProvider,
            "SWPM-7859",
            JiraLane.TESTING,
            PackageState.NEW,
        ),
        Package(
            "Firefox",
            Package.str_to_version(request.param[1]),
            Catalog.TESTING,
            datetime.strptime("10:05:55 01.01.2020", "%H:%M:%S %d.%m.%Y"),
            JiraAutopromote.NOPROMOTE,
            Present.PRESENT,
            JiraBoardProvider,
            "SWPM-7859",
            JiraLane.TESTING,
            PackageState.NEW,
        ),
    ]
Beispiel #2
0
def random_package() -> Package:
    yield Package(
        name=get_random_string(10),
        version=Package.str_to_version(str(random.uniform(0, 100))),
        catalog=Catalog(random.choices([e.value for e in Catalog])[0]),
        promote_date=datetime.now(),
        is_autopromote=JiraAutopromote(
            random.choices([e.value for e in JiraAutopromote])[0]),
        is_present=Present(random.choices([e.value for e in Present])[0]),
        provider=JiraBoardProvider,
        jira_id=get_random_string(9),
        jira_lane=JiraLane(random.choices([e.value for e in JiraLane])[0]),
        state=PackageState(random.choices([e.value for e in PackageState])[0]),
    )
Beispiel #3
0
    def _jira_issue_to_package(self, issue: Issue) -> Package:
        """
        Converts a given issue into a `Package` object. Before converting the
        issue is verified to contain
        all needed fields. In case the package is missing certain fields defined
        in `conf.ISSUE_FIELDS`,
        `JiraIssueMissingFields` is raised.

        :param issue: The jira issue converted to a `Package`
        :return: `Package` representing the issue
        """
        fields_dict = issue.fields.__dict__  # type: dict

        if all(field in fields_dict for field in conf.ISSUE_FIELDS):
            # Before we try to get all fields from our issue we check, whether
            # all fields are present as keys

            if fields_dict.get(conf.JIRA_PRESENT_FIELD):
                is_present = Present(
                    fields_dict.get(conf.JIRA_PRESENT_FIELD)[0].id)
            else:
                is_present = Present(None)

            p = Package(
                name=fields_dict.get(conf.JIRA_SOFTWARE_NAME_FIELD),
                version=Package.str_to_version(
                    fields_dict.get(conf.JIRA_SOFTWARE_VERSION_FIELD)),
                catalog=Catalog(fields_dict.get(conf.JIRA_CATALOG_FIELD).id),
                promote_date=datetime.strptime(
                    fields_dict.get(conf.JIRA_DUEDATE_FIELD), "%Y-%m-%d"),
                is_autopromote=JiraAutopromote(
                    fields_dict.get(conf.JIRA_AUTOPROMOTE_FIELD).id),
                is_present=is_present,
                provider=JiraBoardProvider,
                jira_id=issue.key,
                jira_lane=JiraLane(fields_dict.get("status").name),
                state=PackageState.DEFAULT,
                munki_uuid=None,
            )

            return p
        else:
            raise JiraIssueMissingFields()
Beispiel #4
0
 def test_ignored_compare_keys(self):
     """
     Tests the values of the ignored keys.
     """
     assert [
         "promote_date",
         "jira_id",
         "munki_uuid",
         "provider",
         "state",
     ] == Package.ignored_compare_keys()
Beispiel #5
0
    def _lane_promotions(self):
        """
        If a jira package is in a promotion lane (TO_*CATALOG*), it is moved to
        the appropriate catalog (*CATALOG*).
        Additionally the respective munki package is searched and updated
        according to the jira package. If the munki package does not exist in
        the munki_repository it is marked as missing in jira.
        """
        for jira_pkg in self.jira_pkgs_dict.values():
            if jira_pkg.jira_lane.is_promotion_lane:
                # Pkg is in a promotion lane
                jira_pkg.catalog = Catalog.str_to_catalog(
                    jira_pkg.jira_lane.name.replace("TO_", "")
                )

                logger.debug(
                    f"Package {jira_pkg} in promotion lane. Promoting to "
                    f"{jira_pkg.catalog}"
                )

                jira_pkg.state = PackageState.UPDATE
                jira_pkg.promote_date = datetime.now()
                jira_pkg.jira_lane = JiraLane.catalog_to_lane(jira_pkg.catalog)
            elif jira_pkg.jira_lane != JiraLane.catalog_to_lane(
                jira_pkg.catalog
            ):
                logger.debug(
                    f"Catalog and JiraLane Missmatch for package {jira_pkg}. "
                    f"Resetting catalog."
                )
                jira_pkg.catalog = Catalog.jira_lane_to_catalog(
                    jira_pkg.jira_lane
                )
                jira_pkg.state = PackageState.UPDATE

            munki_package = self.munki_pkgs_dict.get(jira_pkg.key)
            if munki_package and munki_package != jira_pkg:
                for key, value in jira_pkg.__dict__.items():
                    if key not in Package.ignored_compare_keys():
                        if munki_package.__dict__.get(key) != value:
                            # Not all values of the existing jira ticket and the
                            # local version match. Therefore update.
                            logger.debug(
                                f"Updating munki pkg {munki_package} values as"
                                f" {key} do not match: "
                                f"{munki_package.__dict__.get(key)} != {value}"
                            )
                            munki_package.state = PackageState.UPDATE
                            setattr(munki_package, key, value)
            else:
                jira_pkg.present = Present.MISSING

            self.jira_pkgs_dict.update({jira_pkg.key: jira_pkg})
Beispiel #6
0
    def test_package_equality(self):
        """Identical packages should be equal."""
        p1 = Package(
            "Firefox",
            Package.str_to_version("61.3.5"),
            Catalog.TESTING,
            datetime.strptime("10:05:55 01.01.2020", "%H:%M:%S %d.%m.%Y"),
            JiraAutopromote.NOPROMOTE,
            Present.PRESENT,
            JiraBoardProvider,
            "SWPM-4556",
            JiraLane.TESTING,
        )

        p2 = Package(
            "Firefox",
            Package.str_to_version("61.3.5"),
            Catalog.TESTING,
            datetime.strptime("10:05:55 01.01.2020", "%H:%M:%S %d.%m.%Y"),
            JiraAutopromote.NOPROMOTE,
            Present.PRESENT,
            JiraBoardProvider,
            "SWPM-4556",
            JiraLane.TESTING,
        )

        assert p1 == p2

        p2.name = "Matlab"

        assert p1 != p2
Beispiel #7
0
    def update(self, package: Package):
        """
        Searches for a package in munki and updates it according to the package
        given in the argument.
        If no munki package exists matching the given package it is labeled as
        missing.

        :param package: `Package` object to be updated in the munki repo
        """
        # make a deep copy of the package to prevent changes in other instances
        package_copy = copy.deepcopy(package)

        if package.key not in self._packages_dict:
            # The package is not present in the Munki repo therefore it must be
            # missing locally also update the referenced package such that jira
            # will be informed
            package.state = PackageState.UPDATE
            package.is_present = Present.MISSING
            # the package is new for the munki repo
            package_copy.state = PackageState.NEW

            self._packages_dict.update({package_copy.key: package_copy})
            return

        p = self._packages_dict.get(package_copy.key)

        for key, value in package_copy.__dict__.items():
            if (key != "promote_date" and key != "jira_id"
                    and key != "munki_uuid" and key != "provider"):
                if p.__dict__.get(key) != value:
                    # Not all values of the existing jira ticket and the local
                    # version match. Therefore update.
                    package_copy.state = PackageState.UPDATE
                    self._packages_dict.update(
                        {package_copy.key: package_copy})
                    return
        logger.debug(
            f"Munki update called for {package}, but no changes detected.")
Beispiel #8
0
    def update(self, package: Package):
        """
        Searches for a package in jira and updates it according to the package
        given in the argument.
        If no jira issue exists matching the given package it is created.

        To prevent `PackageState` changes in propagating to other `Provider`
        instances a deepcopy is created at the
        beginning of the method.

        In case the package already exists we can check if we need to update
        certain values. In this case the
        `PackageState` is set to `PackageState.UPDATE`.

        Otherwise if we want to create a new one the state is set to
        `PackageState.NEW`.

        :param package: `Package` object to be written to jira
        """
        package = copy.deepcopy(package)
        if JiraBoardProvider.check_jira_issue_exists(package):
            # Ticket with this id already exists.
            p = self._packages_dict.get(package.key)

            for key, value in package.__dict__.items():
                if p.__dict__.get(key) != value:
                    # Not all values of the existing jira ticket and the local
                    # version match. Therefore update.
                    p.state = PackageState.UPDATE
                    # Replace original package with updated package
                    self._packages_dict.update({p.key: package})
                    return
            logger.debug(
                f"Jira update called for {package}, but no changes detected.")
        else:
            package.state = PackageState.NEW
            if package.key not in self._packages_dict:
                logger.debug(f"Creating new jira ticket for {package}")
                self._packages_dict.update({package.key: package})
Beispiel #9
0
    def _load_packages(self):
        """
        Loads all available munki packages as a `Dict` of `Package` by
        converting the information of all plists from the munki repository.
        Each key for which there is no information in the plist is set to the
        default value.
        """
        logger.debug(f"Loading packages from repo: {conf.REPO_PATH}")
        # clear internal packages dict, before loading for the first time OR
        # again
        self._packages_dict.clear()
        for filename in os.listdir(conf.CATALOGS_PATH):
            if not (filename.startswith(".") or filename == "all"):
                # Ignore hidden files
                munki_packages = plistlib.load(
                    open(os.path.join(conf.CATALOGS_PATH, filename), "rb"))

                for item in munki_packages:
                    try:
                        # If we find something like this in our pkginfo we will
                        # use the provided information instead
                        # Otherwise fallback to default values.
                        # <key>munkipromote</key>
                        # 	<dict>
                        # 		<key>promotiondate</key>
                        # 		<string>2019-07-16</string>
                        # 		<key>autopromote</key>
                        # 		<true/>
                        # 	</dict>

                        promote_info = item.get("munkipromote")
                        if promote_info and "promotiondate" in promote_info:
                            promotion_date = datetime.strptime(
                                promote_info.get("promotiondate"), "%Y-%m-%d")
                        else:
                            promotion_date = datetime.now() + timedelta(
                                days=conf.DEFAULT_PROMOTION_INTERVAL)

                        if promote_info and "autopromote" in promote_info:
                            if promote_info.get("autopromote"):
                                autopromote = JiraAutopromote.PROMOTE
                            else:
                                autopromote = JiraAutopromote.NOPROMOTE
                        else:
                            autopromote = JiraAutopromote.PROMOTE

                        if len(item.get("catalogs")) > 1:
                            raise MunkiItemInMultipleCatalogs(item)
                        else:
                            item_catalog = Catalog.str_to_catalog(
                                item.get("catalogs")[0])

                        p = Package(
                            name=item.get("name"),
                            version=item.get("version"),
                            catalog=item_catalog,
                            promote_date=promotion_date,
                            is_autopromote=autopromote,
                            is_present=Present.PRESENT,
                            provider=MunkiRepoProvider,
                            jira_id=None,
                            jira_lane=JiraLane.catalog_to_lane(item_catalog),
                            state=PackageState.DEFAULT,
                            munki_uuid=uuid4(),
                        )

                        self._packages_dict.update({p.key: p})
                    except MunkiItemInMultipleCatalogs as e:
                        logger.error(e)
Beispiel #10
0
 def test_str_to_version(self, version):
     """
     Tests the conversion of `Package.str_to_version`
     :param version: `str` version
     """
     assert isinstance(Package.str_to_version(version), PackageVersion)