Skip to content

Commit

Permalink
AIP-84 Get Providers (apache#43159)
Browse files Browse the repository at this point in the history
  • Loading branch information
pierrejeambrun authored and PaulKobow7536 committed Oct 24, 2024
1 parent cfee48c commit e718698
Show file tree
Hide file tree
Showing 13 changed files with 456 additions and 0 deletions.
2 changes: 2 additions & 0 deletions airflow/api_connexion/endpoints/provider_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
)
from airflow.auth.managers.models.resource_details import AccessView
from airflow.providers_manager import ProvidersManager
from airflow.utils.api_migration import mark_fastapi_migration_done

if TYPE_CHECKING:
from airflow.api_connexion.types import APIResponse
Expand All @@ -46,6 +47,7 @@ def _provider_mapper(provider: ProviderInfo) -> Provider:
)


@mark_fastapi_migration_done
@security.requires_access_view(AccessView.PROVIDERS)
def get_providers() -> APIResponse:
"""Get providers."""
Expand Down
69 changes: 69 additions & 0 deletions airflow/api_fastapi/core_api/openapi/v1-generated.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,41 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/public/providers/:
get:
tags:
- Provider
summary: Get Providers
description: Get providers.
operationId: get_providers
parameters:
- name: limit
in: query
required: false
schema:
type: integer
default: 100
title: Limit
- name: offset
in: query
required: false
schema:
type: integer
default: 0
title: Offset
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/ProviderCollectionResponse'
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
components:
schemas:
BaseInfoSchema:
Expand Down Expand Up @@ -1803,6 +1838,40 @@ components:
- task_instance_states
title: HistoricalMetricDataResponse
description: Historical Metric Data serializer for responses.
ProviderCollectionResponse:
properties:
providers:
items:
$ref: '#/components/schemas/ProviderResponse'
type: array
title: Providers
total_entries:
type: integer
title: Total Entries
type: object
required:
- providers
- total_entries
title: ProviderCollectionResponse
description: Provider Collection serializer for responses.
ProviderResponse:
properties:
package_name:
type: string
title: Package Name
description:
type: string
title: Description
version:
type: string
title: Version
type: object
required:
- package_name
- description
- version
title: ProviderResponse
description: Provider serializer for responses.
SchedulerInfoSchema:
properties:
status:
Expand Down
2 changes: 2 additions & 0 deletions airflow/api_fastapi/core_api/routes/public/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from airflow.api_fastapi.core_api.routes.public.dags import dags_router
from airflow.api_fastapi.core_api.routes.public.monitor import monitor_router
from airflow.api_fastapi.core_api.routes.public.pools import pools_router
from airflow.api_fastapi.core_api.routes.public.providers import providers_router
from airflow.api_fastapi.core_api.routes.public.variables import variables_router

public_router = AirflowRouter(prefix="/public")
Expand All @@ -34,3 +35,4 @@
public_router.include_router(dag_run_router)
public_router.include_router(monitor_router)
public_router.include_router(pools_router)
public_router.include_router(providers_router)
55 changes: 55 additions & 0 deletions airflow/api_fastapi/core_api/routes/public/providers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

from __future__ import annotations

import re2

from airflow.api_fastapi.common.parameters import QueryLimit, QueryOffset
from airflow.api_fastapi.common.router import AirflowRouter
from airflow.api_fastapi.core_api.serializers.providers import ProviderCollectionResponse, ProviderResponse
from airflow.providers_manager import ProviderInfo, ProvidersManager

providers_router = AirflowRouter(tags=["Provider"], prefix="/providers")


def _remove_rst_syntax(value: str) -> str:
return re2.sub("[`_<>]", "", value.strip(" \n."))


def _provider_mapper(provider: ProviderInfo) -> ProviderResponse:
return ProviderResponse(
package_name=provider.data["package-name"],
description=_remove_rst_syntax(provider.data["description"]),
version=provider.version,
)


@providers_router.get("/")
async def get_providers(
limit: QueryLimit,
offset: QueryOffset,
) -> ProviderCollectionResponse:
"""Get providers."""
providers = sorted(
[_provider_mapper(d) for d in ProvidersManager().providers.values()], key=lambda x: x.package_name
)
total_entries = len(providers)

if limit.value is not None and offset.value is not None:
providers = providers[offset.value : offset.value + limit.value]
return ProviderCollectionResponse(providers=providers, total_entries=total_entries)
35 changes: 35 additions & 0 deletions airflow/api_fastapi/core_api/serializers/providers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

from __future__ import annotations

from pydantic import BaseModel


class ProviderResponse(BaseModel):
"""Provider serializer for responses."""

package_name: str
description: str
version: str


class ProviderCollectionResponse(BaseModel):
"""Provider Collection serializer for responses."""

providers: list[ProviderResponse]
total_entries: int
19 changes: 19 additions & 0 deletions airflow/ui/openapi-gen/queries/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
DashboardService,
MonitorService,
PoolService,
ProviderService,
VariableService,
} from "../requests/services.gen";
import { DagRunState } from "../requests/types.gen";
Expand Down Expand Up @@ -246,6 +247,24 @@ export const UseMonitorServiceGetHealthKeyFn = (queryKey?: Array<unknown>) => [
useMonitorServiceGetHealthKey,
...(queryKey ?? []),
];
export type ProviderServiceGetProvidersDefaultResponse = Awaited<
ReturnType<typeof ProviderService.getProviders>
>;
export type ProviderServiceGetProvidersQueryResult<
TData = ProviderServiceGetProvidersDefaultResponse,
TError = unknown,
> = UseQueryResult<TData, TError>;
export const useProviderServiceGetProvidersKey = "ProviderServiceGetProviders";
export const UseProviderServiceGetProvidersKeyFn = (
{
limit,
offset,
}: {
limit?: number;
offset?: number;
} = {},
queryKey?: Array<unknown>,
) => [useProviderServiceGetProvidersKey, ...(queryKey ?? [{ limit, offset }])];
export type VariableServicePostVariableMutationResult = Awaited<
ReturnType<typeof VariableService.postVariable>
>;
Expand Down
24 changes: 24 additions & 0 deletions airflow/ui/openapi-gen/queries/prefetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
DagService,
DashboardService,
MonitorService,
ProviderService,
VariableService,
} from "../requests/services.gen";
import { DagRunState } from "../requests/types.gen";
Expand Down Expand Up @@ -300,3 +301,26 @@ export const prefetchUseMonitorServiceGetHealth = (queryClient: QueryClient) =>
queryKey: Common.UseMonitorServiceGetHealthKeyFn(),
queryFn: () => MonitorService.getHealth(),
});
/**
* Get Providers
* Get providers.
* @param data The data for the request.
* @param data.limit
* @param data.offset
* @returns ProviderCollectionResponse Successful Response
* @throws ApiError
*/
export const prefetchUseProviderServiceGetProviders = (
queryClient: QueryClient,
{
limit,
offset,
}: {
limit?: number;
offset?: number;
} = {},
) =>
queryClient.prefetchQuery({
queryKey: Common.UseProviderServiceGetProvidersKeyFn({ limit, offset }),
queryFn: () => ProviderService.getProviders({ limit, offset }),
});
33 changes: 33 additions & 0 deletions airflow/ui/openapi-gen/queries/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
DashboardService,
MonitorService,
PoolService,
ProviderService,
VariableService,
} from "../requests/services.gen";
import { DAGPatchBody, DagRunState, VariableBody } from "../requests/types.gen";
Expand Down Expand Up @@ -387,6 +388,38 @@ export const useMonitorServiceGetHealth = <
queryFn: () => MonitorService.getHealth() as TData,
...options,
});
/**
* Get Providers
* Get providers.
* @param data The data for the request.
* @param data.limit
* @param data.offset
* @returns ProviderCollectionResponse Successful Response
* @throws ApiError
*/
export const useProviderServiceGetProviders = <
TData = Common.ProviderServiceGetProvidersDefaultResponse,
TError = unknown,
TQueryKey extends Array<unknown> = unknown[],
>(
{
limit,
offset,
}: {
limit?: number;
offset?: number;
} = {},
queryKey?: TQueryKey,
options?: Omit<UseQueryOptions<TData, TError>, "queryKey" | "queryFn">,
) =>
useQuery<TData, TError>({
queryKey: Common.UseProviderServiceGetProvidersKeyFn(
{ limit, offset },
queryKey,
),
queryFn: () => ProviderService.getProviders({ limit, offset }) as TData,
...options,
});
/**
* Post Variable
* Create a variable.
Expand Down
33 changes: 33 additions & 0 deletions airflow/ui/openapi-gen/queries/suspense.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
DagService,
DashboardService,
MonitorService,
ProviderService,
VariableService,
} from "../requests/services.gen";
import { DagRunState } from "../requests/types.gen";
Expand Down Expand Up @@ -381,3 +382,35 @@ export const useMonitorServiceGetHealthSuspense = <
queryFn: () => MonitorService.getHealth() as TData,
...options,
});
/**
* Get Providers
* Get providers.
* @param data The data for the request.
* @param data.limit
* @param data.offset
* @returns ProviderCollectionResponse Successful Response
* @throws ApiError
*/
export const useProviderServiceGetProvidersSuspense = <
TData = Common.ProviderServiceGetProvidersDefaultResponse,
TError = unknown,
TQueryKey extends Array<unknown> = unknown[],
>(
{
limit,
offset,
}: {
limit?: number;
offset?: number;
} = {},
queryKey?: TQueryKey,
options?: Omit<UseQueryOptions<TData, TError>, "queryKey" | "queryFn">,
) =>
useSuspenseQuery<TData, TError>({
queryKey: Common.UseProviderServiceGetProvidersKeyFn(
{ limit, offset },
queryKey,
),
queryFn: () => ProviderService.getProviders({ limit, offset }) as TData,
...options,
});
Loading

0 comments on commit e718698

Please sign in to comment.