Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,10 @@ coverage:
target: 75
flags:
- kyototycoon
LPARStats:
target: 75
flags:
- lparstats
Lighttpd:
target: 75
flags:
Expand Down Expand Up @@ -1408,6 +1412,11 @@ flags:
paths:
- kyverno/datadog_checks/kyverno
- kyverno/tests
lparstats:
carryforward: true
paths:
- lparstats/datadog_checks/lparstats
- lparstats/tests
lighttpd:
carryforward: true
paths:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/config/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,10 @@ integration/langchain:
- changed-files:
- any-glob-to-any-file:
- langchain/**/*
integration/lparstats:
- changed-files:
- any-glob-to-any-file:
- lparstats/**/*
integration/lastpass:
- changed-files:
- any-glob-to-any-file:
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/test-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2457,6 +2457,26 @@ jobs:
minimum-base-package: ${{ inputs.minimum-base-package }}
pytest-args: ${{ inputs.pytest-args }}
secrets: inherit
jefcf576:
uses: ./.github/workflows/test-target.yml
with:
job-name: LPARStats
target: lparstats
platform: linux
runner: '["ubuntu-22.04"]'
repo: "${{ inputs.repo }}"
context: ${{ inputs.context }}
python-version: "${{ inputs.python-version }}"
latest: ${{ inputs.latest }}
agent-image: "${{ inputs.agent-image }}"
agent-image-py2: "${{ inputs.agent-image-py2 }}"
agent-image-windows: "${{ inputs.agent-image-windows }}"
agent-image-windows-py2: "${{ inputs.agent-image-windows-py2 }}"
test-py2: ${{ inputs.test-py2 }}
test-py3: ${{ inputs.test-py3 }}
minimum-base-package: ${{ inputs.minimum-base-package }}
pytest-args: ${{ inputs.pytest-args }}
secrets: inherit
je63e92c:
uses: ./.github/workflows/test-target.yml
with:
Expand Down
3 changes: 3 additions & 0 deletions lparstats/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# CHANGELOG - lparstats

<!-- towncrier release notes start -->
71 changes: 71 additions & 0 deletions lparstats/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# LPARStats

## Overview

The LPARStats check collects performance metrics from IBM POWER Logical Partitions (LPARs)
running AIX by parsing the output of the `lparstat` command.

**This check is only supported on AIX.** It relies on the `lparstat` utility, which is
exclusive to IBM AIX on POWER hardware.

Metrics collected:

- **Memory statistics** (`system.lpar.memory.*`): physical memory usage, page statistics,
I/O memory pool utilization.
- **Hypervisor call statistics** (`system.lpar.hypervisor.*`): per-call counts and latency
for hypervisor calls. Requires root or sudo.
- **I/O memory entitlements** (`system.lpar.memory.entitlement.*`): per-pool entitlement
and allocation data. Requires root or sudo.
- **SPURR processor utilization** (`system.lpar.spurr.*`): actual and normalized physical
processor utilization rates.

## Setup

### Installation

The LPARStats check is included in the [Datadog Agent][1] package for AIX. No additional
installation is needed.

### Configuration

1. Edit the `lparstats.d/conf.yaml` file in your Agent's `conf.d/` directory.
See the [sample lparstats.d/conf.yaml][2] for all available configuration options.

2. To collect hypervisor and memory entitlement metrics, the Agent must run as root, or
the `dd-agent` user must be granted sudo access to `lparstat`:

```
dd-agent ALL=(root) NOPASSWD: /usr/bin/lparstat
```

3. [Restart the Agent][3].

### Validation

Run the [Agent's status subcommand][4] and look for `lparstats` under the Checks section.

## Data Collected

### Metrics

See [metadata.csv][5] for a list of metrics provided by this check.

### Service Checks

`lparstats.can_collect`
: Returns `CRITICAL` if any `lparstat` sub-command exits with a non-zero return code. Returns `OK` otherwise.

### Events

The LPARStats check does not include any events.

## Support

Need help? Contact [Datadog support][6].

[1]: https://app.datadoghq.com/account/settings/agent/latest
[2]: https://github.com/DataDog/integrations-core/blob/master/lparstats/datadog_checks/lparstats/data/conf.yaml.example
[3]: https://docs.datadoghq.com/agent/guide/agent-commands/#start-stop-and-restart-the-agent
[4]: https://docs.datadoghq.com/agent/guide/agent-commands/#agent-status-and-information
[5]: https://github.com/DataDog/integrations-core/blob/master/lparstats/metadata.csv
[6]: https://docs.datadoghq.com/help/
61 changes: 61 additions & 0 deletions lparstats/assets/configuration/spec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: LPARStats
files:
- name: lparstats.yaml
options:
- template: init_config
options:
- template: init_config/default
- template: instances
options:
- name: name
description: A name for this instance.
required: false
value:
type: string
example: lparstats
- name: sudo
description: |
Run lparstat with sudo. Requires adding dd-agent to the sudoers file:

dd-agent ALL=(ALL) NOPASSWD: /usr/bin/lparstat

When running as root, sudo is not needed.
required: false
value:
type: boolean
example: false
- name: memory_stats
description: Collect physical memory and page statistics (lparstat -m).
required: false
value:
type: boolean
example: true
- name: page_stats
description: Include page-level statistics (-pw flag). Requires memory_stats to be true.
required: false
value:
type: boolean
example: true
- name: memory_entitlements
description: |
Collect per-I/O-memory-pool entitlement stats (lparstat -m -eR).
Requires root or sudo.
required: false
value:
type: boolean
example: true
- name: hypervisor
description: |
Collect hypervisor call statistics (lparstat -H).
Requires root or sudo.
required: false
value:
type: boolean
example: true
- name: spurr_utilization
description: Collect SPURR physical processor utilization (lparstat -E).
required: false
value:
type: boolean
example: true
- template: instances/default
11 changes: 11 additions & 0 deletions lparstats/assets/service_checks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[
{
"agent_version": "7.0.0",
"integration": "lparstats",
"check": "lparstats.can_collect",
"statuses": ["ok", "critical"],
"groups": [],
"name": "LPARStats Can Collect",
"description": "Returns `CRITICAL` if any `lparstat` sub-command fails (non-zero exit code). Returns `OK` otherwise."
}
]
5 changes: 5 additions & 0 deletions lparstats/datadog_checks/lparstats/__about__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# (C) Datadog, Inc. 2026-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)

__version__ = '0.1.0'
8 changes: 8 additions & 0 deletions lparstats/datadog_checks/lparstats/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# (C) Datadog, Inc. 2026-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)

from .__about__ import __version__
from .lparstats import LPARStats

__all__ = ['__version__', 'LPARStats']
24 changes: 24 additions & 0 deletions lparstats/datadog_checks/lparstats/config_models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# (C) Datadog, Inc. 2026-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)

# This file is autogenerated.
# To change this file you should edit assets/configuration/spec.yaml and then run the following commands:
# ddev -x validate config -s <INTEGRATION_NAME>
# ddev -x validate models -s <INTEGRATION_NAME>

from .instance import InstanceConfig
from .shared import SharedConfig


class ConfigMixin:
_config_model_instance: InstanceConfig
_config_model_shared: SharedConfig

@property
def config(self) -> InstanceConfig:
return self._config_model_instance

@property
def shared_config(self) -> SharedConfig:
return self._config_model_shared
52 changes: 52 additions & 0 deletions lparstats/datadog_checks/lparstats/config_models/defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# (C) Datadog, Inc. 2026-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)

# This file is autogenerated.
# To change this file you should edit assets/configuration/spec.yaml and then run the following commands:
# ddev -x validate config -s <INTEGRATION_NAME>
# ddev -x validate models -s <INTEGRATION_NAME>


def instance_disable_generic_tags():
return False


def instance_empty_default_hostname():
return False


def instance_enable_legacy_tags_normalization():
return True


def instance_hypervisor():
return True


def instance_memory_entitlements():
return True


def instance_memory_stats():
return True


def instance_min_collection_interval():
return 15


def instance_name():
return 'lparstats'


def instance_page_stats():
return True


def instance_spurr_utilization():
return True


def instance_sudo():
return False
69 changes: 69 additions & 0 deletions lparstats/datadog_checks/lparstats/config_models/instance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# (C) Datadog, Inc. 2026-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)

# This file is autogenerated.
# To change this file you should edit assets/configuration/spec.yaml and then run the following commands:
# ddev -x validate config -s <INTEGRATION_NAME>
# ddev -x validate models -s <INTEGRATION_NAME>

from __future__ import annotations

from typing import Optional

from pydantic import BaseModel, ConfigDict, field_validator, model_validator

from datadog_checks.base.utils.functions import identity
from datadog_checks.base.utils.models import validation

from . import defaults, validators


class MetricPatterns(BaseModel):
model_config = ConfigDict(
arbitrary_types_allowed=True,
frozen=True,
)
exclude: Optional[tuple[str, ...]] = None
include: Optional[tuple[str, ...]] = None


class InstanceConfig(BaseModel):
model_config = ConfigDict(
validate_default=True,
arbitrary_types_allowed=True,
frozen=True,
)
disable_generic_tags: Optional[bool] = None
empty_default_hostname: Optional[bool] = None
enable_legacy_tags_normalization: Optional[bool] = None
hypervisor: Optional[bool] = None
memory_entitlements: Optional[bool] = None
memory_stats: Optional[bool] = None
metric_patterns: Optional[MetricPatterns] = None
min_collection_interval: Optional[float] = None
name: Optional[str] = None
page_stats: Optional[bool] = None
service: Optional[str] = None
spurr_utilization: Optional[bool] = None
sudo: Optional[bool] = None
tags: Optional[tuple[str, ...]] = None

@model_validator(mode='before')
def _initial_validation(cls, values):
return validation.core.initialize_config(getattr(validators, 'initialize_instance', identity)(values))

@field_validator('*', mode='before')
def _validate(cls, value, info):
field = cls.model_fields[info.field_name]
field_name = field.alias or info.field_name
if field_name in info.context['configured_fields']:
value = getattr(validators, f'instance_{info.field_name}', identity)(value, field=field)
else:
value = getattr(defaults, f'instance_{info.field_name}', lambda: value)()

return validation.utils.make_immutable(value)

@model_validator(mode='after')
def _final_validation(cls, model):
return validation.core.check_model(getattr(validators, 'check_instance', identity)(model))
Loading
Loading