diff --git a/phpunit.xml.dist b/phpunit.xml.dist index f6da34e..7b99837 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -15,6 +15,7 @@ + diff --git a/src/Controller/DeployImageAction.php b/src/Controller/DeployImageAction.php index a586835..ae59bc3 100644 --- a/src/Controller/DeployImageAction.php +++ b/src/Controller/DeployImageAction.php @@ -60,6 +60,10 @@ class DeployImageAction extends AbstractController ]; $agentJobId = $this->deployImageOgAgentAction->__invoke($image, $input, $client->getEntity(), DeployMethodTypes::UNICAST); + if (!$agentJobId){ + continue; + } + $this->createService->__invoke($client->getEntity(), CommandTypes::DEPLOY_IMAGE, TraceStatus::IN_PROGRESS, $agentJobId, $inputData); } break; @@ -85,11 +89,14 @@ class DeployImageAction extends AbstractController try { $this->deployImageOgRepositoryAction->__invoke($input, $image, $client->getEntity(), $this->httpClient); } catch (\Exception $e) { - //return new JsonResponse(data: ['error' => $e->getMessage()], status: Response::HTTP_INTERNAL_SERVER_ERROR); continue; } $agentJobId = $this->deployImageOgAgentAction->__invoke($image, $input, $client->getEntity(), DeployMethodTypes::MULTICAST); + if (!$agentJobId){ + continue; + } + $this->createService->__invoke($client->getEntity(), CommandTypes::DEPLOY_IMAGE, TraceStatus::IN_PROGRESS, $agentJobId, $inputData); } break; @@ -109,11 +116,14 @@ class DeployImageAction extends AbstractController try { $this->deployImageOgRepositoryAction->__invoke($input, $image, $client->getEntity(), $this->httpClient); } catch (\Exception $e) { - //return new JsonResponse(data: ['error' => $e->getMessage()], status: Response::HTTP_INTERNAL_SERVER_ERROR); continue; } $agentJobId = $this->deployImageOgAgentAction->__invoke($image, $input, $client->getEntity(), DeployMethodTypes::TORRENT); + if (!$agentJobId){ + continue; + } + $this->createService->__invoke($client->getEntity(), CommandTypes::DEPLOY_IMAGE, TraceStatus::IN_PROGRESS, $agentJobId, $inputData); } diff --git a/src/Controller/OgAgent/DeployImageAction.php b/src/Controller/OgAgent/DeployImageAction.php index 1c5b1c9..eaacd9b 100644 --- a/src/Controller/OgAgent/DeployImageAction.php +++ b/src/Controller/OgAgent/DeployImageAction.php @@ -18,6 +18,7 @@ use App\Service\Trace\CreateService; use Doctrine\ORM\EntityManagerInterface; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; @@ -39,6 +40,12 @@ class DeployImageAction extends AbstractController { } + /** + * @throws RedirectionExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ public function __invoke(ImageImageRepository $imageImageRepository, DeployImageInput $input, Client $client, string $method) { $image = $imageImageRepository->getImage(); @@ -95,11 +102,15 @@ class DeployImageAction extends AbstractController ]); $this->logger->info('Deploying image', ['image' => $image->getId()]); - } catch (TransportExceptionInterface $e) { - $this->logger->error('Error deploying image', ['image' => $image->getId(), 'error' => $e->getMessage()]); + $jobId = json_decode($response->getContent(), true)['job_id']; + } catch (ClientExceptionInterface | ServerExceptionInterface | TransportExceptionInterface | TransportException $e) { + $this->logger->error('Error deploying image', [ + 'image' => $image->getId() ?? 'unknown', + 'error' => $e->getMessage() + ]); + return null; } - $jobId = json_decode($response->getContent(), true)['job_id']; $client->setStatus(ClientStatus::BUSY); $this->entityManager->persist($client); diff --git a/src/Controller/OgAgent/PowerOffAction.php b/src/Controller/OgAgent/PowerOffAction.php index 4817ca5..39f2e5b 100644 --- a/src/Controller/OgAgent/PowerOffAction.php +++ b/src/Controller/OgAgent/PowerOffAction.php @@ -17,6 +17,7 @@ use App\Service\Trace\CreateService; use Doctrine\ORM\EntityManagerInterface; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; @@ -67,14 +68,16 @@ class PowerOffAction extends AbstractController 'json' => $data, ]); $this->logger->info('Powering off client', ['client' => $client->getId()]); + $jobId = json_decode($response->getContent(), true)['job_id']; - } catch (TransportExceptionInterface $e) { - $this->logger->error('Error powering off client', ['client' => $client->getId(), 'error' => $e->getMessage()]); + } catch (ClientExceptionInterface | ServerExceptionInterface | TransportExceptionInterface | TransportException $e) { + $this->logger->error('Error power off client', [ + 'image' => $client->getIp(), + 'error' => $e->getMessage() + ]); continue; } - $jobId = json_decode($response->getContent(), true)['job_id']; - $client->setStatus(ClientStatus::TURNING_OFF); $this->entityManager->persist($client); $this->entityManager->flush(); @@ -82,6 +85,6 @@ class PowerOffAction extends AbstractController $this->createService->__invoke($client, CommandTypes::SHUTDOWN, TraceStatus::SUCCESS, $jobId, []); } - return new JsonResponse(data: $client, status: Response::HTTP_OK); + return new JsonResponse(data: [], status: Response::HTTP_OK); } } diff --git a/src/Controller/OgRepository/AbstractOgRepositoryController.php b/src/Controller/OgRepository/AbstractOgRepositoryController.php index effcb5c..eb61f33 100644 --- a/src/Controller/OgRepository/AbstractOgRepositoryController.php +++ b/src/Controller/OgRepository/AbstractOgRepositoryController.php @@ -55,6 +55,7 @@ abstract class AbstractOgRepositoryController extends AbstractController $this->logger->error(sprintf('Client/Server error in request to %s: %s', $url, $e->getMessage())); return [ + 'code' => Response::HTTP_INTERNAL_SERVER_ERROR, 'error' => 'Client/Server error', 'details' => $e->getMessage(), ]; @@ -62,6 +63,7 @@ abstract class AbstractOgRepositoryController extends AbstractController $this->logger->error(sprintf('Transport error in request to %s: %s', $url, $e->getMessage())); return [ + 'code' => Response::HTTP_INTERNAL_SERVER_ERROR, 'error' => 'Transport error', 'details' => $e->getMessage(), ]; diff --git a/src/Controller/OgRepository/Image/CancelTransmissionAction.php b/src/Controller/OgRepository/Image/CancelTransmissionAction.php index 29e950d..eec94f2 100644 --- a/src/Controller/OgRepository/Image/CancelTransmissionAction.php +++ b/src/Controller/OgRepository/Image/CancelTransmissionAction.php @@ -2,7 +2,66 @@ namespace App\Controller\OgRepository\Image; -class CancelTransmissionAction -{ +use App\Controller\OgRepository\AbstractOgRepositoryController; +use App\Entity\Client; +use App\Entity\Image; +use App\Entity\ImageImageRepository; +use App\Entity\Trace; +use App\Model\CommandTypes; +use App\Model\TraceStatus; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Attribute\AsController; +use Symfony\Component\Validator\Exception\ValidatorException; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +#[AsController] +class CancelTransmissionAction extends AbstractOgRepositoryController +{ + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ClientExceptionInterface + */ + public function __invoke(Trace $data): JsonResponse + { + if ($data->getCommand() !== CommandTypes::DEPLOY_IMAGE) { + throw new ValidatorException('Command is not DEPLOY_IMAGE'); + } + + $input = $data->getInput(); + + if (!isset($input['client']) || !isset($input['image']) || !isset($input['method'])) { + throw new ValidatorException('Client, image and method are required'); + } + $client = $this->entityManager->getRepository(Client::class)->findOneBy(['uuid' => $input['client']]); + $image = $this->entityManager->getRepository(ImageImageRepository::class)->findOneBy(['uuid' => $input['image']]); + + if (!$client || !$image) { + throw new ValidatorException('Client or image not found'); + } + + $method = $input['method']; + + if (!$image->getImageFullsum()) { + throw new ValidatorException('Fullsum is required'); + } + + $content = $this->createRequest('DELETE', 'http://'.$image->getRepository()->getIp().':8006/ogrepository/v1/'.$method.'/images/'.$image->getImageFullsum()); + + if (isset($content['error']) && $content['error'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { + throw new ValidatorException('Error cancelling transmission'); + } + + $data->setStatus(TraceStatus::CANCELLED); + $this->entityManager->persist($data); + $this->entityManager->flush(); + + return new JsonResponse(data: $content, status: Response::HTTP_OK); + } } \ No newline at end of file diff --git a/src/Controller/OgRepository/Image/GetStatusAction.php b/src/Controller/OgRepository/Image/GetStatusAction.php index 329c53e..37d5085 100644 --- a/src/Controller/OgRepository/Image/GetStatusAction.php +++ b/src/Controller/OgRepository/Image/GetStatusAction.php @@ -2,7 +2,40 @@ namespace App\Controller\OgRepository\Image; -class GetStatusAction -{ +use App\Controller\OgRepository\AbstractOgRepositoryController; +use App\Entity\Image; +use App\Entity\ImageImageRepository; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Attribute\AsController; +use Symfony\Component\Validator\Exception\ValidatorException; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +#[AsController] +class GetStatusAction extends AbstractOgRepositoryController +{ + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ClientExceptionInterface + */ + public function __invoke(ImageImageRepository $data): JsonResponse + { + if (!$data->getImageFullsum()) { + throw new ValidatorException('Fullsum is required'); + } + + $content = $this->createRequest('GET', 'http://'.$data->getRepository()->getIp().':8006/ogrepository/v1/status/images/'.$data->getImageFullsum()); + + if (isset($content['error']) && $content['error'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { + throw new ValidatorException('Error getting status'); + } + + return new JsonResponse(data: $content, status: Response::HTTP_OK); + } } \ No newline at end of file diff --git a/src/Controller/OgRepository/WoLAction.php b/src/Controller/OgRepository/WoLAction.php index e486651..814d7b9 100644 --- a/src/Controller/OgRepository/WoLAction.php +++ b/src/Controller/OgRepository/WoLAction.php @@ -58,11 +58,16 @@ class WoLAction extends AbstractOgRepositoryController $content = $this->createRequest('POST', 'http://'.$repository->getIp(). ':8006/ogrepository/v1/wol', $params); + if (isset($content['error']) && $content['error'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { + $this->logger->error('Error sending WoL to client', ['mac' => $client->getMac()]); + continue; + } + $client->setStatus(ClientStatus::INITIALIZING); $this->entityManager->persist($client); $this->entityManager->flush(); - $this->createService->__invoke($client, CommandTypes::SHUTDOWN, TraceStatus::SUCCESS, '', []); + $this->createService->__invoke($client, CommandTypes::POWER_ON, TraceStatus::SUCCESS, '', []); } return new JsonResponse(data: [], status: Response::HTTP_OK);