diff --git a/src/app/drivers/DevicePOEPowerDriver.go b/src/app/drivers/DevicePOEPowerDriver.go new file mode 100644 index 00000000..90447e5a --- /dev/null +++ b/src/app/drivers/DevicePOEPowerDriver.go @@ -0,0 +1,130 @@ +package drivers + +import ( + "context" + "github.com/google/uuid" + "rol/app/errors" + "rol/app/interfaces" + "rol/domain" +) + +//DevicePOEPowerDriver - power control driver for devices that uses POE as power supply +type DevicePOEPowerDriver struct { + provider interfaces.IEthernetSwitchManagerProvider + devEthRepo interfaces.IGenericRepository[uuid.UUID, domain.DeviceNetworkInterface] + switchPortsRepo interfaces.IGenericRepository[uuid.UUID, domain.EthernetSwitchPort] + devPowerHistory interfaces.IGenericRepository[uuid.UUID, domain.DevicePowerState] +} + +//NewDevicePOEPowerDriver - constructor for DevicePOEPowerDriver +func NewDevicePOEPowerDriver( + provider interfaces.IEthernetSwitchManagerProvider, + devEthRepo interfaces.IGenericRepository[uuid.UUID, domain.DeviceNetworkInterface], + switchPortsRepo interfaces.IGenericRepository[uuid.UUID, domain.EthernetSwitchPort], + devPowerHistory interfaces.IGenericRepository[uuid.UUID, domain.DevicePowerState], +) *DevicePOEPowerDriver { + return &DevicePOEPowerDriver{ + provider: provider, + devEthRepo: devEthRepo, + switchPortsRepo: switchPortsRepo, + devPowerHistory: devPowerHistory, + } +} + +func (p *DevicePOEPowerDriver) getDeviceEthPort(ctx context.Context, device domain.Device) (domain.DeviceNetworkInterface, error) { + devPort := domain.DeviceNetworkInterface{} + devPorts, err := p.devEthRepo.GetList(ctx, "", "", 1, 1, nil) + if err != nil { + return devPort, errors.Internal.Wrapf(err, "failed to get ethernet ports for device: %s", device.ID) + } + if len(devPorts) < 1 { + return devPort, errors.Internal.Wrapf(err, "device with id: %s not have POE ports", device.ID) + } + return devPorts[0], nil +} + +func (p *DevicePOEPowerDriver) getConnectedSwitchPort(ctx context.Context, devPort domain.DeviceNetworkInterface) (domain.EthernetSwitchPort, error) { + ethPortQuery := p.switchPortsRepo.NewQueryBuilder(ctx) + ethPortQuery.Where("EthernetSwitchID", "==", devPort.ConnectedSwitchId) + switchPort, err := p.switchPortsRepo.GetByIDExtended(ctx, devPort.ConnectedSwitchPortId, ethPortQuery) + if err != nil { + return domain.EthernetSwitchPort{}, errors.Internal.Wrapf(err, "failed to get connected switch port for device: %s", devPort.DeviceID) + } + return switchPort, nil +} + +func (p *DevicePOEPowerDriver) getSwitchPortNameAndManager(ctx context.Context, dev domain.Device) ( + string, interfaces.IEthernetSwitchManager, error, +) { + devEthPort, err := p.getDeviceEthPort(ctx, dev) + if err != nil { + return "", nil, err + } + switchEthPort, err := p.getConnectedSwitchPort(ctx, devEthPort) + if err != nil { + return "", nil, errors.Internal.Wrapf(err, "get power state of device with id %s failed", dev.ID.String()) + } + switchManager, err := p.provider.Get(ctx, devEthPort.ConnectedSwitchId) + if err != nil { + return "", nil, errors.Internal.Wrapf(err, "get ethernet switch provider failed for device: %s", dev.ID.String()) + } + return switchEthPort.Name, switchManager, nil +} + +//GetPowerState - get device power status from power supply controller +func (p *DevicePOEPowerDriver) GetPowerState(ctx context.Context, dev domain.Device) (domain.DevPowerState, error) { + devUnkState := domain.DevInPowerUnknownState + portName, switchManager, err := p.getSwitchPortNameAndManager(ctx, dev) + if err != nil { + return devUnkState, err + } + poeStatus, err := switchManager.GetPOEPortStatus(portName) + if err != nil { + return devUnkState, errors.Internal.Wrapf(err, "failed to get power state of device with id: %s", dev.ID.String()) + } + switch poeStatus { + case "enable": + return domain.DevInPowerOnState, nil + } + return domain.DevInPowerOffState, nil +} + +//PowerOff device +func (p *DevicePOEPowerDriver) PowerOff(ctx context.Context, dev domain.Device) error { + portName, switchManager, err := p.getSwitchPortNameAndManager(ctx, dev) + if err != nil { + return err + } + err = switchManager.DisablePOEPort(portName) + if err != nil { + return errors.Internal.Wrapf(err, "disable POE power for device %s failed", dev.ID) + } + _, err = p.devPowerHistory.Insert(ctx, domain.DevicePowerState{ + DeviceID: dev.ID, + DevPowerState: domain.DevInPowerOffState, + }) + if err != nil { + return errors.Internal.Wrapf(err, "save POE power history for device %s failed", dev.ID) + } + return nil +} + +//PowerOn device +func (p *DevicePOEPowerDriver) PowerOn(ctx context.Context, dev domain.Device) error { + portName, switchManager, err := p.getSwitchPortNameAndManager(ctx, dev) + if err != nil { + return err + } + err = switchManager.EnablePOEPort(portName, "poe+") + if err != nil { + return errors.Internal.Wrapf(err, "enable POE power for device %s failed", dev.ID) + } + _, err = p.devPowerHistory.Insert(ctx, domain.DevicePowerState{ + DeviceID: dev.ID, + DevPowerState: domain.DevInPowerOnState, + }) + if err != nil { + return errors.Internal.Wrapf(err, "save POE power history for device %s failed", dev.ID) + } + return nil +} diff --git a/src/app/interfaces/IDevicePowerDriver.go b/src/app/interfaces/IDevicePowerDriver.go new file mode 100644 index 00000000..14742294 --- /dev/null +++ b/src/app/interfaces/IDevicePowerDriver.go @@ -0,0 +1,12 @@ +package interfaces + +import ( + "context" + "rol/domain" +) + +type IDevicePowerDriver interface { + GetPowerState(ctx context.Context, device domain.Device) (domain.DevPowerState, error) + PowerOn(ctx context.Context, device domain.Device) error + PowerOff(ctx context.Context, device domain.Device) error +} diff --git a/src/app/mappers/DeviceMapper.go b/src/app/mappers/DeviceMapper.go new file mode 100644 index 00000000..8afb851b --- /dev/null +++ b/src/app/mappers/DeviceMapper.go @@ -0,0 +1,39 @@ +// Package mappers uses for entity <--> dto conversions +package mappers + +import ( + "github.com/google/uuid" + "rol/domain" + "rol/dtos" +) + +//MapDeviceToDto writes Device entity to dto +//Params +// entity - Device entity +// dto - dest Device dto +func MapDeviceToDto(entity domain.Device, dto *dtos.DeviceDto) { + mapEntityToBaseDto[uuid.UUID](entity, &dto.BaseDto) + dto.Name = entity.Name + dto.Model = entity.Model + dto.PowerControlBus = entity.PowerControlBus +} + +//MapDeviceCreateDtoToEntity writes Device create dto fields to entity +//Params +// dto - Device create dto +// entity - dest Device entity +func MapDeviceCreateDtoToEntity(dto dtos.DeviceCreateDto, entity *domain.Device) { + entity.Name = dto.Name + entity.Model = dto.Model + entity.PowerControlBus = dto.PowerControlBus +} + +//MapDeviceUpdateDtoToEntity writes Device update dto fields to entity +//Params +// dto - Device update dto +// entity - dest Device entity +func MapDeviceUpdateDtoToEntity(dto dtos.DeviceUpdateDto, entity *domain.Device) { + entity.Name = dto.Name + entity.Model = dto.Model + entity.PowerControlBus = dto.PowerControlBus +} diff --git a/src/app/mappers/DeviceNetworkInterfaceMapper.go b/src/app/mappers/DeviceNetworkInterfaceMapper.go new file mode 100644 index 00000000..1ebd0f7a --- /dev/null +++ b/src/app/mappers/DeviceNetworkInterfaceMapper.go @@ -0,0 +1,39 @@ +// Package mappers uses for entity <--> dto conversions +package mappers + +import ( + "github.com/google/uuid" + "rol/domain" + "rol/dtos" +) + +//MapDeviceNetworkInterfaceToDto writes DeviceNetworkInterface entity to dto +//Params +// entity - DeviceNetworkInterface entity +// dto - dest DeviceNetworkInterface dto +func MapDeviceNetworkInterfaceToDto(entity domain.DeviceNetworkInterface, dto *dtos.DeviceNetworkInterfaceDto) { + mapEntityToBaseDto[uuid.UUID](entity, &dto.BaseDto) + dto.Mac = entity.Mac + dto.ConnectedSwitchPortId = entity.ConnectedSwitchPortId + dto.ConnectedSwitchId = entity.ConnectedSwitchId +} + +//MapDeviceNetworkInterfaceCreateDtoToEntity writes DeviceNetworkInterface create dto fields to entity +//Params +// dto - DeviceNetworkInterface create dto +// entity - dest DeviceNetworkInterface entity +func MapDeviceNetworkInterfaceCreateDtoToEntity(dto dtos.DeviceNetworkInterfaceCreateDto, entity *domain.DeviceNetworkInterface) { + entity.Mac = dto.Mac + entity.ConnectedSwitchId = dto.ConnectedSwitchId + entity.ConnectedSwitchPortId = dto.ConnectedSwitchPortId +} + +//MapDeviceNetworkInterfaceUpdateDtoToEntity writes DeviceNetworkInterface update dto fields to entity +//Params +// dto - DeviceNetworkInterface update dto +// entity - dest DeviceNetworkInterface entity +func MapDeviceNetworkInterfaceUpdateDtoToEntity(dto dtos.DeviceNetworkInterfaceUpdateDto, entity *domain.DeviceNetworkInterface) { + entity.Mac = dto.Mac + entity.ConnectedSwitchId = dto.ConnectedSwitchId + entity.ConnectedSwitchPortId = dto.ConnectedSwitchPortId +} diff --git a/src/app/mappers/EntityDtoMapper.go b/src/app/mappers/EntityDtoMapper.go index 7ecea29d..7c83a2aa 100644 --- a/src/app/mappers/EntityDtoMapper.go +++ b/src/app/mappers/EntityDtoMapper.go @@ -65,6 +65,16 @@ func MapDtoToEntity(dto interface{}, entity interface{}) error { MapDHCP4LeaseCreateDtoToEntity(dto.(dtos.DHCP4LeaseCreateDto), entity.(*domain.DHCP4Lease)) case dtos.DHCP4LeaseUpdateDto: MapDHCP4LeaseUpdateDtoToEntity(dto.(dtos.DHCP4LeaseUpdateDto), entity.(*domain.DHCP4Lease)) + //Device + case dtos.DeviceCreateDto: + MapDeviceCreateDtoToEntity(dto.(dtos.DeviceCreateDto), entity.(*domain.Device)) + case dtos.DeviceUpdateDto: + MapDeviceUpdateDtoToEntity(dto.(dtos.DeviceUpdateDto), entity.(*domain.Device)) + //DeviceNetworkInterface + case dtos.DeviceNetworkInterfaceCreateDto: + MapDeviceNetworkInterfaceCreateDtoToEntity(dto.(dtos.DeviceNetworkInterfaceCreateDto), entity.(*domain.DeviceNetworkInterface)) + case dtos.DeviceNetworkInterfaceUpdateDto: + MapDeviceNetworkInterfaceUpdateDtoToEntity(dto.(dtos.DeviceNetworkInterfaceUpdateDto), entity.(*domain.DeviceNetworkInterface)) default: return errors.Internal.Newf("can't find route for map dto %+v to entity %+v", dto, entity) } @@ -115,7 +125,12 @@ func MapEntityToDto(entity interface{}, dto interface{}) error { //DHCP4Lease case domain.DHCP4Lease: MapDHCP4LeaseToDto(entity.(domain.DHCP4Lease), dto.(*dtos.DHCP4LeaseDto)) - + //Device + case domain.Device: + MapDeviceToDto(entity.(domain.Device), dto.(*dtos.DeviceDto)) + //DeviceNetworkInterface + case domain.DeviceNetworkInterface: + MapDeviceNetworkInterfaceToDto(entity.(domain.DeviceNetworkInterface), dto.(*dtos.DeviceNetworkInterfaceDto)) default: return errors.Internal.Newf("can't find route for map entity %+v to dto %+v", dto, entity) } diff --git a/src/app/providers/DevicePowerDriverProvider.go b/src/app/providers/DevicePowerDriverProvider.go new file mode 100644 index 00000000..4b4cf71d --- /dev/null +++ b/src/app/providers/DevicePowerDriverProvider.go @@ -0,0 +1,24 @@ +package providers + +import ( + "rol/app/drivers" + "rol/app/interfaces" + "rol/domain" +) + +type DevicePowerDriverProvider struct { + poeDriver *drivers.DevicePOEPowerDriver +} + +func NewDevicePowerDriverProvider(poeDriver *drivers.DevicePOEPowerDriver) *DevicePowerDriverProvider { + return &DevicePowerDriverProvider{ + poeDriver: poeDriver, + } +} + +func (p *DevicePowerDriverProvider) GetPowerManagerDriver(device domain.Device) (interfaces.IDevicePowerDriver, error) { + if device.PowerControlBus == "POE" { + return p.poeDriver, nil + } + return nil, nil +} diff --git a/src/app/services/DeviceService.go b/src/app/services/DeviceService.go new file mode 100644 index 00000000..e9e47bc7 --- /dev/null +++ b/src/app/services/DeviceService.go @@ -0,0 +1,105 @@ +// Package services stores business logic for each entity +package services + +import ( + "context" + "github.com/google/uuid" + "github.com/sirupsen/logrus" + "rol/app/errors" + "rol/app/interfaces" + "rol/app/providers" + "rol/domain" + "rol/dtos" +) + +//DeviceService service structure for manage device entity and sub-entities +type DeviceService struct { + devRepo interfaces.IGenericRepository[uuid.UUID, domain.Device] + devEthRepo interfaces.IGenericRepository[uuid.UUID, domain.DeviceNetworkInterface] + powerStateHistory interfaces.IGenericRepository[uuid.UUID, domain.DevicePowerState] + powerDriverProvider *providers.DevicePowerDriverProvider + log *logrus.Logger +} + +func NewDeviceService( + devRepo interfaces.IGenericRepository[uuid.UUID, domain.Device], + devEthRepo interfaces.IGenericRepository[uuid.UUID, domain.DeviceNetworkInterface], + powerStateHistory interfaces.IGenericRepository[uuid.UUID, domain.DevicePowerState], + powerDriverProvider *providers.DevicePowerDriverProvider, + log *logrus.Logger, +) *DeviceService { + return &DeviceService{ + devRepo: devRepo, + devEthRepo: devEthRepo, + powerStateHistory: powerStateHistory, + powerDriverProvider: powerDriverProvider, + log: log, + } +} + +func (s *DeviceService) CheckDeviceExistence(ctx context.Context, deviceID uuid.UUID) error { + exist, err := s.devRepo.IsExist(ctx, deviceID, nil) + if err != nil { + return errors.Internal.Wrapf(err, "failed to check existence of the device with id: %s", deviceID) + } + if !exist { + return errors.NotFound.Newf("device with id %s not found", deviceID) + } + return nil +} + +func (s *DeviceService) GetDevicesList(ctx context.Context, search, orderBy, orderDirection string, page, pageSize int) (dtos.PaginatedItemsDto[dtos.DeviceDto], error) { + devices, err := GetList[dtos.DeviceDto](ctx, s.devRepo, search, orderBy, orderDirection, page, pageSize) + if err != nil { + return devices, errors.Internal.Wrap(err, "failed to get tftp server configs list") + } + for i, device := range devices.Items { + (&devices.Items[i]).PowerState = s.getLastPowerStateString(ctx, device.ID) + } + return devices, nil +} + +func (s *DeviceService) GetDeviceByID(ctx context.Context, id uuid.UUID) (dtos.DeviceDto, error) { + dto, err := GetByID[dtos.DeviceDto](ctx, s.devRepo, id, nil) + if err != nil { + return dto, err + } + state := s.getLastPowerStateString(ctx, id) + dto.PowerState = state + return dto, nil +} + +func (s *DeviceService) UpdateDevice(ctx context.Context, id uuid.UUID, updateDto dtos.DeviceUpdateDto) (dtos.DeviceDto, error) { + dto, err := Update[dtos.DeviceDto](ctx, s.devRepo, updateDto, id, nil) + if err != nil { + return dto, err + } + dto.PowerState = s.getLastPowerStateString(ctx, id) + return dto, nil +} + +func (s *DeviceService) CreateDevice(ctx context.Context, createDto dtos.DeviceCreateDto) (dtos.DeviceDto, error) { + dto, err := Create[dtos.DeviceDto](ctx, s.devRepo, createDto) + if err != nil { + return dto, err + } + dto.PowerState = s.getLastPowerStateString(ctx, dto.ID) + return dto, nil +} + +func (s *DeviceService) DeleteDevice(ctx context.Context, id uuid.UUID) error { + err := s.CheckDeviceExistence(ctx, id) + if err != nil { + return err + } + queryBuilder := s.getDeviceIDQueryBuilder(ctx, id) + err = s.devEthRepo.DeleteAll(ctx, queryBuilder) + if err != nil { + return errors.Internal.Wrapf(err, "delete network interfaces failed for device %s", id.String()) + } + err = s.powerStateHistory.DeleteAll(ctx, queryBuilder) + if err != nil { + return errors.Internal.Wrapf(err, "delete power history failed for device %s", id.String()) + } + return s.devRepo.Delete(ctx, id) +} diff --git a/src/app/services/DeviceServiceNetInterfaces.go b/src/app/services/DeviceServiceNetInterfaces.go new file mode 100644 index 00000000..90323417 --- /dev/null +++ b/src/app/services/DeviceServiceNetInterfaces.go @@ -0,0 +1,71 @@ +package services + +import ( + "context" + "github.com/google/uuid" + "rol/app/interfaces" + "rol/dtos" +) + +func (s *DeviceService) getDeviceIDQueryBuilder(ctx context.Context, deviceID uuid.UUID) interfaces.IQueryBuilder { + queryBuilder := s.devEthRepo.NewQueryBuilder(ctx) + queryBuilder.Where("DeviceID", "==", deviceID) + return queryBuilder +} + +func (s *DeviceService) GetNetInterfacesList(ctx context.Context, deviceID uuid.UUID, search, orderBy, orderDirection string, page, pageSize int) (dtos.PaginatedItemsDto[dtos.DeviceNetworkInterfaceDto], error) { + err := s.CheckDeviceExistence(ctx, deviceID) + if err != nil { + return dtos.PaginatedItemsDto[dtos.DeviceNetworkInterfaceDto]{}, err + } + queryBuilder := s.getDeviceIDQueryBuilder(ctx, deviceID) + AddSearchInAllFields(search, s.devEthRepo, queryBuilder) + netInterfaces, err := GetListExtended[dtos.DeviceNetworkInterfaceDto](ctx, s.devEthRepo, queryBuilder, orderBy, + orderDirection, page, pageSize) + if err != nil { + return netInterfaces, err + } + return netInterfaces, nil +} + +func (s *DeviceService) GetNetInterfaceByID(ctx context.Context, deviceID uuid.UUID, devNetID uuid.UUID) ( + dtos.DeviceNetworkInterfaceDto, error, +) { + queryBuilder := s.getDeviceIDQueryBuilder(ctx, deviceID) + netInterface, err := GetByID[dtos.DeviceNetworkInterfaceDto](ctx, s.devEthRepo, devNetID, queryBuilder) + if err != nil { + return netInterface, err + } + return netInterface, nil +} + +func (s *DeviceService) CreateNetInterface(ctx context.Context, deviceID uuid.UUID, + createDto dtos.DeviceNetworkInterfaceCreateDto) (dtos.DeviceNetworkInterfaceDto, error) { + err := s.CheckDeviceExistence(ctx, deviceID) + if err != nil { + return dtos.DeviceNetworkInterfaceDto{}, err + } + netInterface, err := Create[dtos.DeviceNetworkInterfaceDto](ctx, s.devEthRepo, createDto) + if err != nil { + return netInterface, err + } + return netInterface, nil +} + +func (s *DeviceService) UpdateNetInterface(ctx context.Context, deviceID uuid.UUID, devNetID uuid.UUID, + updateDto dtos.DeviceNetworkInterfaceUpdateDto) (dtos.DeviceNetworkInterfaceDto, error) { + queryBuilder := s.getDeviceIDQueryBuilder(ctx, deviceID) + netInterface, err := Update[dtos.DeviceNetworkInterfaceDto](ctx, s.devEthRepo, updateDto, devNetID, queryBuilder) + if err != nil { + return netInterface, err + } + return netInterface, nil +} + +func (s *DeviceService) DeleteNetInterface(ctx context.Context, deviceID uuid.UUID, devNetID uuid.UUID) error { + err := s.CheckDeviceExistence(ctx, deviceID) + if err != nil { + return err + } + return s.devEthRepo.Delete(ctx, devNetID) +} diff --git a/src/app/services/DeviceServicePower.go b/src/app/services/DeviceServicePower.go new file mode 100644 index 00000000..d96d9935 --- /dev/null +++ b/src/app/services/DeviceServicePower.go @@ -0,0 +1,58 @@ +package services + +import ( + "context" + "github.com/google/uuid" + "github.com/sirupsen/logrus" + "rol/app/errors" + "rol/domain" + "rol/dtos" +) + +func (s *DeviceService) DevicePowerCommand(ctx context.Context, deviceID uuid.UUID, dto dtos.DevicePowerCommandDto) error { + err := s.CheckDeviceExistence(ctx, deviceID) + if err != nil { + return err + } + dev, err := s.devRepo.GetByID(ctx, deviceID) + if err != nil { + return errors.Internal.Wrapf(err, "failed to get device with id %s", deviceID.String()) + } + powerManagerDriver, err := s.powerDriverProvider.GetPowerManagerDriver(dev) + if err != nil { + return errors.Internal.Wrapf(err, "get power manager error for device %s", deviceID.String()) + } + switch dto.Command { + case "On": + err = powerManagerDriver.PowerOn(ctx, dev) + case "Off": + err = powerManagerDriver.PowerOff(ctx, dev) + default: + return errors.Internal.Newf("unknown power command for device %s", deviceID.String()) + } + return nil +} + +func (s *DeviceService) getLastPowerState(ctx context.Context, deviceID uuid.UUID) (domain.DevPowerState, error) { + err := s.CheckDeviceExistence(ctx, deviceID) + if err != nil { + return domain.DevInPowerUnknownState, err + } + queryBuilder := s.getDeviceIDQueryBuilder(ctx, deviceID) + states, err := s.powerStateHistory.GetList(ctx, "CreatedAt", "desc", 1, 1, queryBuilder) + if err != nil { + return domain.DevInPowerUnknownState, errors.Internal.Wrapf(err, "get power state history failed for device %s", deviceID.String()) + } + if len(states) < 1 { + return domain.DevInPowerUnknownState, nil + } + return states[0].DevPowerState, nil +} + +func (s *DeviceService) getLastPowerStateString(ctx context.Context, deviceID uuid.UUID) string { + state, err := s.getLastPowerState(ctx, deviceID) + if err != nil { + logrus.Errorf("get last power state error for device %s: %s", deviceID, err) + } + return state.String() +} diff --git a/src/app/services/EthernetSwitchService.go b/src/app/services/EthernetSwitchService.go index 6ea33391..e6b2dd57 100644 --- a/src/app/services/EthernetSwitchService.go +++ b/src/app/services/EthernetSwitchService.go @@ -56,6 +56,12 @@ func (e *EthernetSwitchService) initSupportedList() { Code: "unifi_switch_us-24-250w", } *e.supportedList = append(*e.supportedList, ubiquityUnifiSwitchUs24250W) + tpLink := domain.EthernetSwitchModel{ + Model: "TL-SG2210MP", + Manufacturer: "TP-Link", + Code: "tl-sg2210mp", + } + *e.supportedList = append(*e.supportedList, tpLink) } func (e *EthernetSwitchService) modelIsSupported(model string) bool { diff --git a/src/app/services/EthernetSwitchServicePorts.go b/src/app/services/EthernetSwitchServicePorts.go index e0f3f2eb..4dd0cd03 100644 --- a/src/app/services/EthernetSwitchServicePorts.go +++ b/src/app/services/EthernetSwitchServicePorts.go @@ -271,7 +271,8 @@ func (e *EthernetSwitchService) UpdatePort(ctx context.Context, switchID, id uui if err != nil { return dto, err // we already wrap error in Update() } - return updatedPort, e.syncPortConfOnSwitch(ctx, switchID, dto.Name, dto.POEType, dto.POEEnabled, dto.PVID) + return updatedPort, e.syncPortConfOnSwitch(ctx, switchID, + updatedPort.Name, updatedPort.POEType, updatedPort.POEEnabled, updatedPort.PVID) } //GetPorts Get list of ethernet switch ports with filtering and pagination diff --git a/src/domain/Device.go b/src/domain/Device.go new file mode 100644 index 00000000..de938c37 --- /dev/null +++ b/src/domain/Device.go @@ -0,0 +1,13 @@ +package domain + +type Device struct { + EntityUUID + //Name - device name + Name string + //Model - device model + Model string + //Manufacturer - device manufacturer + Manufacturer string + //PowerControlBus - power control bus for this device + PowerControlBus string +} diff --git a/src/domain/DeviceNetworkInterface.go b/src/domain/DeviceNetworkInterface.go new file mode 100644 index 00000000..63a1913a --- /dev/null +++ b/src/domain/DeviceNetworkInterface.go @@ -0,0 +1,15 @@ +package domain + +import "github.com/google/uuid" + +//DeviceNetworkInterface - device network interface configuration +type DeviceNetworkInterface struct { + EntityUUID + DeviceID uuid.UUID `gorm:"type:varchar(36);index"` + //Mac address of network interface. This field is unique within all devices. + Mac string `gorm:"type:varchar(17);index"` + //ConnectedSwitchId - id of connected switch + ConnectedSwitchId uuid.UUID `gorm:"type:varchar(36);index"` + //ConnectedSwitchId - id of connected switch port + ConnectedSwitchPortId uuid.UUID `gorm:"type:varchar(36);index"` +} diff --git a/src/domain/DevicePowerState.go b/src/domain/DevicePowerState.go new file mode 100644 index 00000000..1eafd81f --- /dev/null +++ b/src/domain/DevicePowerState.go @@ -0,0 +1,29 @@ +package domain + +import "github.com/google/uuid" + +//DevPowerState power state for Device +type DevPowerState uint + +const ( + DevInPowerOnState = DevPowerState(iota) + DevInPowerOffState + DevInPowerUnknownState +) + +//String convert state to string +func (s DevPowerState) String() string { + switch s { + case DevInPowerOnState: + return "On" + case DevInPowerOffState: + return "Off" + } + return "unknown" +} + +type DevicePowerState struct { + EntityUUID + DeviceID uuid.UUID + DevPowerState +} diff --git a/src/dtos/DeviceCreateDto.go b/src/dtos/DeviceCreateDto.go new file mode 100644 index 00000000..9ca5483c --- /dev/null +++ b/src/dtos/DeviceCreateDto.go @@ -0,0 +1,12 @@ +package dtos + +type DeviceCreateDto struct { + //Name - device name + Name string + //Model - device model + Model string + //Manufacturer - device manufacturer + Manufacturer string + //PowerControlBus - power control bus for this device + PowerControlBus string +} diff --git a/src/dtos/DeviceDto.go b/src/dtos/DeviceDto.go new file mode 100644 index 00000000..31f645e0 --- /dev/null +++ b/src/dtos/DeviceDto.go @@ -0,0 +1,17 @@ +package dtos + +import "github.com/google/uuid" + +type DeviceDto struct { + BaseDto[uuid.UUID] + //Name - device name + Name string + //Model - device model + Model string + //Manufacturer - device manufacturer + Manufacturer string + //PowerControlBus - power control bus for this device + PowerControlBus string + //PowerState current power state of the device + PowerState string +} diff --git a/src/dtos/DeviceNetworkInterfaceCreateDto.go b/src/dtos/DeviceNetworkInterfaceCreateDto.go new file mode 100644 index 00000000..4dd9cba7 --- /dev/null +++ b/src/dtos/DeviceNetworkInterfaceCreateDto.go @@ -0,0 +1,13 @@ +package dtos + +import "github.com/google/uuid" + +//DeviceNetworkInterfaceCreateDto - device network interface configuration create dto +type DeviceNetworkInterfaceCreateDto struct { + //Mac address of network interface. This field is unique within all devices. + Mac string + //ConnectedSwitchId - id of connected switch + ConnectedSwitchId uuid.UUID + //ConnectedSwitchId - id of connected switch port + ConnectedSwitchPortId uuid.UUID +} diff --git a/src/dtos/DeviceNetworkInterfaceDto.go b/src/dtos/DeviceNetworkInterfaceDto.go new file mode 100644 index 00000000..1716ffad --- /dev/null +++ b/src/dtos/DeviceNetworkInterfaceDto.go @@ -0,0 +1,14 @@ +package dtos + +import "github.com/google/uuid" + +//DeviceNetworkInterfaceDto - device network interface configuration dto +type DeviceNetworkInterfaceDto struct { + BaseDto[uuid.UUID] + //Mac address of network interface. This field is unique within all devices. + Mac string + //ConnectedSwitchId - id of connected switch + ConnectedSwitchId uuid.UUID + //ConnectedSwitchId - id of connected switch port + ConnectedSwitchPortId uuid.UUID +} diff --git a/src/dtos/DeviceNetworkInterfaceUpdateDto.go b/src/dtos/DeviceNetworkInterfaceUpdateDto.go new file mode 100644 index 00000000..a31c586a --- /dev/null +++ b/src/dtos/DeviceNetworkInterfaceUpdateDto.go @@ -0,0 +1,13 @@ +package dtos + +import "github.com/google/uuid" + +//DeviceNetworkInterfaceUpdateDto - device network interface configuration update dto +type DeviceNetworkInterfaceUpdateDto struct { + //Mac address of network interface. This field is unique within all devices. + Mac string + //ConnectedSwitchId - id of connected switch + ConnectedSwitchId uuid.UUID + //ConnectedSwitchId - id of connected switch port + ConnectedSwitchPortId uuid.UUID +} diff --git a/src/dtos/DevicePowerCommandCreateDto.go b/src/dtos/DevicePowerCommandCreateDto.go new file mode 100644 index 00000000..f8f9ba4e --- /dev/null +++ b/src/dtos/DevicePowerCommandCreateDto.go @@ -0,0 +1,5 @@ +package dtos + +type DevicePowerCommandCreateDto struct { + Command string +} diff --git a/src/dtos/DevicePowerCommandDto.go b/src/dtos/DevicePowerCommandDto.go new file mode 100644 index 00000000..b6048c8f --- /dev/null +++ b/src/dtos/DevicePowerCommandDto.go @@ -0,0 +1,10 @@ +package dtos + +import ( + "github.com/google/uuid" +) + +type DevicePowerCommandDto struct { + BaseDto[uuid.UUID] + Command string +} diff --git a/src/dtos/DeviceUpdateDto.go b/src/dtos/DeviceUpdateDto.go new file mode 100644 index 00000000..6565cd34 --- /dev/null +++ b/src/dtos/DeviceUpdateDto.go @@ -0,0 +1,12 @@ +package dtos + +type DeviceUpdateDto struct { + //Name - device name + Name string + //Model - device model + Model string + //Manufacturer - device manufacturer + Manufacturer string + //PowerControlBus - power control bus for this device + PowerControlBus string +} diff --git a/src/infrastructure/GormDbInitializer.go b/src/infrastructure/GormDbInitializer.go index 2987ee80..0a8643cf 100644 --- a/src/infrastructure/GormDbInitializer.go +++ b/src/infrastructure/GormDbInitializer.go @@ -98,6 +98,9 @@ func NewGormEntityDb(cfg *domain.AppConfig) (*gorm.DB, error) { &domain.EthernetSwitchVLAN{}, &domain.DHCP4Config{}, &domain.DHCP4Lease{}, + &domain.Device{}, + &domain.DeviceNetworkInterface{}, + &domain.DevicePowerState{}, ) if err != nil { return nil, errors.Internal.Wrap(err, "failed to apply db migrations") diff --git a/src/infrastructure/GormDeviceNetworkInterfaceRepository.go b/src/infrastructure/GormDeviceNetworkInterfaceRepository.go new file mode 100644 index 00000000..39976870 --- /dev/null +++ b/src/infrastructure/GormDeviceNetworkInterfaceRepository.go @@ -0,0 +1,28 @@ +// Package infrastructure stores all implementations of app interfaces +package infrastructure + +import ( + "github.com/google/uuid" + "github.com/sirupsen/logrus" + "gorm.io/gorm" + "rol/app/interfaces" + "rol/domain" +) + +//GormDeviceNetworkInterfaceRepository repository for domain.DeviceNetworkInterface entity +type GormDeviceNetworkInterfaceRepository struct { + *GormGenericRepository[uuid.UUID, domain.DeviceNetworkInterface] +} + +//NewGormDeviceNetworkInterfaceRepository constructor for domain.DeviceNetworkInterface GORM generic repository +//Params +// db - gorm database +// log - logrus logger +//Return +// interfaces.IGenericRepository[uuid.UUID, domain.DeviceNetworkInterface] - new device network interface repository +func NewGormDeviceNetworkInterfaceRepository(db *gorm.DB, log *logrus.Logger) interfaces.IGenericRepository[uuid.UUID, domain.DeviceNetworkInterface] { + genericRepository := NewGormGenericRepository[uuid.UUID, domain.DeviceNetworkInterface](db, log) + return &GormDeviceNetworkInterfaceRepository{ + genericRepository, + } +} diff --git a/src/infrastructure/GormDevicePowerStateRepository.go b/src/infrastructure/GormDevicePowerStateRepository.go new file mode 100644 index 00000000..7d6f8e62 --- /dev/null +++ b/src/infrastructure/GormDevicePowerStateRepository.go @@ -0,0 +1,63 @@ +// Package infrastructure stores all implementations of app interfaces +package infrastructure + +import ( + "context" + "fmt" + "github.com/google/uuid" + "github.com/sirupsen/logrus" + "gorm.io/gorm" + "rol/app/errors" + "rol/app/interfaces" + "rol/domain" +) + +//GormDevicePowerStateRepository repository for domain.DevicePowerState entity +type GormDevicePowerStateRepository struct { + *GormGenericRepository[uuid.UUID, domain.DevicePowerState] +} + +//NewGormDevicePowerStateRepository constructor for domain.DevicePowerState GORM generic repository +//Params +// db - gorm database +// log - logrus logger +//Return +// interfaces.IGenericRepository[uuid.UUID, domain.DevicePowerState] - new device power state repository +func NewGormDevicePowerStateRepository(db *gorm.DB, log *logrus.Logger) interfaces.IGenericRepository[uuid.UUID, domain.DevicePowerState] { + genericRepository := NewGormGenericRepository[uuid.UUID, domain.DevicePowerState](db, log) + return &GormDevicePowerStateRepository{ + genericRepository, + } +} + +//Insert entity to the repository +// +//Params +// ctx - context +// entity - entity to save +//Return +// EntityType - created entity +// error - if an error occurs, otherwise nil +func (r *GormDevicePowerStateRepository) Insert(ctx context.Context, entity domain.DevicePowerState) (domain.DevicePowerState, error) { + r.log(ctx, "debug", fmt.Sprintf("Insert: entity=%+v", entity)) + queryBuilder := r.NewQueryBuilder(ctx) + queryBuilder.Where("DeviceID", "==", entity.DeviceID) + stateForRemove, err := r.GetList(ctx, "CreatedAt", "desc", 51, 1, queryBuilder) + if err != nil { + return domain.DevicePowerState{}, errors.Internal.Wrapf(err, "power states count failed for device %s", entity.DeviceID.String()) + } + if len(stateForRemove) > 0 { + back := r.Db + r.Db = r.Db.Unscoped() + err := r.Delete(ctx, stateForRemove[0].ID) + if err != nil { + r.log(ctx, "debug", fmt.Sprintf("failed to remove oldest(51) power state for device %s", entity.DeviceID.String())) + } + r.Db = back + } + if err = r.Db.Create(&entity).Error; err != nil { + return domain.DevicePowerState{}, errors.Internal.Wrap(err, "gorm failed create entity") + } + r.log(ctx, "debug", fmt.Sprintf("Insert: newID=%+v", entity.GetID())) + return entity, nil +} diff --git a/src/infrastructure/GormDeviceRepository.go b/src/infrastructure/GormDeviceRepository.go new file mode 100644 index 00000000..6b25c395 --- /dev/null +++ b/src/infrastructure/GormDeviceRepository.go @@ -0,0 +1,28 @@ +// Package infrastructure stores all implementations of app interfaces +package infrastructure + +import ( + "github.com/google/uuid" + "github.com/sirupsen/logrus" + "gorm.io/gorm" + "rol/app/interfaces" + "rol/domain" +) + +//GormDeviceRepository repository for domain.Device entity +type GormDeviceRepository struct { + *GormGenericRepository[uuid.UUID, domain.Device] +} + +//NewGormDeviceRepository constructor for domain.Device GORM generic repository +//Params +// db - gorm database +// log - logrus logger +//Return +// interfaces.IGenericRepository[uuid.UUID, domain.Device] - new device repository +func NewGormDeviceRepository(db *gorm.DB, log *logrus.Logger) interfaces.IGenericRepository[uuid.UUID, domain.Device] { + genericRepository := NewGormGenericRepository[uuid.UUID, domain.Device](db, log) + return &GormDeviceRepository{ + genericRepository, + } +} diff --git a/src/main.go b/src/main.go index a68ad769..82421982 100644 --- a/src/main.go +++ b/src/main.go @@ -4,6 +4,8 @@ package main import ( "os" "path/filepath" + "rol/app/drivers" + "rol/app/providers" "rol/app/services" "rol/domain" "rol/infrastructure" @@ -35,7 +37,7 @@ func GetGlobalDIParameters() domain.GlobalDIParameters { // @license.name license(Mandatory) // @license.url http://www.apache.org/licenses/LICENSE-2.0.html -// @host localhost:8080 +// @host 192.168.8.118:8080 // @BasePath /api/v1/ func main() { app := fx.New( @@ -62,6 +64,14 @@ func main() { infrastructure.NewGormDHCP4LeaseRepository, infrastructure.NewGormDHCP4ConfigRepository, infrastructure.NewCoreDHCP4ServerFactory, + infrastructure.NewGormDeviceRepository, + infrastructure.NewGormDeviceNetworkInterfaceRepository, + infrastructure.NewGormDevicePowerStateRepository, + // APP + // Device power drivers + drivers.NewDevicePOEPowerDriver, + // Device power driver provider + providers.NewDevicePowerDriverProvider, // Application logic services.NewEthernetSwitchService, services.NewHTTPLogService, @@ -70,9 +80,11 @@ func main() { services.NewHostNetworkService, services.NewDHCP4ServerService, services.NewTFTPServerService, - // WEB API -> GIN Server + services.NewDeviceService, + // WEB + // API -> GIN Server webapi.NewGinHTTPServer, - // WEB API -> GIN Controllers + // API -> GIN Controllers controllers.NewEthernetSwitchGinController, controllers.NewHTTPLogGinController, controllers.NewAppLogGinController, @@ -84,6 +96,7 @@ func main() { controllers.NewEthernetSwitchVLANGinController, controllers.NewDHCP4ServerGinController, controllers.NewTFTPServerGinController, + controllers.NewDeviceGinController, ), fx.Invoke( //Register logrus hooks @@ -104,6 +117,7 @@ func main() { controllers.RegisterEthernetSwitchVLANGinController, controllers.RegisterDHCP4ServerGinController, controllers.RegisterTFTPServerGinController, + controllers.RegisterDeviceGinController, //Start GIN http server webapi.StartHTTPServer, ), diff --git a/src/webapi/controllers/DeviceController.go b/src/webapi/controllers/DeviceController.go new file mode 100644 index 00000000..ee4fc28f --- /dev/null +++ b/src/webapi/controllers/DeviceController.go @@ -0,0 +1,366 @@ +package controllers + +import ( + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" + "rol/app/services" + "rol/dtos" + "rol/webapi" +) + +//DeviceGinController Device entity GIN controller constructor +type DeviceGinController struct { + service *services.DeviceService + logger *logrus.Logger +} + +//NewDeviceGinController device entity controller constructor +//Params +// service - device entity service +// log - logrus logger +//Return +// *DeviceGinController - Gin controller for Device entity +func NewDeviceGinController(service *services.DeviceService, log *logrus.Logger) *DeviceGinController { + deviceContr := &DeviceGinController{ + service: service, + logger: log, + } + return deviceContr +} + +//RegisterDeviceGinController registers controller for the Device entity +func RegisterDeviceGinController(controller *DeviceGinController, server *webapi.GinHTTPServer) { + groupRoute := server.Engine.Group("/api/v1") + groupRoute.GET("/device/", controller.GetDeviceList) + groupRoute.GET("/device/:id", controller.GetDeviceByID) + groupRoute.POST("/device", controller.CreateDevice) + groupRoute.PUT("/device/:id", controller.UpdateDevice) + groupRoute.DELETE("/device/:id", controller.DeleteDevice) + //deviceNetInterface + groupRoute.GET("/device/:id/network-interface", controller.GetDeviceNetInterfacesList) + groupRoute.GET("/device/:id/network-interface/:interfaceID", controller.GetDeviceNetInterfaceByID) + groupRoute.POST("/device/:id/network-interface", controller.CreateDeviceNetInterface) + groupRoute.PUT("/device/:id/network-interface/:interfaceID", controller.UpdateDeviceNetInterface) + groupRoute.DELETE("/device/:id/network-interface/:interfaceID", controller.DeleteDeviceNetInterface) + //PowerCommand + groupRoute.POST("/device/:id/power-command", controller.PowerCommand) +} + +//GetDeviceList Get list of devices with search and pagination +//Params +// ctx - gin context +// @Summary Gets paginated list of device entity +// @version 1.0 +// @Tags device +// @Accept json +// @Produce json +// @param orderBy query string false "Order by field" +// @param orderDirection query string false "'asc' or 'desc' for ascending or descending order" +// @param search query string false "searchable value in entity" +// @param page query int false "page number" +// @param pageSize query int false "number of entities per page" +// @Success 200 {object} dtos.PaginatedItemsDto[dtos.DeviceDto] +// @Failure 500 "Internal Server Error" +// @router /device/ [get] +func (c *DeviceGinController) GetDeviceList(ctx *gin.Context) { + req := newPaginatedRequestStructForParsing(1, 10, "CreatedAt", "asc", "") + err := parseGinRequest(ctx, &req) + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + paginatedList, err := c.service.GetDevicesList(ctx, req.Search, req.OrderBy, req.OrderDirection, + req.Page, req.PageSize) + handleWithData(ctx, err, paginatedList) +} + +//GetDeviceByID get device by id +// Params +// ctx - gin context +// @Summary Get device by id +// @version 1.0 +// @Tags device +// @Accept json +// @Produce json +// @param id path string true "Device ID" +// @Success 200 {object} dtos.DeviceDto +// @Failure 404 "Not Found" +// @Failure 500 "Internal Server Error" +// @router /device/{id} [get] +func (c *DeviceGinController) GetDeviceByID(ctx *gin.Context) { + id, err := parseUUIDParam(ctx, "id") + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + dto, err := c.service.GetDeviceByID(ctx, id) + handleWithData(ctx, err, dto) +} + +//CreateDevice - create new device +// Params +// ctx - gin context +// @Summary Create device +// @version 1.0 +// @Tags device +// @Accept json +// @Produce json +// @Param request body dtos.DeviceCreateDto true "Device fields" +// @Success 200 {object} dtos.DeviceDto +// @Failure 400 {object} dtos.ValidationErrorDto +// @Failure 500 "Internal Server Error" +// @router /device/ [post] +func (c *DeviceGinController) CreateDevice(ctx *gin.Context) { + reqDto, err := getRequestDtoAndRestoreBody[dtos.DeviceCreateDto](ctx) + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + + dto, err := c.service.CreateDevice(ctx, reqDto) + handleWithData(ctx, err, dto) +} + +//UpdateDevice - update device +// Params +// ctx - gin context +// @Summary Updates device +// @version 1.0 +// @Tags device +// @Accept json +// @Produce json +// @param id path string true "Device ID" +// @Param request body dtos.DeviceUpdateDto true "Device fields" +// @Success 200 {object} dtos.DeviceDto +// @Failure 400 {object} dtos.ValidationErrorDto +// @Failure 404 "Not Found" +// @Failure 500 "Internal Server Error" +// @router /device/{id} [put] +func (c *DeviceGinController) UpdateDevice(ctx *gin.Context) { + reqDto, err := getRequestDtoAndRestoreBody[dtos.DeviceUpdateDto](ctx) + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + id, err := parseUUIDParam(ctx, "id") + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + + dto, err := c.service.UpdateDevice(ctx, id, reqDto) + handleWithData(ctx, err, dto) +} + +//DeleteDevice - delete device by id +// Params +// ctx - gin context +// @Summary Delete device by id +// @version 1.0 +// @Tags device +// @Accept json +// @Produce json +// @param id path string true "Device ID" +// @Success 204 "OK, but No Content" +// @Failure 404 "Not Found" +// @Failure 500 "Internal Server Error" +// @router /device/{id} [delete] +func (c *DeviceGinController) DeleteDevice(ctx *gin.Context) { + id, err := parseUUIDParam(ctx, "id") + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + + err = c.service.DeleteDevice(ctx, id) + handle(ctx, err) +} + +//GetDeviceNetInterfacesList - get list of device network interfaces with search and pagination +// Params +// ctx - gin context +// @Summary Get list of device network interface +// @version 1.0 +// @Tags device +// @Accept json +// @Produce json +// @param id path string true "Device ID" +// @param orderBy query string false "Order by field" +// @param orderDirection query string false "'asc' or 'desc' for ascending or descending order" +// @param search query string false "Searchable value in entity" +// @param page query int false "Page number" +// @param pageSize query int false "Number of entities per page" +// @Success 200 {object} dtos.PaginatedItemsDto[dtos.DeviceNetworkInterfaceDto] +// @Failure 500 "Internal Server Error" +// @router /device/{id}/network-interface [get] +func (c *DeviceGinController) GetDeviceNetInterfacesList(ctx *gin.Context) { + req := newPaginatedRequestStructForParsing(1, 10, "CreatedAt", "asc", "") + err := parseGinRequest(ctx, &req) + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + id, err := parseUUIDParam(ctx, "id") + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + paginatedList, err := c.service.GetNetInterfacesList(ctx, id, req.Search, req.OrderBy, req.OrderDirection, + req.Page, req.PageSize) + handleWithData(ctx, err, paginatedList) +} + +//GetDeviceNetInterfaceByID get device network interface by id +// Params +// ctx - gin context +// @Summary Get device network interface by id +// @version 1.0 +// @Tags device +// @Accept json +// @Produce json +// @param id path string true "Device ID" +// @param interfaceID path string true "Device network interface ID" +// @Success 200 {object} dtos.DeviceNetworkInterfaceDto +// @Failure 404 "Not Found" +// @Failure 500 "Internal Server Error" +// @router /device/{id}/network-interface/{interfaceID} [get] +func (c *DeviceGinController) GetDeviceNetInterfaceByID(ctx *gin.Context) { + deviceID, err := parseUUIDParam(ctx, "id") + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + interfaceID, err := parseUUIDParam(ctx, "interfaceID") + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + dto, err := c.service.GetNetInterfaceByID(ctx, deviceID, interfaceID) + handleWithData(ctx, err, dto) +} + +//CreateDeviceNetInterface - crate new device network interface +// Params +// ctx - gin context +// @Summary Create device network interface +// @version 1.0 +// @Tags device +// @Accept json +// @Produce json +// @param id path string true "DHCP v4 server ID" +// @Param request body dtos.DeviceNetworkInterfaceCreateDto true "Device network interface fields" +// @Success 200 {object} dtos.DeviceNetworkInterfaceDto +// @Failure 400 {object} dtos.ValidationErrorDto +// @Failure 500 "Internal Server Error" +// @router /device/{id}/network-interface [post] +func (c *DeviceGinController) CreateDeviceNetInterface(ctx *gin.Context) { + id, err := parseUUIDParam(ctx, "id") + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + reqDto, err := getRequestDtoAndRestoreBody[dtos.DeviceNetworkInterfaceCreateDto](ctx) + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + + dto, err := c.service.CreateNetInterface(ctx, id, reqDto) + handleWithData(ctx, err, dto) +} + +//UpdateDeviceNetInterface - update device network interface +// Params +// ctx - gin context +// @Summary Updates device network interface +// @version 1.0 +// @Tags device +// @Accept json +// @Produce json +// @param id path string true "Device ID" +// @param interfaceID path string true "Device network interface ID" +// @Param request body dtos.DeviceNetworkInterfaceUpdateDto true "Device network interface fields" +// @Success 200 {object} dtos.DeviceNetworkInterfaceDto +// @Failure 400 {object} dtos.ValidationErrorDto +// @Failure 404 "Not Found" +// @Failure 500 "Internal Server Error" +// @router /device/{id}/network-interface/{interfaceID} [put] +func (c *DeviceGinController) UpdateDeviceNetInterface(ctx *gin.Context) { + reqDto, err := getRequestDtoAndRestoreBody[dtos.DeviceNetworkInterfaceUpdateDto](ctx) + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + serverID, err := parseUUIDParam(ctx, "id") + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + interfaceID, err := parseUUIDParam(ctx, "interfaceID") + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + + dto, err := c.service.UpdateNetInterface(ctx, serverID, interfaceID, reqDto) + handleWithData(ctx, err, dto) +} + +//DeleteDeviceNetInterface - delete device network interface +// Params +// ctx - gin context +// @Summary Delete device network interface by id +// @version 1.0 +// @Tags device +// @Accept json +// @Produce json +// @param id path string true "Device ID" +// @param interfaceID path string true "Device network interface ID" +// @Success 204 "OK, but No Content" +// @Failure 404 "Not Found" +// @Failure 500 "Internal Server Error" +// @router /device/{id}/network-interface/{interfaceID} [delete] +func (c *DeviceGinController) DeleteDeviceNetInterface(ctx *gin.Context) { + id, err := parseUUIDParam(ctx, "id") + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + interfaceID, err := parseUUIDParam(ctx, "interfaceID") + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + + err = c.service.DeleteNetInterface(ctx, id, interfaceID) + handle(ctx, err) +} + +//PowerCommand - send power device command +// Params +// ctx - gin context +// @Summary Send power device command +// @version 1.0 +// @Tags device +// @Accept json +// @Produce json +// @param id path string true "Device ID" +// @Param request body dtos.DevicePowerCommandDto true "Device power command fields" +// @Success 204 "OK, but No Content" +// @Failure 404 "Not Found" +// @Failure 500 "Internal Server Error" +// @router /device/{id}/power-command/ [post] +func (c *DeviceGinController) PowerCommand(ctx *gin.Context) { + id, err := parseUUIDParam(ctx, "id") + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + reqDto, err := getRequestDtoAndRestoreBody[dtos.DevicePowerCommandDto](ctx) + if err != nil { + abortWithStatusByErrorType(ctx, err) + return + } + err = c.service.DevicePowerCommand(ctx, id, reqDto) + handle(ctx, err) +} diff --git a/src/webapi/swagger/docs.go b/src/webapi/swagger/docs.go index d5a1cc2b..2a43703a 100644 --- a/src/webapi/swagger/docs.go +++ b/src/webapi/swagger/docs.go @@ -24,6 +24,516 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/device/": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Gets paginated list of device entity", + "parameters": [ + { + "type": "string", + "description": "Order by field", + "name": "orderBy", + "in": "query" + }, + { + "type": "string", + "description": "'asc' or 'desc' for ascending or descending order", + "name": "orderDirection", + "in": "query" + }, + { + "type": "string", + "description": "searchable value in entity", + "name": "search", + "in": "query" + }, + { + "type": "integer", + "description": "page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "number of entities per page", + "name": "pageSize", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.PaginatedItemsDto-dtos_DeviceDto" + } + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Create device", + "parameters": [ + { + "description": "Device fields", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dtos.DeviceCreateDto" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.DeviceDto" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/dtos.ValidationErrorDto" + } + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/device/{id}": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Get device by id", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.DeviceDto" + } + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "put": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Updates device", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Device fields", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dtos.DeviceUpdateDto" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.DeviceDto" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/dtos.ValidationErrorDto" + } + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "delete": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Delete device by id", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "OK, but No Content" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/device/{id}/network-interface": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Get list of device network interface", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Order by field", + "name": "orderBy", + "in": "query" + }, + { + "type": "string", + "description": "'asc' or 'desc' for ascending or descending order", + "name": "orderDirection", + "in": "query" + }, + { + "type": "string", + "description": "Searchable value in entity", + "name": "search", + "in": "query" + }, + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "Number of entities per page", + "name": "pageSize", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.PaginatedItemsDto-dtos_DeviceNetworkInterfaceDto" + } + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Create device network interface", + "parameters": [ + { + "type": "string", + "description": "DHCP v4 server ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Device network interface fields", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dtos.DeviceNetworkInterfaceCreateDto" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.DeviceNetworkInterfaceDto" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/dtos.ValidationErrorDto" + } + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/device/{id}/network-interface/{interfaceID}": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Get device network interface by id", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Device network interface ID", + "name": "interfaceID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.DeviceNetworkInterfaceDto" + } + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "put": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Updates device network interface", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Device network interface ID", + "name": "interfaceID", + "in": "path", + "required": true + }, + { + "description": "Device network interface fields", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dtos.DeviceNetworkInterfaceUpdateDto" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.DeviceNetworkInterfaceDto" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/dtos.ValidationErrorDto" + } + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "delete": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Delete device network interface by id", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Device network interface ID", + "name": "interfaceID", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "OK, but No Content" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/device/{id}/power-command/": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Send power device command", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Device power command fields", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dtos.DevicePowerCommandDto" + } + } + ], + "responses": { + "204": { + "description": "OK, but No Content" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, "/dhcp/": { "get": { "consumes": [ @@ -2508,6 +3018,147 @@ const docTemplate = `{ } } }, + "dtos.DeviceCreateDto": { + "type": "object", + "properties": { + "manufacturer": { + "description": "Manufacturer - device manufacturer", + "type": "string" + }, + "model": { + "description": "Model - device model", + "type": "string" + }, + "name": { + "description": "Name - device name", + "type": "string" + }, + "powerControlBus": { + "description": "PowerControlBus - power control bus for this device", + "type": "string" + } + } + }, + "dtos.DeviceDto": { + "type": "object", + "properties": { + "createdAt": { + "description": "CreatedAt - entity create time", + "type": "string" + }, + "id": { + "description": "ID - unique identifier", + "type": "string" + }, + "manufacturer": { + "description": "Manufacturer - device manufacturer", + "type": "string" + }, + "model": { + "description": "Model - device model", + "type": "string" + }, + "name": { + "description": "Name - device name", + "type": "string" + }, + "powerControlBus": { + "description": "PowerControlBus - power control bus for this device", + "type": "string" + }, + "powerState": { + "description": "PowerState current power state of the device", + "type": "string" + }, + "updatedAt": { + "description": "UpdatedAt - entity update time", + "type": "string" + } + } + }, + "dtos.DeviceNetworkInterfaceCreateDto": { + "type": "object", + "properties": { + "connectedSwitchId": { + "description": "ConnectedSwitchId - id of connected switch", + "type": "string" + }, + "connectedSwitchPortId": { + "description": "ConnectedSwitchId - id of connected switch port", + "type": "string" + }, + "mac": { + "description": "Mac address of network interface. This field is unique within all devices.", + "type": "string" + } + } + }, + "dtos.DeviceNetworkInterfaceDto": { + "type": "object", + "properties": { + "connectedSwitchId": { + "description": "ConnectedSwitchId - id of connected switch", + "type": "string" + }, + "connectedSwitchPortId": { + "description": "ConnectedSwitchId - id of connected switch port", + "type": "string" + }, + "createdAt": { + "description": "CreatedAt - entity create time", + "type": "string" + }, + "id": { + "description": "ID - unique identifier", + "type": "string" + }, + "mac": { + "description": "Mac address of network interface. This field is unique within all devices.", + "type": "string" + }, + "updatedAt": { + "description": "UpdatedAt - entity update time", + "type": "string" + } + } + }, + "dtos.DeviceNetworkInterfaceUpdateDto": { + "type": "object", + "properties": { + "connectedSwitchId": { + "description": "ConnectedSwitchId - id of connected switch", + "type": "string" + }, + "connectedSwitchPortId": { + "description": "ConnectedSwitchId - id of connected switch port", + "type": "string" + }, + "mac": { + "description": "Mac address of network interface. This field is unique within all devices.", + "type": "string" + } + } + }, + "dtos.DevicePowerCommandDto": { + "type": "object", + "properties": { + "command": { + "type": "string" + }, + "createdAt": { + "description": "CreatedAt - entity create time", + "type": "string" + }, + "id": { + "description": "ID - unique identifier", + "type": "string" + }, + "updatedAt": { + "description": "UpdatedAt - entity update time", + "type": "string" + } + } + }, "dtos.DeviceTemplateBootStageDto": { "type": "object", "properties": { @@ -2648,6 +3299,27 @@ const docTemplate = `{ } } }, + "dtos.DeviceUpdateDto": { + "type": "object", + "properties": { + "manufacturer": { + "description": "Manufacturer - device manufacturer", + "type": "string" + }, + "model": { + "description": "Model - device model", + "type": "string" + }, + "name": { + "description": "Name - device name", + "type": "string" + }, + "powerControlBus": { + "description": "PowerControlBus - power control bus for this device", + "type": "string" + } + } + }, "dtos.EthernetSwitchCreateDto": { "type": "object", "properties": { @@ -3142,6 +3814,38 @@ const docTemplate = `{ } } }, + "dtos.PaginatedItemsDto-dtos_DeviceDto": { + "type": "object", + "properties": { + "items": { + "description": "Items slice of items", + "type": "array", + "items": { + "$ref": "#/definitions/dtos.DeviceDto" + } + }, + "pagination": { + "description": "Pagination info about pagination", + "$ref": "#/definitions/dtos.PaginationInfoDto" + } + } + }, + "dtos.PaginatedItemsDto-dtos_DeviceNetworkInterfaceDto": { + "type": "object", + "properties": { + "items": { + "description": "Items slice of items", + "type": "array", + "items": { + "$ref": "#/definitions/dtos.DeviceNetworkInterfaceDto" + } + }, + "pagination": { + "description": "Pagination info about pagination", + "$ref": "#/definitions/dtos.PaginationInfoDto" + } + } + }, "dtos.PaginatedItemsDto-dtos_DeviceTemplateDto": { "type": "object", "properties": { @@ -3417,7 +4121,7 @@ const docTemplate = `{ // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ Version: "0.1.0", - Host: "localhost:8080", + Host: "192.168.8.118:8080", BasePath: "/api/v1/", Schemes: []string{}, Title: "Rack of labs API", diff --git a/src/webapi/swagger/swagger.json b/src/webapi/swagger/swagger.json index 5d5dcab4..b5f9c275 100644 --- a/src/webapi/swagger/swagger.json +++ b/src/webapi/swagger/swagger.json @@ -14,9 +14,519 @@ }, "version": "0.1.0" }, - "host": "localhost:8080", + "host": "192.168.8.118:8080", "basePath": "/api/v1/", "paths": { + "/device/": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Gets paginated list of device entity", + "parameters": [ + { + "type": "string", + "description": "Order by field", + "name": "orderBy", + "in": "query" + }, + { + "type": "string", + "description": "'asc' or 'desc' for ascending or descending order", + "name": "orderDirection", + "in": "query" + }, + { + "type": "string", + "description": "searchable value in entity", + "name": "search", + "in": "query" + }, + { + "type": "integer", + "description": "page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "number of entities per page", + "name": "pageSize", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.PaginatedItemsDto-dtos_DeviceDto" + } + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Create device", + "parameters": [ + { + "description": "Device fields", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dtos.DeviceCreateDto" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.DeviceDto" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/dtos.ValidationErrorDto" + } + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/device/{id}": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Get device by id", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.DeviceDto" + } + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "put": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Updates device", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Device fields", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dtos.DeviceUpdateDto" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.DeviceDto" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/dtos.ValidationErrorDto" + } + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "delete": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Delete device by id", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "OK, but No Content" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/device/{id}/network-interface": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Get list of device network interface", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Order by field", + "name": "orderBy", + "in": "query" + }, + { + "type": "string", + "description": "'asc' or 'desc' for ascending or descending order", + "name": "orderDirection", + "in": "query" + }, + { + "type": "string", + "description": "Searchable value in entity", + "name": "search", + "in": "query" + }, + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "Number of entities per page", + "name": "pageSize", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.PaginatedItemsDto-dtos_DeviceNetworkInterfaceDto" + } + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Create device network interface", + "parameters": [ + { + "type": "string", + "description": "DHCP v4 server ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Device network interface fields", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dtos.DeviceNetworkInterfaceCreateDto" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.DeviceNetworkInterfaceDto" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/dtos.ValidationErrorDto" + } + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/device/{id}/network-interface/{interfaceID}": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Get device network interface by id", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Device network interface ID", + "name": "interfaceID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.DeviceNetworkInterfaceDto" + } + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "put": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Updates device network interface", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Device network interface ID", + "name": "interfaceID", + "in": "path", + "required": true + }, + { + "description": "Device network interface fields", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dtos.DeviceNetworkInterfaceUpdateDto" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dtos.DeviceNetworkInterfaceDto" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/dtos.ValidationErrorDto" + } + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "delete": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Delete device network interface by id", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Device network interface ID", + "name": "interfaceID", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "OK, but No Content" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/device/{id}/power-command/": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "device" + ], + "summary": "Send power device command", + "parameters": [ + { + "type": "string", + "description": "Device ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Device power command fields", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dtos.DevicePowerCommandDto" + } + } + ], + "responses": { + "204": { + "description": "OK, but No Content" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, "/dhcp/": { "get": { "consumes": [ @@ -2501,6 +3011,147 @@ } } }, + "dtos.DeviceCreateDto": { + "type": "object", + "properties": { + "manufacturer": { + "description": "Manufacturer - device manufacturer", + "type": "string" + }, + "model": { + "description": "Model - device model", + "type": "string" + }, + "name": { + "description": "Name - device name", + "type": "string" + }, + "powerControlBus": { + "description": "PowerControlBus - power control bus for this device", + "type": "string" + } + } + }, + "dtos.DeviceDto": { + "type": "object", + "properties": { + "createdAt": { + "description": "CreatedAt - entity create time", + "type": "string" + }, + "id": { + "description": "ID - unique identifier", + "type": "string" + }, + "manufacturer": { + "description": "Manufacturer - device manufacturer", + "type": "string" + }, + "model": { + "description": "Model - device model", + "type": "string" + }, + "name": { + "description": "Name - device name", + "type": "string" + }, + "powerControlBus": { + "description": "PowerControlBus - power control bus for this device", + "type": "string" + }, + "powerState": { + "description": "PowerState current power state of the device", + "type": "string" + }, + "updatedAt": { + "description": "UpdatedAt - entity update time", + "type": "string" + } + } + }, + "dtos.DeviceNetworkInterfaceCreateDto": { + "type": "object", + "properties": { + "connectedSwitchId": { + "description": "ConnectedSwitchId - id of connected switch", + "type": "string" + }, + "connectedSwitchPortId": { + "description": "ConnectedSwitchId - id of connected switch port", + "type": "string" + }, + "mac": { + "description": "Mac address of network interface. This field is unique within all devices.", + "type": "string" + } + } + }, + "dtos.DeviceNetworkInterfaceDto": { + "type": "object", + "properties": { + "connectedSwitchId": { + "description": "ConnectedSwitchId - id of connected switch", + "type": "string" + }, + "connectedSwitchPortId": { + "description": "ConnectedSwitchId - id of connected switch port", + "type": "string" + }, + "createdAt": { + "description": "CreatedAt - entity create time", + "type": "string" + }, + "id": { + "description": "ID - unique identifier", + "type": "string" + }, + "mac": { + "description": "Mac address of network interface. This field is unique within all devices.", + "type": "string" + }, + "updatedAt": { + "description": "UpdatedAt - entity update time", + "type": "string" + } + } + }, + "dtos.DeviceNetworkInterfaceUpdateDto": { + "type": "object", + "properties": { + "connectedSwitchId": { + "description": "ConnectedSwitchId - id of connected switch", + "type": "string" + }, + "connectedSwitchPortId": { + "description": "ConnectedSwitchId - id of connected switch port", + "type": "string" + }, + "mac": { + "description": "Mac address of network interface. This field is unique within all devices.", + "type": "string" + } + } + }, + "dtos.DevicePowerCommandDto": { + "type": "object", + "properties": { + "command": { + "type": "string" + }, + "createdAt": { + "description": "CreatedAt - entity create time", + "type": "string" + }, + "id": { + "description": "ID - unique identifier", + "type": "string" + }, + "updatedAt": { + "description": "UpdatedAt - entity update time", + "type": "string" + } + } + }, "dtos.DeviceTemplateBootStageDto": { "type": "object", "properties": { @@ -2641,6 +3292,27 @@ } } }, + "dtos.DeviceUpdateDto": { + "type": "object", + "properties": { + "manufacturer": { + "description": "Manufacturer - device manufacturer", + "type": "string" + }, + "model": { + "description": "Model - device model", + "type": "string" + }, + "name": { + "description": "Name - device name", + "type": "string" + }, + "powerControlBus": { + "description": "PowerControlBus - power control bus for this device", + "type": "string" + } + } + }, "dtos.EthernetSwitchCreateDto": { "type": "object", "properties": { @@ -3135,6 +3807,38 @@ } } }, + "dtos.PaginatedItemsDto-dtos_DeviceDto": { + "type": "object", + "properties": { + "items": { + "description": "Items slice of items", + "type": "array", + "items": { + "$ref": "#/definitions/dtos.DeviceDto" + } + }, + "pagination": { + "description": "Pagination info about pagination", + "$ref": "#/definitions/dtos.PaginationInfoDto" + } + } + }, + "dtos.PaginatedItemsDto-dtos_DeviceNetworkInterfaceDto": { + "type": "object", + "properties": { + "items": { + "description": "Items slice of items", + "type": "array", + "items": { + "$ref": "#/definitions/dtos.DeviceNetworkInterfaceDto" + } + }, + "pagination": { + "description": "Pagination info about pagination", + "$ref": "#/definitions/dtos.PaginationInfoDto" + } + } + }, "dtos.PaginatedItemsDto-dtos_DeviceTemplateDto": { "type": "object", "properties": { diff --git a/src/webapi/swagger/swagger.yaml b/src/webapi/swagger/swagger.yaml index 6081a889..3ce4303a 100644 --- a/src/webapi/swagger/swagger.yaml +++ b/src/webapi/swagger/swagger.yaml @@ -166,6 +166,110 @@ definitions: description: Port of DHCP server type: integer type: object + dtos.DeviceCreateDto: + properties: + manufacturer: + description: Manufacturer - device manufacturer + type: string + model: + description: Model - device model + type: string + name: + description: Name - device name + type: string + powerControlBus: + description: PowerControlBus - power control bus for this device + type: string + type: object + dtos.DeviceDto: + properties: + createdAt: + description: CreatedAt - entity create time + type: string + id: + description: ID - unique identifier + type: string + manufacturer: + description: Manufacturer - device manufacturer + type: string + model: + description: Model - device model + type: string + name: + description: Name - device name + type: string + powerControlBus: + description: PowerControlBus - power control bus for this device + type: string + powerState: + description: PowerState current power state of the device + type: string + updatedAt: + description: UpdatedAt - entity update time + type: string + type: object + dtos.DeviceNetworkInterfaceCreateDto: + properties: + connectedSwitchId: + description: ConnectedSwitchId - id of connected switch + type: string + connectedSwitchPortId: + description: ConnectedSwitchId - id of connected switch port + type: string + mac: + description: Mac address of network interface. This field is unique within + all devices. + type: string + type: object + dtos.DeviceNetworkInterfaceDto: + properties: + connectedSwitchId: + description: ConnectedSwitchId - id of connected switch + type: string + connectedSwitchPortId: + description: ConnectedSwitchId - id of connected switch port + type: string + createdAt: + description: CreatedAt - entity create time + type: string + id: + description: ID - unique identifier + type: string + mac: + description: Mac address of network interface. This field is unique within + all devices. + type: string + updatedAt: + description: UpdatedAt - entity update time + type: string + type: object + dtos.DeviceNetworkInterfaceUpdateDto: + properties: + connectedSwitchId: + description: ConnectedSwitchId - id of connected switch + type: string + connectedSwitchPortId: + description: ConnectedSwitchId - id of connected switch port + type: string + mac: + description: Mac address of network interface. This field is unique within + all devices. + type: string + type: object + dtos.DevicePowerCommandDto: + properties: + command: + type: string + createdAt: + description: CreatedAt - entity create time + type: string + id: + description: ID - unique identifier + type: string + updatedAt: + description: UpdatedAt - entity update time + type: string + type: object dtos.DeviceTemplateBootStageDto: properties: action: @@ -277,6 +381,21 @@ definitions: description: POEIn only one network interface can be mark as POEIn type: boolean type: object + dtos.DeviceUpdateDto: + properties: + manufacturer: + description: Manufacturer - device manufacturer + type: string + model: + description: Model - device model + type: string + name: + description: Name - device name + type: string + powerControlBus: + description: PowerControlBus - power control bus for this device + type: string + type: object dtos.EthernetSwitchCreateDto: properties: address: @@ -634,6 +753,28 @@ definitions: $ref: '#/definitions/dtos.PaginationInfoDto' description: Pagination info about pagination type: object + dtos.PaginatedItemsDto-dtos_DeviceDto: + properties: + items: + description: Items slice of items + items: + $ref: '#/definitions/dtos.DeviceDto' + type: array + pagination: + $ref: '#/definitions/dtos.PaginationInfoDto' + description: Pagination info about pagination + type: object + dtos.PaginatedItemsDto-dtos_DeviceNetworkInterfaceDto: + properties: + items: + description: Items slice of items + items: + $ref: '#/definitions/dtos.DeviceNetworkInterfaceDto' + type: array + pagination: + $ref: '#/definitions/dtos.PaginationInfoDto' + description: Pagination info about pagination + type: object dtos.PaginatedItemsDto-dtos_DeviceTemplateDto: properties: items: @@ -822,7 +963,7 @@ definitions: description: Source for the field, for example query or body type: string type: object -host: localhost:8080 +host: 192.168.8.118:8080 info: contact: email: support@swagger.io @@ -835,6 +976,341 @@ info: title: Rack of labs API version: 0.1.0 paths: + /device/: + get: + consumes: + - application/json + parameters: + - description: Order by field + in: query + name: orderBy + type: string + - description: '''asc'' or ''desc'' for ascending or descending order' + in: query + name: orderDirection + type: string + - description: searchable value in entity + in: query + name: search + type: string + - description: page number + in: query + name: page + type: integer + - description: number of entities per page + in: query + name: pageSize + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dtos.PaginatedItemsDto-dtos_DeviceDto' + "500": + description: Internal Server Error + summary: Gets paginated list of device entity + tags: + - device + post: + consumes: + - application/json + parameters: + - description: Device fields + in: body + name: request + required: true + schema: + $ref: '#/definitions/dtos.DeviceCreateDto' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dtos.DeviceDto' + "400": + description: Bad Request + schema: + $ref: '#/definitions/dtos.ValidationErrorDto' + "500": + description: Internal Server Error + summary: Create device + tags: + - device + /device/{id}: + delete: + consumes: + - application/json + parameters: + - description: Device ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "204": + description: OK, but No Content + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Delete device by id + tags: + - device + get: + consumes: + - application/json + parameters: + - description: Device ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dtos.DeviceDto' + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Get device by id + tags: + - device + put: + consumes: + - application/json + parameters: + - description: Device ID + in: path + name: id + required: true + type: string + - description: Device fields + in: body + name: request + required: true + schema: + $ref: '#/definitions/dtos.DeviceUpdateDto' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dtos.DeviceDto' + "400": + description: Bad Request + schema: + $ref: '#/definitions/dtos.ValidationErrorDto' + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Updates device + tags: + - device + /device/{id}/network-interface: + get: + consumes: + - application/json + parameters: + - description: Device ID + in: path + name: id + required: true + type: string + - description: Order by field + in: query + name: orderBy + type: string + - description: '''asc'' or ''desc'' for ascending or descending order' + in: query + name: orderDirection + type: string + - description: Searchable value in entity + in: query + name: search + type: string + - description: Page number + in: query + name: page + type: integer + - description: Number of entities per page + in: query + name: pageSize + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dtos.PaginatedItemsDto-dtos_DeviceNetworkInterfaceDto' + "500": + description: Internal Server Error + summary: Get list of device network interface + tags: + - device + post: + consumes: + - application/json + parameters: + - description: DHCP v4 server ID + in: path + name: id + required: true + type: string + - description: Device network interface fields + in: body + name: request + required: true + schema: + $ref: '#/definitions/dtos.DeviceNetworkInterfaceCreateDto' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dtos.DeviceNetworkInterfaceDto' + "400": + description: Bad Request + schema: + $ref: '#/definitions/dtos.ValidationErrorDto' + "500": + description: Internal Server Error + summary: Create device network interface + tags: + - device + /device/{id}/network-interface/{interfaceID}: + delete: + consumes: + - application/json + parameters: + - description: Device ID + in: path + name: id + required: true + type: string + - description: Device network interface ID + in: path + name: interfaceID + required: true + type: string + produces: + - application/json + responses: + "204": + description: OK, but No Content + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Delete device network interface by id + tags: + - device + get: + consumes: + - application/json + parameters: + - description: Device ID + in: path + name: id + required: true + type: string + - description: Device network interface ID + in: path + name: interfaceID + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dtos.DeviceNetworkInterfaceDto' + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Get device network interface by id + tags: + - device + put: + consumes: + - application/json + parameters: + - description: Device ID + in: path + name: id + required: true + type: string + - description: Device network interface ID + in: path + name: interfaceID + required: true + type: string + - description: Device network interface fields + in: body + name: request + required: true + schema: + $ref: '#/definitions/dtos.DeviceNetworkInterfaceUpdateDto' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dtos.DeviceNetworkInterfaceDto' + "400": + description: Bad Request + schema: + $ref: '#/definitions/dtos.ValidationErrorDto' + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Updates device network interface + tags: + - device + /device/{id}/power-command/: + post: + consumes: + - application/json + parameters: + - description: Device ID + in: path + name: id + required: true + type: string + - description: Device power command fields + in: body + name: request + required: true + schema: + $ref: '#/definitions/dtos.DevicePowerCommandDto' + produces: + - application/json + responses: + "204": + description: OK, but No Content + "404": + description: Not Found + "500": + description: Internal Server Error + summary: Send power device command + tags: + - device /dhcp/: get: consumes: