infrahub-server 1.1.6__py3-none-any.whl → 1.1.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. infrahub/core/attribute.py +4 -1
  2. infrahub/core/branch/tasks.py +7 -4
  3. infrahub/core/diff/combiner.py +11 -7
  4. infrahub/core/diff/coordinator.py +49 -70
  5. infrahub/core/diff/data_check_synchronizer.py +86 -7
  6. infrahub/core/diff/enricher/aggregated.py +3 -3
  7. infrahub/core/diff/enricher/cardinality_one.py +1 -6
  8. infrahub/core/diff/enricher/labels.py +13 -3
  9. infrahub/core/diff/enricher/path_identifier.py +2 -8
  10. infrahub/core/diff/merger/merger.py +5 -3
  11. infrahub/core/diff/model/path.py +42 -24
  12. infrahub/core/diff/query/all_conflicts.py +5 -2
  13. infrahub/core/diff/query/diff_get.py +2 -1
  14. infrahub/core/diff/query/field_specifiers.py +2 -0
  15. infrahub/core/diff/query/field_summary.py +2 -1
  16. infrahub/core/diff/query/filters.py +12 -1
  17. infrahub/core/diff/query/has_conflicts_query.py +5 -2
  18. infrahub/core/diff/query/{drop_tracking_id.py → merge_tracking_id.py} +3 -3
  19. infrahub/core/diff/query/roots_metadata.py +8 -1
  20. infrahub/core/diff/query/save.py +148 -63
  21. infrahub/core/diff/query/summary_counts_enricher.py +220 -0
  22. infrahub/core/diff/query/time_range_query.py +2 -1
  23. infrahub/core/diff/query_parser.py +49 -24
  24. infrahub/core/diff/repository/deserializer.py +23 -24
  25. infrahub/core/diff/repository/repository.py +76 -20
  26. infrahub/core/node/__init__.py +6 -1
  27. infrahub/core/node/constraints/grouped_uniqueness.py +9 -2
  28. infrahub/core/node/ipam.py +6 -1
  29. infrahub/core/node/permissions.py +4 -0
  30. infrahub/core/query/diff.py +41 -3
  31. infrahub/core/query/node.py +8 -2
  32. infrahub/core/query/relationship.py +2 -1
  33. infrahub/core/query/resource_manager.py +3 -1
  34. infrahub/core/utils.py +1 -0
  35. infrahub/core/validators/uniqueness/query.py +20 -17
  36. infrahub/database/__init__.py +13 -0
  37. infrahub/dependencies/builder/constraint/grouped/node_runner.py +0 -2
  38. infrahub/dependencies/builder/diff/coordinator.py +0 -2
  39. infrahub/graphql/mutations/computed_attribute.py +3 -1
  40. infrahub/graphql/mutations/diff.py +28 -4
  41. infrahub/graphql/mutations/main.py +11 -6
  42. infrahub/graphql/mutations/relationship.py +29 -1
  43. infrahub/graphql/mutations/tasks.py +6 -3
  44. infrahub/graphql/queries/resource_manager.py +7 -3
  45. infrahub/permissions/__init__.py +2 -1
  46. infrahub/permissions/types.py +26 -0
  47. infrahub_sdk/batch.py +2 -2
  48. infrahub_sdk/config.py +1 -1
  49. infrahub_sdk/ctl/check.py +1 -1
  50. infrahub_sdk/ctl/utils.py +2 -2
  51. infrahub_sdk/data.py +1 -1
  52. infrahub_sdk/node.py +4 -1
  53. infrahub_sdk/protocols.py +1 -0
  54. infrahub_sdk/schema/__init__.py +3 -0
  55. infrahub_sdk/testing/docker.py +0 -30
  56. infrahub_sdk/transfer/exporter/json.py +1 -1
  57. {infrahub_server-1.1.6.dist-info → infrahub_server-1.1.7.dist-info}/METADATA +41 -7
  58. {infrahub_server-1.1.6.dist-info → infrahub_server-1.1.7.dist-info}/RECORD +65 -65
  59. infrahub_testcontainers/container.py +12 -3
  60. infrahub_testcontainers/docker-compose.test.yml +22 -3
  61. infrahub_testcontainers/haproxy.cfg +43 -0
  62. infrahub_testcontainers/helpers.py +85 -1
  63. infrahub/core/diff/enricher/summary_counts.py +0 -105
  64. infrahub/dependencies/builder/diff/enricher/summary_counts.py +0 -8
  65. {infrahub_server-1.1.6.dist-info → infrahub_server-1.1.7.dist-info}/LICENSE.txt +0 -0
  66. {infrahub_server-1.1.6.dist-info → infrahub_server-1.1.7.dist-info}/WHEEL +0 -0
  67. {infrahub_server-1.1.6.dist-info → infrahub_server-1.1.7.dist-info}/entry_points.txt +0 -0
@@ -87,7 +87,9 @@ class UpdateComputedAttribute(Mutation):
87
87
  log_data = get_log_data()
88
88
  request_id = log_data.get("request_id", "")
89
89
 
90
- graphql_payload = await target_node.to_graphql(db=context.db, filter_sensitive=True)
90
+ graphql_payload = await target_node.to_graphql(
91
+ db=context.db, filter_sensitive=True, include_properties=False
92
+ )
91
93
 
92
94
  event = NodeMutatedEvent(
93
95
  branch=context.branch.name,
@@ -5,9 +5,13 @@ from graphql import GraphQLResolveInfo
5
5
 
6
6
  from infrahub.core import registry
7
7
  from infrahub.core.diff.coordinator import DiffCoordinator
8
+ from infrahub.core.diff.model.path import NameTrackingId
8
9
  from infrahub.core.diff.models import RequestDiffUpdate
10
+ from infrahub.core.diff.repository.repository import DiffRepository
11
+ from infrahub.core.timestamp import Timestamp
9
12
  from infrahub.database import retry_db_transaction
10
13
  from infrahub.dependencies.registry import get_component_registry
14
+ from infrahub.exceptions import ValidationError
11
15
  from infrahub.workflows.catalogue import DIFF_UPDATE
12
16
 
13
17
  if TYPE_CHECKING:
@@ -40,11 +44,31 @@ class DiffUpdateMutation(Mutation):
40
44
 
41
45
  from_timestamp_str = DateTime.serialize(data.from_time) if data.from_time else None
42
46
  to_timestamp_str = DateTime.serialize(data.to_time) if data.to_time else None
43
- if data.wait_for_completion is True:
44
- component_registry = get_component_registry()
45
- base_branch = await registry.get_branch(db=context.db, branch=registry.default_branch)
46
- diff_branch = await registry.get_branch(db=context.db, branch=data.branch)
47
+ if (data.from_time or data.to_time) and not data.name:
48
+ raise ValidationError("diff with specified time range requires a name")
49
+
50
+ component_registry = get_component_registry()
51
+ base_branch = await registry.get_branch(db=context.db, branch=registry.default_branch)
52
+ diff_branch = await registry.get_branch(db=context.db, branch=data.branch)
53
+ diff_repository = await component_registry.get_component(DiffRepository, db=context.db, branch=diff_branch)
47
54
 
55
+ tracking_id = NameTrackingId(name=data.name)
56
+ existing_diffs_metatdatas = await diff_repository.get_roots_metadata(
57
+ diff_branch_names=[diff_branch.name], base_branch_names=[base_branch.name], tracking_id=tracking_id
58
+ )
59
+ if existing_diffs_metatdatas:
60
+ metadata = existing_diffs_metatdatas[0]
61
+ from_time = Timestamp(from_timestamp_str) if from_timestamp_str else None
62
+ to_time = Timestamp(to_timestamp_str) if to_timestamp_str else None
63
+ branched_from_timestamp = Timestamp(diff_branch.get_branched_from())
64
+ if from_time and from_time > metadata.from_time:
65
+ raise ValidationError(f"from_time must be null or less than or equal to {metadata.from_time}")
66
+ if from_time and from_time < branched_from_timestamp:
67
+ raise ValidationError(f"from_time must be null or greater than or equal to {branched_from_timestamp}")
68
+ if to_time and to_time < metadata.to_time:
69
+ raise ValidationError(f"to_time must be null or greater than or equal to {metadata.to_time}")
70
+
71
+ if data.wait_for_completion is True:
48
72
  diff_coordinator = await component_registry.get_component(
49
73
  DiffCoordinator, db=context.db, branch=diff_branch
50
74
  )
@@ -97,7 +97,7 @@ class InfrahubMutationMixin:
97
97
  log_data = get_log_data()
98
98
  request_id = log_data.get("request_id", "")
99
99
 
100
- graphql_payload = await obj.to_graphql(db=context.db, filter_sensitive=True)
100
+ graphql_payload = await obj.to_graphql(db=context.db, filter_sensitive=True, include_properties=False)
101
101
  event = NodeMutatedEvent(
102
102
  branch=context.branch.name,
103
103
  kind=obj._schema.kind,
@@ -175,20 +175,25 @@ class InfrahubMutationMixin:
175
175
  branch: Branch,
176
176
  ) -> Node:
177
177
  component_registry = get_component_registry()
178
- node_constraint_runner = await component_registry.get_component(NodeConstraintRunner, db=db, branch=branch)
178
+ node_constraint_runner = await component_registry.get_component(
179
+ NodeConstraintRunner, db=db.start_session(), branch=branch
180
+ )
179
181
  node_class = Node
180
182
  if cls._meta.schema.kind in registry.node:
181
183
  node_class = registry.node[cls._meta.schema.kind]
182
184
 
185
+ fields_to_validate = list(data)
183
186
  try:
184
- obj = await node_class.init(db=db, schema=cls._meta.schema, branch=branch)
185
- await obj.new(db=db, **data)
186
- fields_to_validate = list(data)
187
- await node_constraint_runner.check(node=obj, field_filters=fields_to_validate)
188
187
  if db.is_transaction:
188
+ obj = await node_class.init(db=db, schema=cls._meta.schema, branch=branch)
189
+ await obj.new(db=db, **data)
190
+ await node_constraint_runner.check(node=obj, field_filters=fields_to_validate)
189
191
  await obj.save(db=db)
190
192
  else:
191
193
  async with db.start_transaction() as dbt:
194
+ obj = await node_class.init(db=dbt, schema=cls._meta.schema, branch=branch)
195
+ await obj.new(db=dbt, **data)
196
+ await node_constraint_runner.check(node=obj, field_filters=fields_to_validate)
192
197
  await obj.save(db=dbt)
193
198
 
194
199
  except ValidationError as exc:
@@ -5,7 +5,8 @@ from typing import TYPE_CHECKING
5
5
  from graphene import Boolean, InputField, InputObjectType, List, Mutation, String
6
6
  from infrahub_sdk.utils import compare_lists
7
7
 
8
- from infrahub.core.constants import InfrahubKind, RelationshipCardinality
8
+ from infrahub.core.account import GlobalPermission, ObjectPermission
9
+ from infrahub.core.constants import InfrahubKind, PermissionAction, PermissionDecision, RelationshipCardinality
9
10
  from infrahub.core.manager import NodeManager
10
11
  from infrahub.core.query.relationship import (
11
12
  RelationshipGetPeerQuery,
@@ -14,6 +15,7 @@ from infrahub.core.query.relationship import (
14
15
  from infrahub.core.relationship import Relationship
15
16
  from infrahub.database import retry_db_transaction
16
17
  from infrahub.exceptions import NodeNotFoundError, ValidationError
18
+ from infrahub.permissions import get_global_permission_for_kind
17
19
 
18
20
  from ..types import RelatedNodeInput
19
21
 
@@ -76,6 +78,32 @@ class RelationshipMixin:
76
78
  db=context.db, ids=node_ids, fields={"display_label": None}, branch=context.branch
77
79
  )
78
80
 
81
+ if context.account_session:
82
+ impacted_schemas = {node.get_schema() for node in [source] + list(nodes.values())}
83
+ required_permissions: list[GlobalPermission | ObjectPermission] = []
84
+ decision = (
85
+ PermissionDecision.ALLOW_DEFAULT.value
86
+ if context.branch.is_default
87
+ else PermissionDecision.ALLOW_OTHER.value
88
+ )
89
+
90
+ for impacted_schema in impacted_schemas:
91
+ global_action = get_global_permission_for_kind(schema=impacted_schema)
92
+
93
+ if global_action:
94
+ required_permissions.append(GlobalPermission(action=global_action, decision=decision))
95
+ else:
96
+ required_permissions.append(
97
+ ObjectPermission(
98
+ namespace=impacted_schema.namespace,
99
+ name=impacted_schema.name,
100
+ action=PermissionAction.UPDATE.value,
101
+ decision=decision,
102
+ )
103
+ )
104
+
105
+ context.active_permissions.raise_for_permissions(permissions=required_permissions)
106
+
79
107
  _, _, in_list2 = compare_lists(list1=list(nodes.keys()), list2=node_ids)
80
108
  if in_list2:
81
109
  for node_id in in_list2:
@@ -31,14 +31,17 @@ async def merge_branch_mutation(branch: str) -> None:
31
31
  diff_coordinator = await component_registry.get_component(DiffCoordinator, db=db, branch=obj)
32
32
  diff_repository = await component_registry.get_component(DiffRepository, db=db, branch=obj)
33
33
  diff_merger = await component_registry.get_component(DiffMerger, db=db, branch=obj)
34
- enriched_diff = await diff_coordinator.update_branch_diff_and_return(base_branch=base_branch, diff_branch=obj)
35
- if enriched_diff.get_all_conflicts():
34
+ enriched_diff_metadata = await diff_coordinator.update_branch_diff(base_branch=base_branch, diff_branch=obj)
35
+ async for _ in diff_repository.get_all_conflicts_for_diff(
36
+ diff_branch_name=enriched_diff_metadata.diff_branch_name, diff_id=enriched_diff_metadata.uuid
37
+ ):
38
+ # if there are any conflicts, raise the error
36
39
  raise ValidationError(
37
40
  f"Branch {obj.name} contains conflicts with the default branch."
38
41
  " Please create a Proposed Change to resolve the conflicts or manually update them before merging."
39
42
  )
40
43
  node_diff_field_summaries = await diff_repository.get_node_field_summaries(
41
- diff_branch_name=enriched_diff.diff_branch_name, diff_id=enriched_diff.uuid
44
+ diff_branch_name=enriched_diff_metadata.diff_branch_name, diff_id=enriched_diff_metadata.uuid
42
45
  )
43
46
 
44
47
  merger = BranchMerger(
@@ -21,8 +21,10 @@ from infrahub.pools.number import NumberUtilizationGetter
21
21
  if TYPE_CHECKING:
22
22
  from graphql import GraphQLResolveInfo
23
23
 
24
+ from infrahub.core.branch import Branch
24
25
  from infrahub.core.node import Node
25
26
  from infrahub.core.protocols import CoreNode
27
+ from infrahub.core.timestamp import Timestamp
26
28
  from infrahub.database import InfrahubDatabase
27
29
  from infrahub.graphql.initialization import GraphqlContext
28
30
 
@@ -184,7 +186,7 @@ class PoolUtilization(ObjectType):
184
186
  pool: CoreNode | None = await NodeManager.get_one(id=pool_id, db=db, branch=context.branch)
185
187
  pool = _validate_pool_type(pool_id=pool_id, pool=pool)
186
188
  if pool.get_kind() == "CoreNumberPool":
187
- return await resolve_number_pool_utilization(db=db, context=context, pool=pool)
189
+ return await resolve_number_pool_utilization(db=db, at=context.at, pool=pool, branch=context.branch)
188
190
 
189
191
  resources_map: dict[str, Node] = {}
190
192
 
@@ -290,8 +292,10 @@ async def resolve_number_pool_allocation(
290
292
  return response
291
293
 
292
294
 
293
- async def resolve_number_pool_utilization(db: InfrahubDatabase, context: GraphqlContext, pool: CoreNode) -> dict:
294
- number_pool = NumberUtilizationGetter(db=db, pool=pool, at=context.at, branch=context.branch)
295
+ async def resolve_number_pool_utilization(
296
+ db: InfrahubDatabase, pool: CoreNode, at: Timestamp | str | None, branch: Branch
297
+ ) -> dict:
298
+ number_pool = NumberUtilizationGetter(db=db, pool=pool, at=at, branch=branch)
295
299
  await number_pool.load_data()
296
300
 
297
301
  return {
@@ -2,12 +2,13 @@ from infrahub.permissions.backend import PermissionBackend
2
2
  from infrahub.permissions.local_backend import LocalPermissionBackend
3
3
  from infrahub.permissions.manager import PermissionManager
4
4
  from infrahub.permissions.report import report_schema_permissions
5
- from infrahub.permissions.types import AssignedPermissions
5
+ from infrahub.permissions.types import AssignedPermissions, get_global_permission_for_kind
6
6
 
7
7
  __all__ = [
8
8
  "AssignedPermissions",
9
9
  "LocalPermissionBackend",
10
10
  "PermissionBackend",
11
11
  "PermissionManager",
12
+ "get_global_permission_for_kind",
12
13
  "report_schema_permissions",
13
14
  ]
@@ -2,8 +2,12 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, TypedDict
4
4
 
5
+ from infrahub.core.constants import GlobalPermissions, InfrahubKind
6
+ from infrahub.core.schema import NodeSchema
7
+
5
8
  if TYPE_CHECKING:
6
9
  from infrahub.core.account import GlobalPermission, ObjectPermission
10
+ from infrahub.core.schema import MainSchemaTypes
7
11
  from infrahub.permissions.constants import BranchRelativePermissionDecision
8
12
 
9
13
 
@@ -18,3 +22,25 @@ class KindPermissions(TypedDict):
18
22
  delete: BranchRelativePermissionDecision
19
23
  update: BranchRelativePermissionDecision
20
24
  view: BranchRelativePermissionDecision
25
+
26
+
27
+ def get_global_permission_for_kind(schema: MainSchemaTypes) -> GlobalPermissions | None:
28
+ kind_permission_map = {
29
+ InfrahubKind.GENERICACCOUNT: GlobalPermissions.MANAGE_ACCOUNTS,
30
+ InfrahubKind.ACCOUNTGROUP: GlobalPermissions.MANAGE_ACCOUNTS,
31
+ InfrahubKind.ACCOUNTROLE: GlobalPermissions.MANAGE_ACCOUNTS,
32
+ InfrahubKind.BASEPERMISSION: GlobalPermissions.MANAGE_PERMISSIONS,
33
+ InfrahubKind.GENERICREPOSITORY: GlobalPermissions.MANAGE_REPOSITORIES,
34
+ }
35
+
36
+ if schema.kind in kind_permission_map:
37
+ return kind_permission_map[schema.kind]
38
+
39
+ if isinstance(schema, NodeSchema):
40
+ for base in schema.inherit_from:
41
+ try:
42
+ return kind_permission_map[base]
43
+ except KeyError:
44
+ continue
45
+
46
+ return None
infrahub_sdk/batch.py CHANGED
@@ -30,7 +30,7 @@ class BatchTaskSync:
30
30
  result = None
31
31
  try:
32
32
  result = self.task(*self.args, **self.kwargs)
33
- except Exception as exc:
33
+ except Exception as exc: # pylint: disable=broad-exception-caught
34
34
  if return_exceptions:
35
35
  return self.node, exc
36
36
  raise exc
@@ -44,7 +44,7 @@ async def execute_batch_task_in_pool(
44
44
  async with semaphore:
45
45
  try:
46
46
  result = await task.task(*task.args, **task.kwargs)
47
- except Exception as exc:
47
+ except Exception as exc: # pylint: disable=broad-exception-caught
48
48
  if return_exceptions:
49
49
  return (task.node, exc)
50
50
  raise exc
infrahub_sdk/config.py CHANGED
@@ -113,7 +113,7 @@ class ConfigBase(BaseSettings):
113
113
 
114
114
  @model_validator(mode="after")
115
115
  def validate_proxy_config(self) -> Self:
116
- if self.proxy and self.proxy_mounts.is_set:
116
+ if self.proxy and self.proxy_mounts.is_set: # pylint: disable=no-member
117
117
  raise ValueError("'proxy' and 'proxy_mounts' are mutually exclusive")
118
118
  return self
119
119
 
infrahub_sdk/ctl/check.py CHANGED
@@ -121,7 +121,7 @@ async def run_check(
121
121
  except QueryNotFoundError as exc:
122
122
  log.warning(f"{module_name}::{check}: unable to find query ({exc!s})")
123
123
  passed = False
124
- except Exception as exc:
124
+ except Exception as exc: # pylint: disable=broad-exception-caught
125
125
  log.warning(f"{module_name}::{check}: An error occurred during execution ({exc})")
126
126
  passed = False
127
127
 
infrahub_sdk/ctl/utils.py CHANGED
@@ -88,7 +88,7 @@ def catch_exception(
88
88
  async def async_wrapper(*args: Any, **kwargs: Any) -> T:
89
89
  try:
90
90
  return await func(*args, **kwargs)
91
- except (Error, Exception) as exc:
91
+ except (Error, Exception) as exc: # pylint: disable=broad-exception-caught
92
92
  return handle_exception(exc=exc, console=console, exit_code=exit_code)
93
93
 
94
94
  return async_wrapper
@@ -97,7 +97,7 @@ def catch_exception(
97
97
  def wrapper(*args: Any, **kwargs: Any) -> T:
98
98
  try:
99
99
  return func(*args, **kwargs)
100
- except (Error, Exception) as exc:
100
+ except (Error, Exception) as exc: # pylint: disable=broad-exception-caught
101
101
  return handle_exception(exc=exc, console=console, exit_code=exit_code)
102
102
 
103
103
  return wrapper
infrahub_sdk/data.py CHANGED
@@ -20,7 +20,7 @@ class RepositoryData(BaseModel):
20
20
  branch_info: dict[str, RepositoryBranchInfo] = Field(default_factory=dict)
21
21
 
22
22
  def get_staging_branch(self) -> str | None:
23
- for branch, info in self.branch_info.items():
23
+ for branch, info in self.branch_info.items(): # pylint: disable=no-member
24
24
  if info.internal_status == "staging":
25
25
  return branch
26
26
  return None
infrahub_sdk/node.py CHANGED
@@ -25,6 +25,7 @@ if TYPE_CHECKING:
25
25
  from .schema import AttributeSchemaAPI, MainSchemaTypesAPI, RelationshipSchemaAPI
26
26
  from .types import Order
27
27
 
28
+ # pylint: disable=too-many-lines
28
29
 
29
30
  PROPERTIES_FLAG = ["is_visible", "is_protected"]
30
31
  PROPERTIES_OBJECT = ["source", "owner"]
@@ -800,7 +801,7 @@ class InfrahubNodeBase:
800
801
  Returns:
801
802
  dict[str, Dict]: Representation of an input data in dict format
802
803
  """
803
-
804
+ # pylint: disable=too-many-branches
804
805
  data = {}
805
806
  variables = {}
806
807
 
@@ -1250,6 +1251,7 @@ class InfrahubNode(InfrahubNodeBase):
1250
1251
  Returns:
1251
1252
  dict[str, Union[Any, Dict]]: GraphQL query in dictionary format
1252
1253
  """
1254
+ # pylint: disable=too-many-branches
1253
1255
 
1254
1256
  data: dict[str, Any] = {}
1255
1257
 
@@ -1761,6 +1763,7 @@ class InfrahubNodeSync(InfrahubNodeBase):
1761
1763
  Returns:
1762
1764
  dict[str, Union[Any, Dict]]: GraphQL query in dictionary format
1763
1765
  """
1766
+ # pylint: disable=too-many-branches
1764
1767
 
1765
1768
  data: dict[str, Any] = {}
1766
1769
 
infrahub_sdk/protocols.py CHANGED
@@ -29,6 +29,7 @@ if TYPE_CHECKING:
29
29
  StringOptional,
30
30
  )
31
31
 
32
+ # pylint: disable=too-many-ancestors
32
33
 
33
34
  # ---------------------------------------------
34
35
  # ASYNC
@@ -61,6 +61,9 @@ __all__ = [
61
61
  ]
62
62
 
63
63
 
64
+ # pylint: disable=redefined-builtin
65
+
66
+
64
67
  class DropdownMutationOptionalArgs(TypedDict):
65
68
  color: str | None
66
69
  description: str | None
@@ -1,40 +1,10 @@
1
- from __future__ import annotations
2
-
3
- import os
4
-
5
1
  import pytest
6
2
  from infrahub_testcontainers.helpers import TestInfrahubDocker
7
- from packaging.version import InvalidVersion, Version
8
3
 
9
4
  from .. import Config, InfrahubClient, InfrahubClientSync
10
5
 
11
- INFRAHUB_VERSION = os.getenv("INFRAHUB_TESTING_IMAGE_VER", "latest")
12
-
13
-
14
- def skip_version(min_infrahub_version: str | None = None, max_infrahub_version: str | None = None) -> bool:
15
- """
16
- Check if a test should be skipped depending on infrahub version.
17
- """
18
- try:
19
- version = Version(INFRAHUB_VERSION)
20
- except InvalidVersion:
21
- # We would typically end up here for development purpose while running a CI test against
22
- # unreleased versions of infrahub, like `stable` or `develop` branch.
23
- # For now, we consider this means we are testing against the most recent version of infrahub,
24
- # so we skip if the test should not be ran against a maximum version.
25
- return max_infrahub_version is None
26
-
27
- if min_infrahub_version is not None and version < Version(min_infrahub_version):
28
- return True
29
-
30
- return max_infrahub_version is not None and version > Version(max_infrahub_version)
31
-
32
6
 
33
7
  class TestInfrahubDockerClient(TestInfrahubDocker):
34
- @pytest.fixture(scope="class")
35
- def infrahub_version(self) -> str:
36
- return INFRAHUB_VERSION
37
-
38
8
  @pytest.fixture(scope="class")
39
9
  def client(self, infrahub_port: int) -> InfrahubClient:
40
10
  return InfrahubClient(
@@ -98,7 +98,7 @@ class LineDelimitedJSONExporter(ExporterInterface):
98
98
  return many_relationships
99
99
 
100
100
  # FIXME: Split in smaller functions
101
- async def export(
101
+ async def export( # pylint: disable=too-many-branches
102
102
  self, export_directory: Path, namespaces: list[str], branch: str, exclude: list[str] | None = None
103
103
  ) -> None:
104
104
  illegal_namespaces = set(ILLEGAL_NAMESPACES)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: infrahub-server
3
- Version: 1.1.6
3
+ Version: 1.1.7
4
4
  Summary: Infrahub is taking a new approach to Infrastructure Management by providing a new generation of datastore to organize and control all the data that defines how an infrastructure should run.
5
5
  Home-page: https://opsmill.com
6
6
  License: AGPL-3.0-only
@@ -58,16 +58,46 @@ Project-URL: Documentation, https://docs.infrahub.app/
58
58
  Project-URL: Repository, https://github.com/opsmill/infrahub
59
59
  Description-Content-Type: text/markdown
60
60
 
61
- <!-- markdownlint-disable -->
62
- ![Infrahub Logo](docs/static/img/infrahub-hori.svg)
63
- <!-- markdownlint-restore -->
61
+ <h1 align="center">
62
+ <a href=""><img src="docs/static/img/infrahub-hori.svg" alt="Infrahub" width="350"></a>
63
+ </h1>
64
+ <h3 align="center">Simplify Infrastructure Automation</h2>
64
65
 
65
- # Infrahub
66
+ <p align="center">
67
+ <a href="https://www.linkedin.com/company/opsmill">
68
+ <img src="https://img.shields.io/badge/linkedin-blue?logo=linkedin"/>
69
+ </a>
70
+ <a href="https://discord.gg/opsmill">
71
+ <img src="https://img.shields.io/badge/Discord-7289DA?&logo=discord&logoColor=white"/>
72
+ </a>
73
+ </p>
66
74
 
67
- Infrahub from [OpsMill](https://opsmill.com) is taking a new approach to Infrastructure Management by providing a new generation of datastore to organize and control all the data that defines how an infrastructure should run. Infrahub offers a central hub to manage the data, templates and playbooks that powers your infrastructure by combining the version control and branch management capabilities of Git with the flexible data model and UI of a graph database.
75
+ Infrahub from [OpsMill](https://opsmill.com) is taking a new approach to Infrastructure Management by providing a new generation of datastore to organize and control all the data that defines how an infrastructure should run. Infrahub offers a central hub to manage the data, templates and playbooks that powers your infrastructure by combining the version control and branch management capabilities similar to Git with the flexible data model and UI of a graph database.
76
+
77
+ If you just want to try Infrahub out, you can use our [Always-On Sandbox](https://demo.infrahub.app/) to get started.
68
78
 
69
79
  ![infrahub screenshot](docs/docs/media/infrahub-readme.gif)
70
80
 
81
+ ## Why Use Infrahub?
82
+
83
+ **Unified Source of Truth** - Infrahub is a single source of truth for all your infrastructure and network data. It provides a unified view of your infrastructure, allowing you to manage your infrastructure in a more efficient and effective way. Infrahub allows unidirectional and bi-directional [data synchronization](https://docs.infrahub.app/sync/sync/) between other internal systems and Infrahub. The data can be accessed via WebUI, API and SDK, along with SSO and RBAC for access control.
84
+
85
+ **Flexible Schema** - Infrahub provides a flexible schema for your infrastructure data and related business information, allowing you to define your own data model and customize it to your needs. Get started quickly with our [schema library](https://github.com/opsmill/schema-library) or build your own.
86
+
87
+ **Version Control** - Infrahub provides a version control system for your infrastructure data, allowing you to track changes and revert to previous versions if needed. Immutable history of all changes to the data and artifacts is maintained, allowing you to audit and review changes to your infrastructure.
88
+
89
+ **CI Pipeline and Validation** - Infrahub provides a CI pipeline and validation system for your infrastructure data, allowing you to ensure that your infrastructure is always in a valid state. Infrahub was designed with infrastructure-as-code workflows in mind, removing fragility and complexity of combining together multiple tools and projects to achieve the same goal.
90
+
91
+ ## Infrahub Use Cases
92
+
93
+ **Service Catalog** - Infrahub acts as the underlying system to provide infrastructure-as-a-service, allowing you to manage your services and lifecycle them as the services evolve.
94
+
95
+ **Infrastructure Automation** - Provide infrastructure and network automation workflows with Infrahub rendering configurations and artifacts via Jinja2 and python,then passing to deployment tools such as [Nornir](https://www.opsmill.com/simplifying-network-automation-workflows-with-infrahub-nornir-and-jinja2/), [Ansible](https://docs.infrahub.app/ansible/ansible/), Terraform, or vendor-specific tools.
96
+
97
+ **Inventory Management** - Infrahub serves as a centralized inventory system for your infrastructure, allowing you to manage your inventory and track changes to your infrastructure. It provides a WebUI and API for other teams to self-service the information needed to allow the organization to operate.
98
+
99
+ **DCIM and IPAM** - Infrahub provides centralized DCIM and IPAM systems for your infrastructure, capable of handling complex cases such as overlapping IP addresses and VLANs, automation-friendly, branch-aware allocation of resources via Infrahub's [Resource Manager](https://docs.infrahub.app/python-sdk/guides/resource-manager), and more.
100
+
71
101
  ## Quick Start
72
102
 
73
103
  [Always-On Sandbox](https://demo.infrahub.app/) - Instantly login to the UI of a demo environment of Infrahub with sample data pre-loaded.
@@ -94,7 +124,11 @@ If you need help, support for the community version of Infrahub is provided on [
94
124
 
95
125
  ## Contributing
96
126
 
97
- [View our CONTRIBUTING](./CONTRIBUTING.md) policy to get started on contributing to Infrahub.
127
+ To help our community with the creation of contributions, please view our [CONTRIBUTING](./CONTRIBUTING.md) page.
128
+
129
+ <a href="https://github.com/opsmill/infrahub/graphs/contributors">
130
+ <img src="https://contrib.rocks/image?repo=opsmill/infrahub" />
131
+ </a>
98
132
 
99
133
  ## Security
100
134