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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

у меня есть 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>
```
---