Current File : //proc/self/root/usr/lib/python3/dist-packages/uaclient/entitlements/repo.py
import abc
import copy
import logging
import re
from os.path import exists
from typing import Any, Dict, List, Optional, Tuple, Union

from uaclient import (
    api,
    apt,
    contract,
    event_logger,
    exceptions,
    http,
    messages,
    secret_manager,
    system,
    util,
)
from uaclient.entitlements import base
from uaclient.entitlements.entitlement_status import (
    ApplicationStatus,
    CanDisableFailure,
    CanDisableFailureReason,
)
from uaclient.files.state_files import status_cache_file

event = event_logger.get_event_logger()
LOG = logging.getLogger(util.replace_top_level_logger_name(__name__))

# See 'What does a specific Ubuntu kernel version number mean?' in
# https://wiki.ubuntu.com/Kernel/FAQ
RE_KERNEL_PKG = r"^linux-image-([\d]+[.-][\d]+[.-][\d]+-[\d]+-[A-Za-z0-9_-]+)$"


class RepoEntitlement(base.UAEntitlement):
    repo_file_tmpl = "/etc/apt/sources.list.d/ubuntu-{name}.{extension}"
    repo_pref_file_tmpl = "/etc/apt/preferences.d/ubuntu-{name}"
    repo_url_tmpl = "{}/ubuntu"

    # The repo Origin value defined in apt metadata
    origin = None  # type: Optional[str]

    # GH: #1084 call apt in noninteractive mode
    apt_noninteractive = False

    # Check if the requested packages are installed to inform if
    # the service is enabled or not
    check_packages_are_installed = False

    # RepoEntitlements can be purged, unless specifically stated
    supports_purge = True

    # Optional repo pin priority in subclass
    @property
    def repo_pin_priority(self) -> Union[int, str, None]:
        return None

    @property
    def repo_file(self) -> str:
        extension = "sources"
        series = system.get_release_info().series
        if series in apt.SERIES_NOT_USING_DEB822:
            extension = "list"
        return self.repo_file_tmpl.format(name=self.name, extension=extension)

    @property
    def repo_policy_check_tmpl(self) -> str:
        return self.repo_url_tmpl + " {}"

    @property
    def packages(self) -> List[str]:
        """debs to install on enablement"""
        packages = []

        entitlement = self.entitlement_cfg.get("entitlement", {})

        if entitlement:
            directives = entitlement.get("directives", {})
            additional_packages = copy.copy(
                directives.get("additionalPackages", [])
            )

            packages = additional_packages

        return packages

    @property
    def apt_url(self) -> Optional[str]:
        return (
            self.entitlement_cfg.get("entitlement", {})
            .get("directives", {})
            .get("aptURL")
        )

    @property
    def snapshot_urls(self) -> List[str]:
        return (
            self.entitlement_cfg.get("entitlement", {})
            .get("directives", {})
            .get("aptSnapshotURLs", [])
        )

    @property
    def apt_suites(self) -> Optional[str]:
        return (
            self.entitlement_cfg.get("entitlement", {})
            .get("directives", {})
            .get("suites")
        )

    def get_resource_token(self) -> str:
        token = self.entitlement_cfg.get("resourceToken")
        if not token:
            machine_token = self.machine_token_file.machine_token[
                "machineToken"
            ]
            obligations = self.entitlement_cfg["entitlement"].get(
                "obligations", {}
            )
            if not obligations.get("enableByDefault"):
                # services that are not enableByDefault need to obtain specific
                # resource access for tokens. We want to refresh this every
                # enable call because it is not refreshed by `pro refresh`.
                client = contract.UAContractClient(self.cfg)
                machine_access = client.get_resource_machine_access(
                    machine_token, self.name
                )
                if machine_access:
                    token = machine_access.get("resourceToken")
            if not token:
                token = machine_token
                LOG.warning(
                    "No resourceToken present in contract for service %s."
                    " Using machine token as credentials",
                    self.title,
                )
        return token

    def _check_for_reboot(self) -> bool:
        """Check if system needs to be rebooted."""
        reboot_required = system.should_reboot(
            installed_pkgs=set(self.packages)
        )
        event.needs_reboot(reboot_required)
        return reboot_required

    @property
    @abc.abstractmethod
    def repo_key_file(self) -> str:
        pass

    def can_disable(
        self, ignore_dependent_services: bool = False
    ) -> Tuple[bool, Optional[CanDisableFailure]]:
        result, reason = super().can_disable(
            ignore_dependent_services=ignore_dependent_services
        )
        if result is False:
            return result, reason

        if not self.origin and self.purge:
            return (
                False,
                CanDisableFailure(
                    CanDisableFailureReason.NO_PURGE_WITHOUT_ORIGIN,
                    messages.REPO_PURGE_FAIL_NO_ORIGIN.format(
                        entitlement_name=self.title, title=self.title
                    ),
                ),
            )

        return result, reason

    def enable_steps(self) -> int:
        will_install = self.packages is not None and len(self.packages) > 0
        if self.access_only or not will_install:
            # 1. Configure APT
            # 2. Update APT lists
            return 2
        else:
            # 3. Install packages
            return 3

    def _perform_enable(self, progress: api.ProgressWrapper) -> bool:
        """Enable specific entitlement.

        @return: True on success, False otherwise.
        @raises: UbuntuProError on failure to install suggested packages
        """
        progress.progress(
            messages.CONFIGURING_APT_ACCESS.format(service=self.title)
        )
        self.setup_apt_config(progress)

        if self.supports_access_only and self.access_only:
            if len(self.packages) > 0:
                progress.emit(
                    "info",
                    messages.SKIPPING_INSTALLING_PACKAGES.format(
                        packages=" ".join(self.packages)
                    ),
                )
        else:
            self.install_packages(progress)
        return True

    def disable_steps(self) -> int:
        if not self.purge:
            # 1. Unconfigure APT
            # 2. Update package lists
            return 2
        else:
            # 3. Purge
            return 3

    def _perform_disable(self, progress: api.ProgressWrapper):
        if self.purge and self.origin:
            progress.emit("info", messages.PURGE_EXPERIMENTAL)
            progress.emit("info", "")

            repo_origin_packages = apt.get_installed_packages_by_origin(
                self.origin
            )

            if not self.purge_kernel_check(repo_origin_packages, progress):
                return False

            packages_to_reinstall = []
            packages_to_remove = []
            for package in repo_origin_packages:
                alternatives = apt.get_remote_versions_for_package(
                    package, exclude_origin=self.origin
                )
                if alternatives:
                    # We can call max(List[Version]) but mypy doesn't know.
                    # Or doesn't like it.
                    packages_to_reinstall.append(
                        (package, max(alternatives))  # type: ignore
                    )
                else:
                    packages_to_remove.append(package)

            if not self.prompt_for_purge(
                packages_to_remove, packages_to_reinstall, progress
            ):
                return False

        if hasattr(self, "remove_packages"):
            self.remove_packages()
        self.remove_apt_config(progress)

        if self.purge and self.origin:
            progress.progress(
                messages.PURGING_PACKAGES.format(title=self.title)
            )
            self.execute_reinstall(packages_to_reinstall)
            self.execute_removal(packages_to_remove)
        return True

    def purge_kernel_check(self, package_list, progress: api.ProgressWrapper):
        """
        Checks if the purge operation involves a kernel.

        When package called 'linux-image-*' is in the package list, warn the
        user that a kernel is being removed. Then, show the user what the
        current kernel is.

        If the current kernel is to be removed, and there are no other valid
        Ubuntu Kernels installed in the system, return False to abort the
        operation.

        If there is another Ubuntu kernel - besides the one installed - then
        prompt the user for confirmation before proceeding.
        """
        linux_image_versions = []
        for package in package_list:
            m = re.search(RE_KERNEL_PKG, package.name)
            if m:
                linux_image_versions.append(m.group(1))
        if linux_image_versions:
            # A kernel needs to be removed to purge
            # API will fail here, but we want CLI to allow it to continue
            # after a prompt
            if not progress.is_interactive():
                raise exceptions.NonInteractiveKernelPurgeDisallowed()

            progress.emit(
                "info",
                messages.PURGE_KERNEL_REMOVAL.format(service=self.title),
            )
            progress.emit("info", " ".join(linux_image_versions))

            current_kernel = system.get_kernel_info().uname_release
            progress.emit(
                "info",
                messages.PURGE_CURRENT_KERNEL.format(
                    kernel_version=current_kernel
                ),
            )

            installed_kernels = system.get_installed_ubuntu_kernels()
            # Any installed Ubuntu Kernel not being touched in this operation
            alternative_kernels = [
                version
                for version in installed_kernels
                if version not in linux_image_versions
            ]

            if not alternative_kernels:
                progress.emit("info", messages.PURGE_NO_ALTERNATIVE_KERNEL)
                return False

            progress.emit(
                "message_operation",
                [
                    (
                        util.prompt_for_confirmation,
                        {"msg": messages.PURGE_KERNEL_CONFIRMATION},
                    )
                ],
            )

        return True

    def prompt_for_purge(
        self,
        packages_to_remove,
        packages_to_reinstall,
        progress: api.ProgressWrapper,
    ):
        prompt = False
        if packages_to_remove:
            progress.emit("info", messages.WARN_PACKAGES_REMOVAL)
            progress.emit(
                "info",
                util.create_package_list_str(
                    [package.name for package in packages_to_remove]
                ),
            )
            prompt = True

        if packages_to_reinstall:
            progress.emit("info", messages.WARN_PACKAGES_REINSTALL)
            progress.emit(
                "info",
                util.create_package_list_str(
                    [package.name for (package, _) in packages_to_reinstall]
                ),
            )
            prompt = True

        if prompt:
            progress.emit(
                "message_operation",
                [
                    (
                        util.prompt_for_confirmation,
                        {"msg": messages.PROCEED_YES_NO},
                    )
                ],
            )
        return True

    def execute_removal(self, packages_to_remove):
        # We need to check again if the package is installed, because there is
        # an intermediate step between listing the packages and acting on them.
        # Some reinstalls may also uninstall dependencies.
        # Packages may be removed between those operations.
        installed_packages = apt.get_installed_packages_names()
        to_remove = [
            package.name
            for package in packages_to_remove
            if package.name in installed_packages
        ]
        if to_remove:
            apt.purge_packages(
                to_remove,
                messages.UNINSTALLING_PACKAGES_FAILED.format(
                    packages=to_remove
                ),
            )

    def execute_reinstall(self, packages_to_reinstall):
        # We need to check again if the package is installed, because there is
        # an intermediate step between listing the packages and acting on them.
        # Packages may be removed between those operations.
        installed_packages = apt.get_installed_packages_names()
        to_reinstall = [
            "{}={}".format(package.name, version.ver_str)
            for (package, version) in packages_to_reinstall
            if package.name in installed_packages
        ]
        if to_reinstall:
            apt.reinstall_packages(to_reinstall)

    def application_status(
        self,
    ) -> Tuple[ApplicationStatus, Optional[messages.NamedMessage]]:
        current_status = (
            ApplicationStatus.DISABLED,
            messages.SERVICE_NOT_CONFIGURED.format(title=self.title),
        )

        entitlement_cfg = self.entitlement_cfg
        directives = entitlement_cfg.get("entitlement", {}).get(
            "directives", {}
        )
        repo_url = directives.get("aptURL")
        if not repo_url:
            return (
                ApplicationStatus.DISABLED,
                messages.NO_APT_URL_FOR_SERVICE.format(title=self.title),
            )
        repo_suites = directives.get("suites")
        if not repo_suites:
            return (
                ApplicationStatus.DISABLED,
                messages.NO_SUITES_FOR_SERVICE.format(title=self.title),
            )

        policy = apt.get_apt_cache_policy(error_msg=messages.APT_POLICY_FAILED)
        for suite in repo_suites:
            service_match = re.search(
                self.repo_policy_check_tmpl.format(repo_url, suite), policy
            )
            if service_match:
                current_status = (
                    ApplicationStatus.ENABLED,
                    messages.SERVICE_IS_ACTIVE.format(title=self.title),
                )
                break

        if self.check_packages_are_installed:
            for package in self.packages:
                if not apt.is_installed(package):
                    return (
                        ApplicationStatus.DISABLED,
                        messages.SERVICE_DISABLED_MISSING_PACKAGE.format(
                            service=self.name, package=package
                        ),
                    )

        return current_status

    def _check_apt_url_is_applied(self, apt_url):
        """Check if apt url delta should be applied.

        :param apt_url: string containing the apt url to be used.

        :return: False if apt url is already found on the source file.
                 True otherwise.
        """
        apt_file = self.repo_file
        # If the apt file is commented out, we will assume that we need
        # to regenerate the apt file, regardless of the apt url delta
        if all(
            line.startswith("#")
            for line in system.load_file(apt_file).strip().split("\n")
        ):
            return False

        # If the file is not commented out and we don't have delta,
        # we will not do anything
        if not apt_url:
            return True

        # If the delta is already in the file, we won't reconfigure it
        # again
        return bool(apt_url in system.load_file(apt_file))

    def process_contract_deltas(
        self,
        orig_access: Dict[str, Any],
        deltas: Dict[str, Any],
        allow_enable: bool = False,
    ) -> bool:
        """Process any contract access deltas for this entitlement.

        :param orig_access: Dictionary containing the original
            resourceEntitlement access details.
        :param deltas: Dictionary which contains only the changed access keys
        and values.
        :param allow_enable: Boolean set True if allowed to perform the enable
            operation. When False, a message will be logged to inform the user
            about the recommended enabled service.

        :return: True when delta operations are processed; False when noop.
        """
        if super().process_contract_deltas(orig_access, deltas, allow_enable):
            return True  # Already processed parent class deltas

        delta_entitlement = deltas.get("entitlement", {})
        delta_directives = delta_entitlement.get("directives", {})
        delta_apt_url = delta_directives.get("aptURL")
        delta_packages = delta_directives.get("additionalPackages")
        status_cache = status_cache_file.read()

        if delta_directives and status_cache:
            application_status = self._check_application_status_on_cache()
        else:
            application_status, _ = self.application_status()

        if application_status == ApplicationStatus.DISABLED:
            return False

        if not self._check_apt_url_is_applied(delta_apt_url):
            LOG.info(
                "New aptURL, updating %s apt sources list to %s",
                self.name,
                delta_apt_url,
            )
            event.info(
                messages.REPO_UPDATING_APT_SOURCES.format(service=self.name)
            )

            orig_entitlement = orig_access.get("entitlement", {})
            old_url = orig_entitlement.get("directives", {}).get("aptURL")
            if old_url:
                # Remove original aptURL and auth and rewrite
                apt.remove_auth_apt_repo(
                    self.repo_file, old_url, self.snapshot_urls
                )

            self.remove_apt_config(api.ProgressWrapper())
            self.setup_apt_config(api.ProgressWrapper())

        if delta_packages:
            LOG.info("New additionalPackages, installing %r", delta_packages)
            event.info(
                messages.REPO_REFRESH_INSTALLING_PACKAGES.format(
                    packages=", ".join(delta_packages)
                )
            )
            self.install_packages(
                api.ProgressWrapper(), package_list=delta_packages
            )

        return True

    def install_packages(
        self,
        progress: api.ProgressWrapper,
        package_list: Optional[List[str]] = None,
        cleanup_on_failure: bool = True,
    ) -> None:
        """Install contract recommended packages for the entitlement.

        :param package_list: Optional package list to use instead of
            self.packages.
        :param cleanup_on_failure: Cleanup apt files if apt install fails.
        """

        if not package_list:
            package_list = self.packages

        if not package_list:
            return

        progress.emit("message_operation", self.messaging.get("pre_install"))

        try:
            self._update_sources_list(progress)
        except exceptions.UbuntuProError:
            if cleanup_on_failure:
                self.remove_apt_config(api.ProgressWrapper())
            raise

        progress.progress(
            messages.INSTALLING_SERVICE_PACKAGES.format(title=self.title)
        )

        if self.apt_noninteractive:
            override_env_vars = {"DEBIAN_FRONTEND": "noninteractive"}
            apt_options = [
                "--allow-downgrades",
                '-o Dpkg::Options::="--force-confdef"',
                '-o Dpkg::Options::="--force-confold"',
            ]
        else:
            override_env_vars = None
            apt_options = []

        try:
            apt.run_apt_install_command(
                packages=package_list,
                apt_options=apt_options,
                override_env_vars=override_env_vars,
            )
        except exceptions.UbuntuProError:
            if cleanup_on_failure:
                LOG.info(
                    "Apt install failed, removing apt config for {}".format(
                        self.name
                    )
                )
                self.remove_apt_config(api.ProgressWrapper())
            raise

    def setup_apt_config(self, progress: api.ProgressWrapper) -> None:
        """Setup apt config based on the resourceToken and directives.
        Also sets up apt proxy if necessary.

        :raise UbuntuProError: on failure to setup any aspect of this apt
           configuration
        """
        http_proxy = None  # type: Optional[str]
        https_proxy = None  # type: Optional[str]
        scope = None  # type: Optional[apt.AptProxyScope]
        if self.cfg.global_apt_http_proxy or self.cfg.global_apt_https_proxy:
            http_proxy = http.validate_proxy(
                "http",
                self.cfg.global_apt_http_proxy,
                http.PROXY_VALIDATION_APT_HTTP_URL,
            )
            https_proxy = http.validate_proxy(
                "https",
                self.cfg.global_apt_https_proxy,
                http.PROXY_VALIDATION_APT_HTTPS_URL,
            )
            scope = apt.AptProxyScope.GLOBAL
        elif self.cfg.ua_apt_http_proxy or self.cfg.ua_apt_https_proxy:
            http_proxy = http.validate_proxy(
                "http",
                self.cfg.ua_apt_http_proxy,
                http.PROXY_VALIDATION_APT_HTTP_URL,
            )
            https_proxy = http.validate_proxy(
                "https",
                self.cfg.ua_apt_https_proxy,
                http.PROXY_VALIDATION_APT_HTTPS_URL,
            )
            scope = apt.AptProxyScope.UACLIENT

        apt.setup_apt_proxy(
            http_proxy=http_proxy, https_proxy=https_proxy, proxy_scope=scope
        )
        repo_filename = self.repo_file
        resource_cfg = self.entitlement_cfg
        directives = resource_cfg["entitlement"].get("directives", {})
        token = self.get_resource_token()
        aptKey = directives.get("aptKey")
        if not aptKey:
            raise exceptions.RepoNoAptKey(entitlement_name=self.name)
        repo_url = directives.get("aptURL")
        if not repo_url:
            raise exceptions.MissingAptURLDirective(entitlement_name=self.name)
        repo_suites = directives.get("suites")
        if not repo_suites:
            raise exceptions.RepoNoSuites(entitlement_name=self.name)
        if self.repo_pin_priority:
            if not self.origin:
                raise exceptions.RepoPinFailNoOrigin(
                    entitlement_name=self.name,
                    title=self.title,
                )
            repo_pref_file = self.repo_pref_file_tmpl.format(name=self.name)
            apt.add_ppa_pinning(
                repo_pref_file,
                repo_url,
                self.origin,
                self.repo_pin_priority,
            )

        prerequisite_pkgs = []
        if not exists(apt.APT_METHOD_HTTPS_FILE):
            prerequisite_pkgs.append("apt-transport-https")
        if not exists(apt.CA_CERTIFICATES_FILE):
            prerequisite_pkgs.append("ca-certificates")

        if prerequisite_pkgs:
            progress.emit(
                "info",
                messages.INSTALLING_PACKAGES.format(
                    packages=", ".join(prerequisite_pkgs)
                ),
            )
            try:
                apt.run_apt_install_command(packages=prerequisite_pkgs)
            except exceptions.UbuntuProError:
                self.remove_apt_config(api.ProgressWrapper())
                raise
        apt.add_auth_apt_repo(
            repo_filename,
            self.repo_url_tmpl.format(repo_url),
            token,
            repo_suites,
            self.repo_key_file,
            self.snapshot_urls,
        )
        # Run apt-update on any repo-entitlement enable because the machine
        # probably wants access to the repo that was just enabled.
        # Side-effect is that apt policy will now report the repo as accessible
        # which allows pro status to report correct info
        progress.progress(messages.APT_UPDATING_LIST.format(name=self.title))
        try:
            apt.update_sources_list(repo_filename)
        except exceptions.UbuntuProError:
            self.remove_apt_config(api.ProgressWrapper(), run_apt_update=False)
            raise

    def update_apt_auth(
        self, override_snapshot_urls: Optional[List[str]] = None
    ):
        if override_snapshot_urls is not None:
            snapshot_urls = override_snapshot_urls
        else:
            snapshot_urls = self.snapshot_urls
        credentials = self.get_resource_token()
        repo_url = (
            self.entitlement_cfg.get("entitlement", {})
            .get("directives", {})
            .get("aptURL")
        )
        repo_url = self.repo_url_tmpl.format(repo_url)
        try:
            username, password = credentials.split(":")
        except ValueError:  # Then we have a bearer token
            username = "bearer"
            password = credentials
        secret_manager.secrets.add_secret(password)
        for url in [repo_url] + snapshot_urls:
            if url:
                apt.add_apt_auth_conf_entry(url, username, password)

    def remove_apt_config(
        self,
        progress: api.ProgressWrapper,
        run_apt_update: bool = True,
    ):
        """Remove any repository apt configuration files.

        :param run_apt_update: If after removing the apt update
            command after removing the apt files.
        """
        series = system.get_release_info().series
        repo_filename = self.repo_file
        entitlement = self.machine_token_file.entitlements()[self.name].get(
            "entitlement", {}
        )
        access_directives = entitlement.get("directives", {})
        repo_url = access_directives.get("aptURL")
        if not repo_url:
            raise exceptions.MissingAptURLDirective(entitlement_name=self.name)

        repo_url = self.repo_url_tmpl.format(repo_url)

        progress.progress(
            messages.REMOVING_APT_CONFIGURATION.format(title=self.title)
        )
        apt.remove_auth_apt_repo(
            repo_filename, repo_url, self.snapshot_urls, self.repo_key_file
        )
        apt.remove_apt_list_files(repo_url, series)

        if self.repo_pin_priority:
            repo_pref_file = self.repo_pref_file_tmpl.format(name=self.name)
            system.ensure_file_absent(repo_pref_file)

        if run_apt_update:
            progress.progress(messages.APT_UPDATING_LISTS)
            apt.run_apt_update_command()
¿Qué es la limpieza dental de perros? - Clínica veterinaria


Es la eliminación del sarro y la placa adherida a la superficie de los dientes mediante un equipo de ultrasonidos que garantiza la integridad de las piezas dentales a la vez que elimina en profundidad cualquier resto de suciedad.

A continuación se procede al pulido de los dientes mediante una fresa especial que elimina la placa bacteriana y devuelve a los dientes el aspecto sano que deben tener.

Una vez terminado todo el proceso, se mantiene al perro en observación hasta que se despierta de la anestesia, bajo la atenta supervisión de un veterinario.

¿Cada cuánto tiempo tengo que hacerle una limpieza dental a mi perro?

A partir de cierta edad, los perros pueden necesitar una limpieza dental anual o bianual. Depende de cada caso. En líneas generales, puede decirse que los perros de razas pequeñas suelen acumular más sarro y suelen necesitar una atención mayor en cuanto a higiene dental.


Riesgos de una mala higiene


Los riesgos más evidentes de una mala higiene dental en los perros son los siguientes:

  • Cuando la acumulación de sarro no se trata, se puede producir una inflamación y retracción de las encías que puede descalzar el diente y provocar caídas.
  • Mal aliento (halitosis).
  • Sarro perros
  • Puede ir a más
  • Las bacterias de la placa pueden trasladarse a través del torrente circulatorio a órganos vitales como el corazón ocasionando problemas de endocarditis en las válvulas. Las bacterias pueden incluso acantonarse en huesos (La osteomielitis es la infección ósea, tanto cortical como medular) provocando mucho dolor y una artritis séptica).

¿Cómo se forma el sarro?

El sarro es la calcificación de la placa dental. Los restos de alimentos, junto con las bacterias presentes en la boca, van a formar la placa bacteriana o placa dental. Si la placa no se retira, al mezclarse con la saliva y los minerales presentes en ella, reaccionará formando una costra. La placa se calcifica y se forma el sarro.

El sarro, cuando se forma, es de color blanquecino pero a medida que pasa el tiempo se va poniendo amarillo y luego marrón.

Síntomas de una pobre higiene dental
La señal más obvia de una mala salud dental canina es el mal aliento.

Sin embargo, a veces no es tan fácil de detectar
Y hay perros que no se dejan abrir la boca por su dueño. Por ejemplo…

Recientemente nos trajeron a la clínica a un perro que parpadeaba de un ojo y decía su dueño que le picaba un lado de la cara. Tenía molestias y dificultad para comer, lo que había llevado a sus dueños a comprarle comida blanda (que suele ser un poco más cara y llevar más contenido en grasa) durante medio año. Después de una exploración oftalmológica, nos dimos cuenta de que el ojo tenía una úlcera en la córnea probablemente de rascarse . Además, el canto lateral del ojo estaba inflamado. Tenía lo que en humanos llamamos flemón pero como era un perro de pelo largo, no se le notaba a simple vista. Al abrirle la boca nos llamó la atención el ver una muela llena de sarro. Le realizamos una radiografía y encontramos una fístula que llegaba hasta la parte inferior del ojo.

Le tuvimos que extraer la muela. Tras esto, el ojo se curó completamente con unos colirios y una lentilla protectora de úlcera. Afortunadamente, la úlcera no profundizó y no perforó el ojo. Ahora el perro come perfectamente a pesar de haber perdido una muela.

¿Cómo mantener la higiene dental de tu perro?
Hay varias maneras de prevenir problemas derivados de la salud dental de tu perro.

Limpiezas de dientes en casa
Es recomendable limpiar los dientes de tu perro semanal o diariamente si se puede. Existe una gran variedad de productos que se pueden utilizar:

Pastas de dientes.
Cepillos de dientes o dedales para el dedo índice, que hacen más fácil la limpieza.
Colutorios para echar en agua de bebida o directamente sobre el diente en líquido o en spray.

En la Clínica Tus Veterinarios enseñamos a nuestros clientes a tomar el hábito de limpiar los dientes de sus perros desde que son cachorros. Esto responde a nuestro compromiso con la prevención de enfermedades caninas.

Hoy en día tenemos muchos clientes que limpian los dientes todos los días a su mascota, y como resultado, se ahorran el dinero de hacer limpiezas dentales profesionales y consiguen una mejor salud de su perro.


Limpiezas dentales profesionales de perros y gatos

Recomendamos hacer una limpieza dental especializada anualmente. La realizamos con un aparato de ultrasonidos que utiliza agua para quitar el sarro. Después, procedemos a pulir los dientes con un cepillo de alta velocidad y una pasta especial. Hacemos esto para proteger el esmalte.

La frecuencia de limpiezas dentales necesaria varía mucho entre razas. En general, las razas grandes tienen buena calidad de esmalte, por lo que no necesitan hacerlo tan a menudo e incluso pueden pasarse la vida sin requerir una limpieza. Sin embargo, razas pequeñas como el Yorkshire o el Maltés, deben hacérselas todos los años desde cachorros si se quiere conservar sus piezas dentales.

Otro factor fundamental es la calidad del pienso. Algunas marcas han diseñado croquetas que limpian la superficie del diente y de la muela al masticarse.

Ultrasonido para perros

¿Se necesita anestesia para las limpiezas dentales de perros y gatos?

La limpieza dental en perros no es una técnica que pueda practicarse sin anestesia general , aunque hay veces que los propietarios no quieren anestesiar y si tiene poco sarro y el perro es muy bueno se puede intentar…… , pero no se va a poder pulir ni acceder a todas la zona de la boca …. Además los limpiadores dentales van a irrigar agua y hay riesgo de aspiración a vías respiratorias si no se realiza una anestesia correcta con intubación traqueal . En resumen , sin anestesia no se va hacer una correcta limpieza dental.

Tampoco sirve la sedación ya que necesitamos que el animal esté totalmente quieto, y el veterinario tenga un acceso completo a todas sus piezas dentales y encías.

Alimentos para la limpieza dental

Hay que tener cierto cuidado a la hora de comprar determinados alimentos porque no todos son saludables. Algunos tienen demasiado contenido graso, que en exceso puede causar problemas cardiovasculares y obesidad.

Los mejores alimentos para los dientes son aquellos que están elaborados por empresas farmacéuticas y llevan componentes químicos con tratamientos específicos para el diente del perro. Esto implica no solo limpieza a través de la acción mecánica de morder sino también un tratamiento antibacteriano para prevenir el sarro.

Conclusión

Si eres como la mayoría de dueños, por falta de tiempo , es probable que no estés prestando la suficiente atención a la limpieza dental de tu perro. Por eso te animamos a que comiences a limpiar los dientes de tu perro y consideres atender a su higiene bucal con frecuencia.

Estas simples medidas pueden conllevar a que tu perro tenga una vida más larga y mucho más saludable.

Si te resulta imposible introducir un cepillo de dientes a tu perro en la boca, pásate con él por clínica Tus Veterinarios y te explicamos cómo hacerlo.

Necesitas hacer una limpieza dental profesional a tu mascota?
Llámanos al 622575274 o contacta con nosotros

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

¡Hola!