You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1164 lines
36 KiB

2 months ago
у меня есть AirFlow класстер и github репозиторий для хранения DAGs. Я хочу написать Laravel Jetstream Livewire App для учета и загрузки DAGs в репозиторий чтобы AirFlow мог получить к ним доступ. Никто из пользователей не имеет доступ к Github репозиторию. Доступ осуществляется только через Laravel App в рамках предоставленных прав пользователя. Также я хотел бы видеть статусы выполнения и очередь пользовательского загруженного DAG в Laravel App. Обобщи следующие предложения и напиши финальный пошаговый план для реализации моей задачи:
### **1. Настройка Laravel Jetstream с Livewire**
- **Установка Laravel:**
```bash
composer create-project laravel/laravel airflow-dag-manager
```
- **Установка Jetstream с Livewire:**
```bash
composer require laravel/jetstream
php artisan jetstream:install livewire
npm install
npm run dev
php artisan migrate
```
---
### **2. Реализация аутентификации и авторизации пользователей**
- **Аутентификация:**
Jetstream предоставляет готовые механизмы регистрации, входа и восстановления пароля.
- **Авторизация:**
- Определите роли и разрешения пользователей.
- Используйте **Policies** или **Gates** Laravel для контроля доступа.
- Рекомендуется использовать пакет [Spatie Laravel-Permission](https://github.com/spatie/laravel-permission):
```bash
composer require spatie/laravel-permission
```
- Настройте роли (например, `admin`, `user`) и разрешения (`upload dag`, `view status`).
---
### **3. Интеграция с GitHub API для загрузки DAG-файлов**
- **Аутентификация GitHub API:**
- Создайте **Personal Access Token** с необходимыми правами (`repo` для приватных репозиториев).
- Сохраните токен в файле `.env`:
```
GITHUB_TOKEN=ваш_токен
```
- **Использование GitHub API:**
- Используйте пакет [knplabs/github-api](https://github.com/KnpLabs/php-github-api) или **Guzzle** для взаимодействия с API.
```bash
composer require knplabs/github-api
```
- Пример загрузки файла в репозиторий:
```php
use Github\Client;
$client = new Client();
$client->authenticate(env('GITHUB_TOKEN'), null, Client::AUTH_ACCESS_TOKEN);
$username = 'ваш_логин';
$repository = 'имя_репозитория';
$branch = 'main';
$path = 'dags/' . $dagFilename;
$content = file_get_contents($uploadedDagFile);
// Получение текущего SHA коммита
$reference = $client->api('gitData')->references()->show($username, $repository, 'heads/' . $branch);
$commitSha = $reference['object']['sha'];
// Создание нового блоба
$blob = $client->api('gitData')->blobs()->create($username, $repository, [
'content' => base64_encode($content),
'encoding' => 'base64',
]);
// Создание нового дерева
$tree = $client->api('gitData')->trees()->create($username, $repository, [
'base_tree' => $commitSha,
'tree' => [
[
'path' => $path,
'mode' => '100644',
'type' => 'blob',
'sha' => $blob['sha'],
],
],
]);
// Создание нового коммита
$commit = $client->api('gitData')->commits()->create($username, $repository, [
'message' => 'Добавлен DAG ' . $dagFilename,
'tree' => $tree['sha'],
'parents' => [$commitSha],
]);
// Обновление ссылки
$client->api('gitData')->references()->update($username, $repository, 'heads/' . $branch, [
'sha' => $commit['sha'],
]);
```
- **Отслеживание загруженных DAG:**
- Создайте таблицу `dags` в базе данных с полями `id`, `user_id`, `filename`, `created_at` и т.д.
### **5. Получение статусов выполнения и очереди из Airflow**
- **API Airflow:**
- Включите REST API в `airflow.cfg`:
```
[api]
auth_backend = airflow.api.auth.backend.basic_auth
```
- **Аутентификация:**
- Используйте Basic Auth или другой поддерживаемый метод.
- **Получение статусов DAG:**
```php
use Illuminate\Support\Facades\Http;
$response = Http::withBasicAuth('airflow_username', 'airflow_password')
->get('http://airflow-server:8080/api/v1/dags/{dag_id}/dagRuns');
$dagRuns = $response->json();
```
1. Компонент для загрузки DAG-файлов
1.1. Создание компонента
Создайте Livewire-компонент UploadDagComponent:
```bash
php artisan make:livewire UploadDagComponent
```
1.2. Код компонента
app/Http/Livewire/UploadDagComponent.php
```php
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use Livewire\WithFileUploads;
use Illuminate\Support\Facades\Auth;
use Github\Client;
use Illuminate\Support\Facades\Storage;
class UploadDagComponent extends Component
{
use WithFileUploads;
public $dagFile;
protected $rules = [
'dagFile' => 'required|file|mimes:py|max:1024', // Максимальный размер 1MB
];
public function uploadDag()
{
$this->validate();
// Сохранение файла временно
$path = $this->dagFile->store('temp_dags');
$filename = $this->dagFile->getClientOriginalName();
$content = Storage::get($path);
// Интеграция с GitHub API
$client = new Client();
$client->authenticate(env('GITHUB_TOKEN'), null, Client::AUTH_ACCESS_TOKEN);
$username = env('GITHUB_USERNAME');
$repository = env('GITHUB_REPOSITORY');
$branch = 'main';
$dagPath = 'dags/' . $filename;
// Получение SHA последнего коммита
$reference = $client->api('gitData')->references()->show($username, $repository, 'heads/' . $branch);
$commitSha = $reference['object']['sha'];
// Создание нового блоба
$blob = $client->api('gitData')->blobs()->create($username, $repository, [
'content' => base64_encode($content),
'encoding' => 'base64',
]);
// Создание нового дерева
$tree = $client->api('gitData')->trees()->create($username, $repository, [
'base_tree' => $commitSha,
'tree' => [
[
'path' => $dagPath,
'mode' => '100644',
'type' => 'blob',
'sha' => $blob['sha'],
],
],
]);
// Создание нового коммита
$commit = $client->api('gitData')->commits()->create($username, $repository, [
'message' => 'Добавлен DAG ' . $filename,
'tree' => $tree['sha'],
'parents' => [$commitSha],
]);
// Обновление ссылки
$client->api('gitData')->references()->update($username, $repository, 'heads/' . $branch, [
'sha' => $commit['sha'],
]);
// Удаление временного файла
Storage::delete($path);
// Сохранение информации о DAG в базе данных
Auth::user()->dags()->create([
'filename' => $filename,
'commit_sha' => $commit['sha'],
]);
session()->flash('message', 'DAG успешно загружен и отправлен в репозиторий GitHub.');
// Обновление компонента списка DAG
$this->emit('dagUploaded');
}
public function render()
{
return view('livewire.upload-dag-component');
}
}
```
1.3. Шаблон компонента
resources/views/livewire/upload-dag-component.blade.php
```php
<div>
@if (session()->has('message'))
<div class="alert alert-success">
{{ session('message') }}
</div>
@endif
<form wire:submit.prevent="uploadDag" enctype="multipart/form-data">
<div class="form-group">
<label for="dagFile">Выберите DAG-файл (.py):</label>
<input type="file" wire:model="dagFile" id="dagFile" class="form-control">
@error('dagFile') <span class="text-danger">{{ $message }}</span> @enderror
</div>
<button type="submit" class="btn btn-primary mt-2">Загрузить DAG</button>
</form>
</div>
```
1.4. Обновление модели пользователя
Добавьте связь между пользователем и DAG в модели User.
app/Models/User.php
```php
public function dags()
{
return $this->hasMany(Dag::class);
}
```
2. Компонент для отображения списка DAG-файлов
2.1. Создание компонента
Создайте Livewire-компонент DagListComponent:
```bash
php artisan make:livewire DagListComponent
```
2.2. Код компонента
app/Http/Livewire/DagListComponent.php
```php
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use Illuminate\Support\Facades\Auth;
class DagListComponent extends Component
{
protected $listeners = ['dagUploaded' => 'render'];
public function render()
{
$dags = Auth::user()->dags()->latest()->get();
return view('livewire.dag-list-component', [
'dags' => $dags,
]);
}
}
```
2.3. Шаблон компонента
resources/views/livewire/dag-list-component.blade.php
```php
<div>
<h3>Мои DAG-файлы</h3>
<table class="table">
<thead>
<tr>
<th>Имя файла</th>
<th>Дата загрузки</th>
</tr>
</thead>
<tbody>
@foreach($dags as $dag)
<tr>
<td>{{ $dag->filename }}</td>
<td>{{ $dag->created_at->format('d.m.Y H:i') }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
```
3. Компонент для отображения статусов DAG из Airflow
3.1. Создание компонента
Создайте Livewire-компонент DagStatusComponent:
```bash
php artisan make:livewire DagStatusComponent
```
3.2. Код компонента
app/Http/Livewire/DagStatusComponent.php
```php
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Http;
class DagStatusComponent extends Component
{
public $dagRuns = [];
public function mount()
{
$this->fetchDagStatuses();
}
public function fetchDagStatuses()
{
$airflowUrl = env('AIRFLOW_API_URL');
$username = env('AIRFLOW_USERNAME');
$password = env('AIRFLOW_PASSWORD');
$userDags = Auth::user()->dags()->pluck('filename')->toArray();
$dagIds = array_map(function($filename) {
return pathinfo($filename, PATHINFO_FILENAME);
}, $userDags);
$dagRuns = [];
foreach ($dagIds as $dagId) {
$response = Http::withBasicAuth($username, $password)
->get("$airflowUrl/api/v1/dags/$dagId/dagRuns");
if ($response->ok()) {
$dagRuns[$dagId] = $response->json()['dag_runs'];
} else {
$dagRuns[$dagId] = [];
}
}
$this->dagRuns = $dagRuns;
}
public function render()
{
return view('livewire.dag-status-component');
}
}
```
3.3. Шаблон компонента
resources/views/livewire/dag-status-component.blade.php
```php
<div wire:poll.60000ms="fetchDagStatuses">
<h3>Статусы выполнения DAG</h3>
@foreach($dagRuns as $dagId => $runs)
<h4>DAG ID: {{ $dagId }}</h4>
<table class="table">
<thead>
<tr>
<th>Run ID</th>
<th>Старт</th>
<th>Завершение</th>
<th>Статус</th>
</tr>
</thead>
<tbody>
@foreach($runs as $run)
<tr>
<td>{{ $run['dag_run_id'] }}</td>
<td>{{ $run['start_date'] }}</td>
<td>{{ $run['end_date'] }}</td>
<td>{{ $run['state'] }}</td>
</tr>
@endforeach
</tbody>
</table>
@endforeach
</div>
```
4. Маршруты и отображение компонентов
4.1. Обновление маршрутов
routes/web.php
```php
Route::middleware(['auth:sanctum', 'verified'])->group(function () {
Route::get('/dashboard', function () {
return view('dashboard');
})->name('dashboard');
});
```
4.2. Обновление шаблона панели управления
resources/views/dashboard.blade.php
```php
@extends('layouts.app')
@section('content')
<div class="container">
<h2>Панель управления</h2>
@livewire('upload-dag-component')
@livewire('dag-list-component')
@livewire('dag-status-component')
</div>
@endsection
```
5. Модель DAG
5.1. Создание модели и миграции
Создайте модель Dag с миграцией:
```bash
php artisan make:model Dag -m
```
5.2. Обновление миграции
database/migrations/xxxx_xx_xx_create_dags_table.php
```php
public function up()
{
Schema::create('dags', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->string('filename');
$table->string('commit_sha');
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
```
5.3. Обновление модели DAG
app/Models/Dag.php
```php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Dag extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'filename',
'commit_sha',
];
public function user()
{
return $this->belongsTo(User::class);
}
}
```
5.4. Миграция базы данных
```bash
php artisan migrate
```
6. Настройка переменных окружения
Добавьте следующие переменные в файл .env:
```env
GITHUB_TOKEN=ваш_токен
GITHUB_USERNAME=ваш_логин
GITHUB_REPOSITORY=имя_репозитория
AIRFLOW_API_URL=http://airflow-server:8080
AIRFLOW_USERNAME=airflow_username
AIRFLOW_PASSWORD=airflow_password
```
7. Добавление авторизации (опционально)
Для контроля доступа к компонентам и функциям используйте встроенные возможности Laravel или пакет Spatie Laravel-Permission.
8.3. Уведомления
Реализуйте систему уведомлений при изменении статусов DAG (например, через Laravel Notifications).
1. Компонент UploadDagComponent
Описание:
Этот компонент отвечает за загрузку DAG-файлов пользователями и их сохранение в GitHub репозитории через GitHub API.
Основные функции:
Форма для загрузки файлов.
Валидация загружаемых файлов.
Обработка загрузки и отправка файла в GitHub репозиторий.
Сохранение информации о DAG в базе данных.
Реализация:
Создание компонента:
```bash
php artisan make:livewire UploadDagComponent
```
Свойства компонента:
$file для хранения загружаемого файла.
$dagName имя DAG (если требуется).
Методы компонента:
rules() для определения правил валидации:
```php
protected $rules = [
'file' => 'required|file|mimes:py|max:1024', // Максимум 1MB
];
```
uploadDag() основной метод для обработки загрузки:
Выполнить валидацию файла.
Прочитать содержимое файла.
Использовать GitHub API для загрузки файла в репозиторий (как описано в вашем основном коде).
Сохранить информацию о DAG в базе данных, связав его с текущим пользователем (auth()->user()->id).
Шаблон компонента (Blade):
Форма с полем для выбора файла:
```php
<form wire:submit.prevent="uploadDag">
<input type="file" wire:model="file">
@error('file') <span class="error">{{ $message }}</span> @enderror
<button type="submit">Загрузить DAG</button>
</form>
```
Отображение сообщений об успехе или ошибках.
2. Компонент DagListComponent
Описание:
Этот компонент отображает список DAG-файлов, загруженных текущим пользователем.
Основные функции:
Вывод списка DAG с информацией о каждом файле.
Возможность удаления или обновления DAG (опционально).
Пагинация, если количество DAG большое.
Реализация:
Создание компонента:
bash
Копировать код
php artisan make:livewire DagListComponent
Свойства компонента:
$dags коллекция DAG-файлов пользователя.
Методы компонента:
mount() или render() для загрузки списка DAG:
```php
public function render()
{
$this->dags = Dag::where('user_id', auth()->id())->get();
return view('livewire.dag-list-component');
}
```
deleteDag($dagId) метод для удаления DAG (если необходимо).
Шаблон компонента (Blade):
Таблица или список для отображения DAG:
```php
<table>
<thead>
<tr>
<th>Имя файла</th>
<th>Дата загрузки</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
@foreach($dags as $dag)
<tr>
<td>{{ $dag->filename }}</td>
<td>{{ $dag->created_at }}</td>
<td>
<button wire:click="deleteDag({{ $dag->id }})">Удалить</button>
</td>
</tr>
@endforeach
</tbody>
</table>
```
3. Компонент DagStatusComponent
Описание:
Отображает текущий статус выполнения DAG, получая данные из Airflow API.
Основные функции:
Получение статусов DAG из Airflow API.
Обновление статусов в реальном времени.
Отображение статусов в удобном формате.
Реализация:
Создание компонента:
bash
Копировать код
php artisan make:livewire DagStatusComponent
Свойства компонента:
$dagStatuses массив статусов DAG.
Методы компонента:
mount() для инициализации данных.
getDagStatuses() метод для обращения к Airflow API:
```php
public function getDagStatuses()
{
$dags = Dag::where('user_id', auth()->id())->get();
foreach ($dags as $dag) {
$response = Http::withBasicAuth('airflow_username', 'airflow_password')
->get("http://airflow-server:8080/api/v1/dags/{$dag->dag_id}/dagRuns");
if ($response->successful()) {
$this->dagStatuses[$dag->dag_id] = $response->json();
}
}
}
```
Вы можете использовать wire:poll для автоматического обновления статусов:
```php
<div wire:poll.5000ms="getDagStatuses">
<!-- отображение статусов -->
</div>
```
Шаблон компонента (Blade):
Отображение статусов DAG:
```php
<ul>
@foreach($dagStatuses as $dagId => $status)
<li>DAG {{ $dagId }}: {{ $status['state'] }}</li>
@endforeach
</ul>
```
4. Компонент DagQueueComponent
Описание:
Отображает очередь задач DAG для текущего пользователя, используя данные из Airflow API.
Основные функции:
Получение информации о запланированных и выполняемых задачах.
Обновление данных в реальном времени.
Реализация:
Создание компонента:
bash
Копировать код
php artisan make:livewire DagQueueComponent
Свойства компонента:
$dagQueue массив задач в очереди.
Методы компонента:
getDagQueue() обращение к Airflow API для получения очереди задач:
```php
public function getDagQueue()
{
$response = Http::withBasicAuth('airflow_username', 'airflow_password')
->get('http://airflow-server:8080/api/v1/queues');
if ($response->successful()) {
$this->dagQueue = $response->json();
}
}
```
Используйте wire:poll для обновления данных:
```php
<div wire:poll.5000ms="getDagQueue">
<!-- отображение очереди -->
</div>
```
Шаблон компонента (Blade):
Отображение очереди задач:
```php
<ul>
@foreach($dagQueue as $task)
@if(in_array($task['dag_id'], $userDagIds))
<li>Задача {{ $task['task_id'] }} в DAG {{ $task['dag_id'] }}</li>
@endif
@endforeach
</ul>
```
Здесь $userDagIds массив dag_id текущего пользователя.
Общие рекомендации для компонентов
Валидация и безопасность:
Всегда проверяйте права доступа, чтобы пользователи могли взаимодействовать только со своими данными.
Используйте методы authorize() или проверки внутри методов компонентов.
Обработка ошибок:
Обрабатывайте возможные исключения при работе с внешними API.
Предоставляйте пользователям понятные сообщения об ошибках.
Пользовательский интерфейс:
Делайте интерфейс интуитивно понятным и отзывчивым.
Используйте стандартные компоненты UI или фреймворки CSS, такие как Tailwind CSS (который идет с Jetstream).
Интеграция компонентов в приложение
Маршруты и контроллеры:
Определите маршруты в web.php для страниц, где будут использоваться компоненты.
```php
Route::middleware(['auth:sanctum', 'verified'])->get('/dashboard', function () {
return view('dashboard');
})->name('dashboard');
```
Шаблоны Blade:
Вставьте компоненты в соответствующие шаблоны.
```php
<!-- resources/views/dashboard.blade.php -->
@extends('layouts.app')
@section('content')
<div class="container mx-auto">
<livewire:upload-dag-component />
<livewire:dag-list-component />
<livewire:dag-status-component />
<livewire:dag-queue-component />
</div>
@endsection
```
Дополнительные настройки
Конфигурация Airflow API:
Убедитесь, что Airflow API доступен и настроен для приема запросов от вашего приложения.
Добавьте необходимые переменные в .env файл для хранения URL и данных аутентификации:
```env
AIRFLOW_API_URL=http://airflow-server:8080/api/v1
AIRFLOW_API_USER=airflow_username
AIRFLOW_API_PASSWORD=airflow_password
```
Конфигурация GitHub API:
Обновите конфигурацию GitHub API, если требуется, и храните токен в .env файле:
```env
GITHUB_TOKEN=ваш_токен
GITHUB_USERNAME=ваш_логин
GITHUB_REPOSITORY=имя_репозитория
GITHUB_BRANCH=main
```
Модели и миграции:
Создайте модель Dag и соответствующую миграцию:
bash
Копировать код
php artisan make:model Dag -m
Поля таблицы dags могут включать:
id
user_id
dag_id или filename
created_at
updated_at
Не забудьте установить связь между моделями User и Dag.
```php
// В модели User
public function dags()
{
return $this->hasMany(Dag::class);
}
// В модели Dag
public function user()
{
return $this->belongsTo(User::class);
}
```
Заключение
Следуя этим инструкциям, вы сможете создать полноценное приложение на Laravel Jetstream Livewire, которое позволит пользователям:
Загружать DAG-файлы без прямого доступа к GitHub репозиторию.
Просматривать список своих DAG-файлов.
Отслеживать статусы выполнения и очередь задач своих DAG в Airflow.
Не забудьте протестировать каждую часть приложения и убедиться, что все компоненты работают корректно вместе.
Извиняюсь за недочет. Сейчас я опишу более конкретные шаги разработки приложения с финальным исходным кодом.
### Полный пошаговый план разработки приложения с исходным кодом:
---
### **Шаг 1: Установка Laravel и Jetstream с Livewire**
1. **Создание нового проекта Laravel:**
```bash
composer create-project laravel/laravel airflow-dag-manager
```
2. **Установка Jetstream с Livewire:**
```bash
composer require laravel/jetstream
php artisan jetstream:install livewire
npm install
npm run dev
php artisan migrate
```
3. **Настройка аутентификации:**
Jetstream автоматически добавит базовые функции аутентификации.
---
### **Шаг 2: Настройка ролей и прав доступа**
1. Установка пакета Spatie Laravel-Permission для управления ролями и правами доступа:
```bash
composer require spatie/laravel-permission
```
2. Публикация конфигурации и выполнение миграций:
```bash
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
php artisan migrate
```
3. **Настройка ролей и прав:**
Добавьте роли, например, `admin` и `user`, а также права, такие как `upload dag`, `view status`. Пример настройки ролей можно добавить в seeder:
```php
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
// В seeder:
Role::create(['name' => 'admin']);
Role::create(['name' => 'user']);
Permission::create(['name' => 'upload dag']);
Permission::create(['name' => 'view status']);
```
---
### **Шаг 3: Интеграция с GitHub API**
1. **Создание GitHub Personal Access Token:**
Перейдите в GitHub, создайте новый токен с правами `repo` для доступа к репозиторию. Сохраните его в `.env`:
```env
GITHUB_TOKEN=ваш_токен
GITHUB_USERNAME=ваш_логин
GITHUB_REPOSITORY=имя_репозитория
GITHUB_BRANCH=main
```
2. **Установка библиотеки для работы с GitHub API:**
```bash
composer require knplabs/github-api
```
3. **Создание метода для загрузки DAG в репозиторий:**
Создайте компонент **UploadDagComponent** для загрузки DAG:
```bash
php artisan make:livewire UploadDagComponent
```
**Код компонента UploadDagComponent:**
```php
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use Livewire\WithFileUploads;
use Github\Client;
use Illuminate\Support\Facades\Storage;
class UploadDagComponent extends Component
{
use WithFileUploads;
public $dagFile;
protected $rules = [
'dagFile' => 'required|file|mimes:py|max:1024',
];
public function uploadDag()
{
$this->validate();
// Сохранение временного файла
$path = $this->dagFile->store('temp_dags');
// Получение содержимого файла
$filename = $this->dagFile->getClientOriginalName();
$content = Storage::get($path);
// Интеграция с GitHub API
$client = new Client();
$client->authenticate(env('GITHUB_TOKEN'), null, Client::AUTH_ACCESS_TOKEN);
$username = env('GITHUB_USERNAME');
$repository = env('GITHUB_REPOSITORY');
$branch = env('GITHUB_BRANCH');
$dagPath = 'dags/' . $filename;
// Получение SHA последнего коммита
$reference = $client->api('gitData')->references()->show($username, $repository, 'heads/' . $branch);
$commitSha = $reference['object']['sha'];
// Создание нового блоба
$blob = $client->api('gitData')->blobs()->create($username, $repository, [
'content' => base64_encode($content),
'encoding' => 'base64',
]);
// Создание нового дерева
$tree = $client->api('gitData')->trees()->create($username, $repository, [
'base_tree' => $commitSha,
'tree' => [
[
'path' => $dagPath,
'mode' => '100644',
'type' => 'blob',
'sha' => $blob['sha'],
],
],
]);
// Создание нового коммита
$commit = $client->api('gitData')->commits()->create($username, $repository, [
'message' => 'Добавлен DAG ' . $filename,
'tree' => $tree['sha'],
'parents' => [$commitSha],
]);
// Обновление ссылки
$client->api('gitData')->references()->update($username, $repository, 'heads/' . $branch, [
'sha' => $commit['sha'],
]);
// Удаление временного файла
Storage::delete($path);
// Сообщение об успехе
session()->flash('message', 'DAG успешно загружен и отправлен в репозиторий GitHub.');
}
public function render()
{
return view('livewire.upload-dag-component');
}
}
```
4. **Шаблон компонента (Blade):**
```blade
<div>
@if (session()->has('message'))
<div class="alert alert-success">
{{ session('message') }}
</div>
@endif
<form wire:submit.prevent="uploadDag">
<input type="file" wire:model="dagFile">
@error('dagFile') <span class="text-danger">{{ $message }}</span> @enderror
<button type="submit" class="btn btn-primary mt-2">Загрузить DAG</button>
</form>
</div>
```
---
### **Шаг 4: Синхронизация DAG с Airflow**
1. **Настройка Airflow для получения DAG:**
Вы можете настроить Airflow для автоматического выполнения `git pull` либо использовать GitHub Actions для деплоя DAG на сервер Airflow.
---
### **Шаг 5: Получение статусов выполнения DAG через Airflow API**
1. **Включение Airflow API:**
В `airflow.cfg` добавьте или активируйте следующие строки:
```ini
[api]
auth_backend = airflow.api.auth.backend.basic_auth
```
2. **Запросы к Airflow API для получения статусов DAG:**
Создайте компонент **DagStatusComponent**:
```bash
php artisan make:livewire DagStatusComponent
```
**Код компонента DagStatusComponent:**
```php
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use Illuminate\Support\Facades\Http;
class DagStatusComponent extends Component
{
public $dagRuns = [];
public function mount()
{
$this->fetchDagStatuses();
}
public function fetchDagStatuses()
{
$response = Http::withBasicAuth(env('AIRFLOW_USERNAME'), env('AIRFLOW_PASSWORD'))
->get(env('AIRFLOW_API_URL') . '/api/v1/dags/{dag_id}/dagRuns');
if ($response->ok()) {
$this->dagRuns = $response->json();
}
}
public function render()
{
return view('livewire.dag-status-component');
}
}
```
3. **Шаблон компонента (Blade):**
```blade
<div wire:poll.60000ms="fetchDagStatuses">
<h3>Статусы выполнения DAG</h3>
<table class="table">
<thead>
<tr>
<th>DAG Run ID</th>
<th>Старт</th>
<th>Завершение</th>
<th>Статус</th>
</tr>
</thead>
<tbody>
@foreach($dagRuns as $run)
<tr>
<td>{{ $run['dag_run_id'] }}</td>
<td>{{ $run['start_date'] }}</td>
<td>{{ $run['end_date'] }}</td>
<td>{{ $run['state'] }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
```
---