Compare commits

..

295 Commits

Author SHA1 Message Date
Danko Miladinovic 1a322f8ecb NOISSUE - Fix network interface problem for agent (#96)
* Added bus/addr for pcie net

* Remove SCSI parameters

* Remove bus parameter

* Removed blank lines
2024-03-15 16:37:41 +01:00
Sammy Kerata Oina 8c2caec395 NOISSUE - Use standard GitHub templates for issues and PRs (#92)
Implemented new GitHub templates to streamline the contribution process. Bug report and feature request templates guide users in creating detailed and actionable issues, while a universal pull request template ensures systematically structured submissions. These additions facilitate more efficient reviews, and prioritize issues effectively. Additionally, configured the repository to disallow blank issues, encouraging use of the templates for better project management.

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-03-13 13:06:51 +01:00
Sammy Kerata Oina de60358c02 NOISSUE - Enforce 32-byte length check for hashes (#86)
* Enforce 32-byte length check for hashes

Introduced a validation step in the manager service to ensure both algorithm and dataset hashes are of byte length 32 before provisioning VMs, preventing runtime errors due to invalid hash lengths. The test manager-server now generates a valid 32-byte hash using SHA256 for mock data to align with the new validation requirement.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* use equal comparison

Signed-off-by: SammyOina <sammyoina@gmail.com>

* use a constant

Signed-off-by: SammyOina <sammyoina@gmail.com>

* use constants

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-02-24 22:22:25 +01:00
Sammy Kerata Oina 997fb3bf48 COCOS-83 - Add hash verification for datasets and algorithms (#84)
* Add hash verification for datasets and algorithms

Enhanced data integrity checking by incorporating hash fields in Dataset and Algorithm structures, and modified the corresponding service logic to validate these hashes during processing. The update includes SHA-3 for hash computation, replacing the former SHA-256 usage, and ensures the provided data matches the expected hash from the manifest to prevent processing malformed or corrupted data.

- Introduce `Hash` field to both Dataset and Algorithm structs to store the expected hash value.
- Implement SHA-3 hashing within service methods that process the data, ensuring consistency with newly added `Hash` fields.
- Add error handling for hash mismatches, preventing further processing and alerting to potential data integrity issues.
- Update Protocol Buffers serialization to accommodate the new hash fields for gRPC communication.
- Modify manager service's Run method to pass the hash information when creating agent configurations.

Go module dependencies were updated to include the new SHA-3 package and upgrade Go version to 1.21.6 for improved stability and compatibility.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Remove identifiers from protobuf and related code

The protobuf definitions and related service handling code have been revised to drop specific identifier fields (`AlgorithmID` and `DatasetID`) to simplify API responses and internal function signatures. These removals streamline the overall data flow between components, reduce unnecessary data transmission, and lead to an aligned server-client expectation where identifiers are no longer a part of the response payload. Consequently, these changes simplify the logic within various functions and client commands, reinforcing encapsulation by ensuring that internal identifiers do not need to be managed or exposed unnecessarily.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix lint

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-02-19 15:31:35 +01:00
Sammy Kerata Oina 722b463b6a NOISSUE - Use a single listener for logs and events (#82)
* add handler

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor gRPC and Protobuf integration for manager service

- Shifted Protobuf message definitions to a separate package `pkg/manager`.
- Updated references throughout the codebase to import and use the new package for gRPC service definitions.
- Enhanced AgentLog message with additional fields `level` and `timestamp`.
- Removed direct dependencies on old Protobuf-generated types in favor of the new package.
- Deleted obsolete Protobuf-generated files as they are now superseded by the new `pkg/manager`.
- Streamlined event publishing and gRPC handling in the manager service to use the updated Protobuf messages.

This refactoring improves modularity by centralizing Protobuf message definitions and decouples internal representation from the gRPC interface, aligning with best practices for microservice architecture. Additionally, the enriched logging structure paves the way for more detailed and fine-grained log analysis.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor vsock event/log handling and config

Streamlined event and log services in the manager by moving vsock listening functions out of `managerService` initialization and into dedicated `RetrieveAgentEventsLogs` methods. This change decouples the manager service creation from the actual start of log listening, adding clarity and flexibility in service management. Also moved logging middleware invocation outside of network handling loops to avoid unnecessary overhead.

Additionally, the agent's vsock port configuration is now dynamically passed to the `New` function in the `events` package instead of relying on a hardcoded constant, allowing for greater configurability and testability.

Finally, updated message structures for event and log sending to conform with the `ClientStreamMessage` definitions. These modifications should improve parsing and handling consistency and prepare our system for future enhancements related to inter-process communication.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix linting errors

Signed-off-by: SammyOina <sammyoina@gmail.com>

* correct path to generated files

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix comments

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove uneccessary comments

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-02-15 17:02:05 +01:00
Sammy Kerata Oina 938dd6cb78 NOISSUE - mTLS support across services (#71)
* Implemented mTLS support across services

Extended gRPC configuration to support mutual TLS (mTLS) in agent and manager components for enhanced security. This includes the loading of Certificate Authority (CA) certificates, server, and client certificates, and keys. Updated README documentation to reflect the new environment variables required for mTLS configuration. Additionally, streamlined secure gRPC client connection setup and logging messages to indicate whether a service is running with TLS, mTLS, or without TLS.

The change ensures secure communication between services by verifying both client and server identities, thus addressing potential security concerns in network-level interactions.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Enhance agent cert handling and update copyright

- Implement function to create certificate files for the agent configuration dynamically, ensuring file paths are updated to reflect newly created files. This improves the agent's setup process by automating the certificate handling.
- Update copyright clause to reflect the new owning entity, Ultraviolet, affirming correct attribution and compliance with legal requirements.
- Refactor gRPC client connection code to remove redundant package alias, streamlining the codebase and improving readability.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor cert loading with fallbacks

Removed redundant certificate file creation logic in the agent module and introduced a more robust loading mechanism in the gRPC server module to support direct byte content aside from file paths. This change simplifies the initial setup process for the agent by removing the need to create certificate files preemptively, thereby streamlining deployment in environments with varying filesystem access. It supports using certificate contents directly, enhancing compatibility with in-memory configurations or environments where file storage may not be ideal.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix lint

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-02-08 10:07:51 +01:00
Sammy Kerata Oina e86860b9ea NOISSUE - Enhanced gRPC server concurrency with errgroup (#81)
* Enhanced gRPC server concurrency with errgroup

Refactored the gRPC server's `Process` method to handle incoming messages and service execution concurrently using an `errgroup.Group`. Added a context to the `grpcServer` struct and propagated it to support graceful shutdowns and better request handling. Changed the `Service` interface's `Run` method to use a channel for transmitting `ComputationRunReq`, facilitating non-blocking operation and streamlining the request-response cycle.

Asynchronous handling of stream requests with `errgroup` allows simultaneous processing and error management, improving the server's responsiveness and fault tolerance. This update paves the way for more robust service implementations that require concurrent operations.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove trailing space

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-02-08 10:05:41 +01:00
Sammy Kerata Oina e2fb7ea88d NOISSUE - Add test server (#80)
* add test server

Signed-off-by: SammyOina <sammyoina@gmail.com>

* clean up and update docs

Signed-off-by: SammyOina <sammyoina@gmail.com>

* update docs

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix lint

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-02-07 16:16:27 +01:00
Sammy Kerata Oina 6d0100c096 COCOS-73 - Remove server (#76)
* Refactor GRPC manager service and client

The manager service and client have been restructured for stream communication, facilitating real-time agent events, logs, and run responses. The `Run` RPC is replaced by the `Process` stream RPC, enabling bidirectional streaming between clients and the manager service. This allows continuous interchange of different message types including `WhoAmIRequest`, `AgentLog`, `AgentEvent`, and `RunResponse`.

Several message types have been adjusted and new fields introduced, like `AgentPort` in `RunResponse` and various agent-config attributes including CA files and instance IDs, to support TLS client authentication and distinguish between agent instances.

We've also incorporated `google.protobuf.Timestamp` in `AgentEvent` for precise event logging. The client code reflects these modifications with updated method calls and stream handling logic for ongoing communication. Moreover, the updates necessitate corresponding changes throughout service, grpc, and sdk layers to interoperate with the new streaming approach.

The transition to streaming paves the way for a more interactive, flexible communication system that can accommodate future expansion and real-time monitoring features.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* add computation id to run response

Signed-off-by: SammyOina <sammyoina@gmail.com>

* rename request

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-02-07 15:32:35 +01:00
Sammy Kerata Oina 8975e28437 COCOS-77 - Stream agent logs and events over gRPC (#78)
* Refactor GRPC manager service and client

The manager service and client have been restructured for stream communication, facilitating real-time agent events, logs, and run responses. The `Run` RPC is replaced by the `Process` stream RPC, enabling bidirectional streaming between clients and the manager service. This allows continuous interchange of different message types including `WhoAmIRequest`, `AgentLog`, `AgentEvent`, and `RunResponse`.

Several message types have been adjusted and new fields introduced, like `AgentPort` in `RunResponse` and various agent-config attributes including CA files and instance IDs, to support TLS client authentication and distinguish between agent instances.

We've also incorporated `google.protobuf.Timestamp` in `AgentEvent` for precise event logging. The client code reflects these modifications with updated method calls and stream handling logic for ongoing communication. Moreover, the updates necessitate corresponding changes throughout service, grpc, and sdk layers to interoperate with the new streaming approach.

The transition to streaming paves the way for a more interactive, flexible communication system that can accommodate future expansion and real-time monitoring features.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix lint

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Update GitHub Actions to Latest Versions

Upgraded GitHub Actions 'checkout' to version 4 and 'setup-go' to version 5 across various workflow files to leverage the latest features and improvements for better performance and reliability. This also ensures compatibility with Go version 1.21.x which is specified in the workflows.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor event handling and logging

Reworked event and log processing to use channels instead of direct HTTP calls. Removed obsolete events package and consolidated event structures, leading to cleaner and more maintainable code. Updated agent events to use channels, enhanced error handling in log forwarding, and simplified manager `New` function signature to accept an event channel directly.

- Removed `events` and `agentevents` packages to reduce complexity.
- Replaced direct event server communication with internal channel usage.
- Introduced `AgentEvent` struct in events.go for standardized event objects.
- Adapted `managerService` to dispatch events and logs through channels.
- Streamlined manager construction by removing the now-unnecessary event service and host IP parameters.

This change results in a more robust and easier to extend event and log management system within the agent-manager interaction.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix ci

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove unused code

Signed-off-by: SammyOina <sammyoina@gmail.com>

* add comments

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-02-07 12:08:39 +01:00
Sammy Kerata Oina 3e2be03047 NOISSUE - Attest validation and verification (#74)
* Expand CLI with Manager Service and Enhanced Attestation Commands

The CLI has been updated to interact not only with the Agent service but also with the Manager service, reflecting an expanded scope of operations. As part of this update, 'manager' subcommands have now been incorporated, ensuring users can seamlessly initiate computations through the manager service using the CLI.

Furthermore, attestation functionality has greatly improved. In addition to retrieving attestations from the agent, users can now validate and verify them directly from the CLI, bolstering security measures. New subcommands under 'attestation' provide clear and specific actions for attestation management.

Additionally, the command structure has been refactored to categorize commands under 'agent' or 'manager' prefixes, promoting better command organization and a more intuitive user experience.

These enhancements are part of ongoing efforts to provide robust and secure tools for service interaction and computational task management in distributed networks.

Relevant documentation adjustments and example usage have been updated in README files to align with these functional improvements.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* capitalize comments

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-02-07 12:02:41 +01:00
Sammy Kerata Oina 046b549079 Remove HTTP server support and streamline config (#75)
The HTTP server-related code, documentation, and configurations have been removed as part of a shift towards prioritizing gRPC for service communication. This update includes deletions of HTTP host and port configs across various components, the manager HTTP API alongside its Swagger definition, and the removal of related scaffolding and utility code. This change simplifies the overall architecture and eliminates redundant HTTP support, focusing on optimizing gRPC performance and security features.

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-02-07 11:03:46 +01:00
Sammy Kerata Oina 6f42135ec0 NOISSUE - Fetch attestation report (#66)
* Improve attestation and update deps

Enhanced the attestation process to require additional report data and a variable privacy level, catering to varying security requirements. The `Run` method's context parameter was removed to simplify invocation following API alignment. Dependencies got updated, notably adding `github.com/google/go-sev-guest` for attestation, and some were indirectly bumped. These updates ensure the agent service leverages the latest available features and improvements for security and stability.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Extend AttestationRequest with data fields

Enhanced the AttestationRequest message structure by introducing 'report_data' and 'vpml' fields to encapsulate additional attestation context. Adjusted service and middleware layers to incorporate these new parameters, enabling richer attestation workflows. The GRPC endpoint, logging, and metrics layers have been updated to handle the additional data, catering to more secure and nuanced attestation use cases.

Refactors Attestation command in CLI to accept report data argument and include an optional 'vpml' flag for specifying virtual machine privilege level. This change empowers users to request attestation with specific context directly from the CLI.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor attestation to remove vpml dependency

Removed the `vpml` field from the AttestationRequest protobuf, and all associated handling code, streamlining the attestation process. Code adjustments were made in gRPC client, server, and service layers to ensure proper request construction and validation that focuses only on report data. This change simplifies the attestation API and its usage, reducing error risk and improving maintainability. It reflects a decision to decouple the protocol from specific vendor measurement levels, potentially due to a shift towards a more generalized attestation procedure.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Enhance CLI usability and streamline SDK attestation

- Added a usage example to the CLI attestation command for better user guidance.
- Simplified the SDK attestation function by removing an unused parameter and directly populating the request structure with report data to align function parameters with actual usage requirements.

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-02-06 17:55:42 +01:00
Sammy Kerata Oina e5c8243f5f COCOS-62 - Add EOS images to release (#72)
* Add build and release GitHub workflow for tagged commits

Introduced a new GitHub Actions workflow to automate building and releasing for tagged commits. The workflow checks out the required repositories, builds the project using Buildroot configurations, and creates a release with the resultant kernel and rootfs artifacts. This streamlines the release process, ensuring consistent and reproducible builds.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Update GitHub Actions to Latest Versions

Upgraded GitHub Actions in the workflow to latest or more recent versions to leverage improvements and maintain compatibility. This includes using version 4 for checkout steps and switching to 'latest' for release creation and asset upload actions, ensuring the use of up-to-date features and potential bug fixes.

Ref: Internal upgrade protocol for CI/CD consistency.
Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix workflow

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Optimized checkout step in CI workflow

Ensured the checked-out repository's reference matches the current workflow's triggering reference. This alignment can result in more predictable builds, especially when the workflow is triggered by pushes to branches other than the default or by tagged commits.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* test repo

Signed-off-by: SammyOina <sammyoina@gmail.com>

* test modified module

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Update and upgrade Ubuntu in GitHub actions workflow

Ensure the GitHub actions runner has the latest Ubuntu updates before checking out the repository. This change significantly reduces the chances of encountering bugs or security vulnerabilities stemming from outdated packages, creating a more reliable and secure CI/CD environment.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* restore repo

Signed-off-by: SammyOina <sammyoina@gmail.com>

* install golang

Signed-off-by: SammyOina <sammyoina@gmail.com>

* create tags only for release

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-31 00:08:01 +01:00
Sammy Kerata Oina 8be6129889 NOISSUE - Fix bug on receiving logs and events, update deprecated methods (#68)
* Ensure graceful shutdown and improve connection handling

Refined the network connection handling in both agent events and logs to continuously process incoming data in a loop, enabling the services to handle more than a single message per connection. Additionally, instituted a deferred close operation for the event service to guarantee resources are cleanly released upon the application's termination.

Resolves potential resource leakage and enhances log processing efficiency.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Improve robustness in event and log handling

Altered handling in agent event and log services to continue processing incoming data rather than returning early upon encountering errors. This ensures that a single erroneous data point does not prematurely halt the processing loop, improving the robustness and reliability of the services. Potential errors are now reported and logged, yet the system remains operational to handle subsequent data.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Upgrade gRPC telemetry to use StatsHandler

Switched from using gRPC's UnaryInterceptor for telemetry to the more comprehensive StatsHandler provided by otelgrpc. This enhances telemetry collection by allowing the capture of a wider range of RPC stats, leading to improved monitoring and observability of the gRPC server.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* use constants

Signed-off-by: sammy <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
Signed-off-by: sammy <sammyoina@gmail.com>
2024-01-25 15:30:27 +01:00
Sammy Kerata Oina f2567830b3 NOISSUE - Remove docker (#67)
* Remove Docker-related build functionality

Removed the Docker build scripts, Dockerfile, and docker-compose definitions from the Makefile and relevant directories. Updated documentation by stripping out references to building and running Docker containers. This change likely reflects a shift towards a different deployment strategy or a move away from Docker as a dependency for builds and runtime. This simplification could lead to less complexity in the build process and reduce maintenance overhead associated with Docker configurations.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Removed Docker image build and publish workflow

The workflow for building and publishing a Docker image on pushes to the main branch has been removed. This step likely reflects a change in deployment strategy or a move to a different CI/CD pipeline. Continuous deployment might now be managed by another service or process, adhering to updated operational requirements or infrastructure changes.

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-25 15:29:16 +01:00
Sammy Kerata Oina 55c19ca6b5 NOISSUE - Refactor SDK and CLI (#69)
* Refactor CLI commands to use CLI struct

Introduced a CLI struct to encapsulate dependencies such as agentSDK and managerSDK previously passed to command constructors. This shift towards a more object-oriented approach simplifies command creation and enhances code readability. CLI-related commands are now methods on the CLI struct, accessing shared services directly, which streamlines the setup of CLI command hierarchies and reduces the need to pass dependencies around.

Removed the OpenAPI specification file as it was likely deemed obsolete or no longer necessary to be included with the CLI binary, suggesting a possible shift in how the API is managed or documented.

Lastly, the main application now sets up two distinct command groups for 'agent' and 'manager', with respective commands organized under them, making the CLI tool's structure more intuitive for users.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix ci

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-25 15:07:33 +01:00
Sammy Kerata Oina 0c77167be1 COCOS-56 - Pass agent computation events to manager (#63)
* Simplify event handling and config

Streamlined event service interface by consolidating `SendEvent` and introducing `SendRaw`. Removed `notification_server_url` and `instance_id` parameters from several event publication calls to leverage centralized event construction. This change not only cleans up redundancy in event-related code but also simplifies the configuration data flow across the system, making it easier to manage and less error-prone. Uniform event generation now improves consistency and maintainability.

Refactored configuration management in the agent and manager services. Removed notifications URL from the agent configuration, relying on a simplification that assumes a single source of events. Updated Manager Port to VsockConfigPort for clarity and consistency across vsock communication.

These modifications should facilitate easier integration and extension of event and configuration systems in the future.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix lint

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor error handling in agent event forwarding

Introduced context and error channel handling to the agent event forwarding process. The logger now warns on errors during forward operations asynchronously, allowing for non-blocking error reporting. Additionally, reliance on the global logger was removed in favor of passing error information via channels, improving modularity and error flow control.

Resolves issue with silent forwarding failures by providing a means to alert system operators without halting the service. This enhancement makes the error reporting more robust and reactive while maintaining service continuity.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove unused field

Signed-off-by: SammyOina <sammyoina@gmail.com>

* update package name

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-22 16:36:34 +01:00
Sammy Kerata Oina 34c3bbdbd8 COCOS-55 - Pass agent logs to manager via vsock (#64)
* Simplify event handling and config

Streamlined event service interface by consolidating `SendEvent` and introducing `SendRaw`. Removed `notification_server_url` and `instance_id` parameters from several event publication calls to leverage centralized event construction. This change not only cleans up redundancy in event-related code but also simplifies the configuration data flow across the system, making it easier to manage and less error-prone. Uniform event generation now improves consistency and maintainability.

Refactored configuration management in the agent and manager services. Removed notifications URL from the agent configuration, relying on a simplification that assumes a single source of events. Updated Manager Port to VsockConfigPort for clarity and consistency across vsock communication.

These modifications should facilitate easier integration and extension of event and configuration systems in the future.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix lint

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor error handling in agent event forwarding

Introduced context and error channel handling to the agent event forwarding process. The logger now warns on errors during forward operations asynchronously, allowing for non-blocking error reporting. Additionally, reliance on the global logger was removed in favor of passing error information via channels, improving modularity and error flow control.

Resolves issue with silent forwarding failures by providing a means to alert system operators without halting the service. This enhancement makes the error reporting more robust and reactive while maintaining service continuity.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove unused field

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Enhance agent logging via vsock connection

Redirected agent logging to use a vsock connection instead of standard output, improving the process isolation and enabling centralized log management. The change involved dialing to the specified vsock log port and initializing the logger with the vsock connection rather than stdout.

Additionally, the manager service now maintains a map of agent vsock cids to computation IDs, providing better tracking of computation resources. A routine to retrieve logs from agents was also initiated during the service setup to facilitate log collection.

Consequential to these changes is the removal of a redundant os package import in the agent's main.go, further cleaning up the dependencies.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fail gracefully

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Updated backoff strategy and VM configurations

- Added `github.com/cenkalti/backoff` to direct dependencies for robust retry logic in agent configuration sending.
- Modified the vsock logs port to align with the updated port range standards.
- Enclosed kernel console arguments in quotes to ensure proper parsing in QEMU configurations.
- Implemented exponential backoff when sending agent configurations to handle transient failures.

Refactors:
- Streamlined creation of `AgentConfig` within the computation setup to avoid unnecessary initializations when `c.AgentConfig` is not nil.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor command execution and improve argument construction

Consolidated the error handling in the command execution function for better readability. In the QEMU configuration, the argument assembly process is enhanced for clarity and correctness; the VNC parameter is now separate, and string quoting is handled properly for kernel parameters. These changes result in more maintainable code and prevent potential formatting issues during QEMU argument parsing.

Resolves issues with argument construction in QEMU config module.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refine default config handling and unpacking

Improved the agent configuration by dynamically setting default values for the log level and port if they are not specified in the incoming configuration. Also streamlined configuration unpacking in the endpoint and service layers, reducing redundancy and ensuring all required fields are correctly copied over to the Manager's configuration structure. This change ensures better fault tolerance and more maintainable code by handling edge cases where configuration values might be missing.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* rename dir

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix lint

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Ensure runRes.Empty() reflects non-empty state

Changed the always-true return value of the `runRes.Empty()` method to `false` to accurately indicate the presence of a response body. This adjustment ensures downstream handling of API responses aligns with actual content state.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Replace mglog with slog across codebase

Updated various components to replace the `mglog` logger implementation with the `slog` logger. This change affects logging initialization and calls throughout the codebase including the agent, manager, and internal server components. Transitioning to `slog` is part of a broader shift to standardize the logging mechanism to improve maintainability and consistency.

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-22 14:13:47 +01:00
Sammy Kerata Oina 55afe4c038 COCOS-49 - Pass agent configuration and computation via vsock (#57)
* Optimize QEMU launch and add V-sock support

Refactored QEMU argument construction and launching logic by removing the dependency on 'agent.Computation'. This simplification makes the VM creation process more streamlined. Additionally, introduced V-sock capabilities in the QEMU configuration to facilitate improved guest-host communication. Updated the README to include kernel module setup instructions for the new V-sock feature.

The V-sock implementation enables VMs to use a consistent communication channel that is not affected by network configuration changes, enhancing reliability and potential interoperability with host services. It's important to ensure that the necessary kernel modules are loaded as part of the setup process, as documented.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Add vsock-based communication to manager

Introduced virtual socket (vsock) communication abilities in the manager package by implementing a new socket service. This includes establishing a vsock listener and stub methods for sending computation results and cleaning up resources. The addition provides the groundwork for interprocess communication between guest and host in virtualized environments.

- Integrated the `mdlayher/vsock` library for handling virtual socket operations.
- Created a new `sockService` struct to encapsulate vsock listener handling.
- Implemented `NewVsock` constructor to initialize the listener with domain value `3`.
- Added placeholder methods for future computation sending and service closing logic.

This enhancement targets scenarios where efficient VM-to-host communication is required.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove env

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor agent config and use vsock

Introduce `AgentConfig` struct to group agent-related configurations, and update `Computation` struct to include the new `AgentConfig` field. Replace command-line computation extraction with vsock-based config retrieval for robustness and decoupling. The agent configuration is now read from a vsock connection during runtime, allowing for more dynamic and flexible deployments. Adjusted the main agent application logic to support these configuration changes, and corresponding changes have been made in the manager to facilitate vsock communication.

This approach aligns with modern practices for microservices by streamlining configuration management and reducing reliance on static command-line parameters. Moreover, it enhances the scalability of the agent service by allowing configuration to be managed externally.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor agent config and remove deprecated code

Consolidated agent configuration management into a single `AgentConfig` message and pruned deprecated Protobuf `ComputationReq`, `DatasetReq`, and `AlgorithmReq` messages. Adapted corresponding manager service logic to the new configuration structure. These modifications align with updated manager API schema, facilitate clearer configuration handling, and improve maintainability.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* send configuration

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Switch agent to listen mode for manager connections

Previously, the agent established a connection to the manager using a direct dial. This change shifts the setup to where the agent listens on a specified port and accepts incoming connections. It ensures that the agent properly handles incoming requests by initiating a listening socket and waiting for the manager to connect, enhancing the system's flexibility in connection management. This adjustment also includes graceful closure of the listening socket.

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-19 17:24:51 +01:00
Danko Miladinovic 2bb3b5650a Add support for vSockets in guest kernel (#61)
* Add python pip to buildroot

* Use DHCP for agent

* Use systemd for naming network interfaces

* Removed eth0 dhcp setting

* Add ETH_IFACE variable

* Added explanation for ETH_IFACE name

* Further explain ETH_IFACE value

* Add guest kernel support for VSOCKETS
2024-01-18 14:41:05 +01:00
Sammy Kerata Oina b4a49fb56c COCOS-58 - Remove refernece to network.link file (#59)
* Optimize QEMU launch and add V-sock support

Refactored QEMU argument construction and launching logic by removing the dependency on 'agent.Computation'. This simplification makes the VM creation process more streamlined. Additionally, introduced V-sock capabilities in the QEMU configuration to facilitate improved guest-host communication. Updated the README to include kernel module setup instructions for the new V-sock feature.

The V-sock implementation enables VMs to use a consistent communication channel that is not affected by network configuration changes, enhancing reliability and potential interoperability with host services. It's important to ensure that the necessary kernel modules are loaded as part of the setup process, as documented.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Add vsock-based communication to manager

Introduced virtual socket (vsock) communication abilities in the manager package by implementing a new socket service. This includes establishing a vsock listener and stub methods for sending computation results and cleaning up resources. The addition provides the groundwork for interprocess communication between guest and host in virtualized environments.

- Integrated the `mdlayher/vsock` library for handling virtual socket operations.
- Created a new `sockService` struct to encapsulate vsock listener handling.
- Implemented `NewVsock` constructor to initialize the listener with domain value `3`.
- Added placeholder methods for future computation sending and service closing logic.

This enhancement targets scenarios where efficient VM-to-host communication is required.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Revert "Optimize QEMU launch and add V-sock support"

This reverts commit 44557c39d9.

* Revert "Add vsock-based communication to manager"

This reverts commit d1d3c01f3b.

* Remove unnecessary network link file installation

Network configuration is being handled elsewhere, making the installation of the `00-network.link` file redundant. Eliminated the line from the agent Makefile to prevent potential conflicts and streamline the initialization process.

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-17 15:14:53 +01:00
Danko Miladinovic c25cfec84c Use DHCP for VM networking (#54)
* Add python pip to buildroot

* Use DHCP for agent

* Use systemd for naming network interfaces

* Removed eth0 dhcp setting

* Add ETH_IFACE variable

* Added explanation for ETH_IFACE name

* Further explain ETH_IFACE value
2024-01-15 19:27:07 +01:00
Danko Miladinovic cca75fc5cc Add python pip to buildroot (#51) 2024-01-12 17:51:26 +01:00
Filip Bugarski d24ce2b5bd NOISSUE - Fix Magistrala dependency version (#48)
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2024-01-12 14:44:41 +01:00
Sammy Kerata Oina 200f207673 fix logger (#47)
Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-12 14:34:54 +01:00
Danko Miladinovic 004f286900 Use systemd for HAL startup (#46) 2024-01-12 13:33:46 +01:00
Danko Miladinovic 0a0f757833 Use systemd for HAL boot (#40)
* Use systemd for HAL boot

* Removed unnecessary mkdir command

* Add  newline at the end of file

* Configure eth0 network interface

* Keep kernel naming scheme

* Fix agent.mk file for network interfaces
2024-01-11 22:05:42 +01:00
Sammy Kerata Oina 1167aeb53f NOISSUE - Update documentation (#20)
* Fix bug in agent service and state

The commit fixes a bug in the agent service and state files.
Previously, the condition to check the state in the agent service
was incorrect. It was checking the state directly instead of
using the GetState() method. This has been fixed by using the
GetState() method to check the state.

Additionally, a new GetState() method has been added to the
StateMachine struct in the state file. This method retrieves
the current state by acquiring a lock and returning the state
value.

The changes have been tested and verified to resolve the bug
and improve the accuracy of state checking in the agent service.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix bug in agent state machine

The bug in the agent state machine caused an error when attempting an invalid transition. This commit fixes the bug by properly locking and unlocking the state machine before and after transitioning to the next state. Additionally, the logger now correctly logs the current and next state during a valid transition.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix race condition in state machine

The commit fixes a race condition in the state machine implementation in the `Start` method. The race condition occurs when multiple goroutines try to access and modify the state concurrently. To fix this, a mutex lock and unlock are added around the critical sections of code to ensure exclusive access to the state variable. This prevents race conditions and ensures the state transitions are executed correctly.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix race condition in StateMachine.Start()

The StateMachine.Start() method was experiencing a race condition
when multiple events were being processed concurrently. This was
caused by not properly locking and unlocking the state machine
before and after updating the state. This commit fixes the issue
by adding proper locking and unlocking around the state update
operation. Additionally, the logging statement has been updated
to include the previous and next states for better debugging.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* add magistrala dep

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove mainflux

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Add Docker environment variables for Nats, RabbitMQ, Message Broker, and Jaeger.

The commit message should be:

"Add Docker environment variables for Nats, RabbitMQ, Message Broker, and Jaeger"

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix notification topic in agent service and update NATS ports in Docker environment variables

The agent service's notification topic was incorrectly set to "channels.manager" instead of "agent". This commit fixes the issue by updating the notification topic.

Additionally, the NATS ports in the Docker environment variables were incorrect. The COCOS_NATS_PORT and COCOS_NATS_HTTP_PORT have been updated to the correct values.

These changes ensure that the agent service uses the correct notification topic and the NATS ports are properly configured.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor Makefile and add new targets for building Docker images

The Makefile has been refactored to include new targets for building Docker images. The `make_docker` and `make_docker_dev` functions have been defined to handle the Docker build process. The `dockers` and `dockers_dev` targets have been added to build the Docker images for all services and development environments respectively.

This commit introduces changes to the Makefile to improve the build process and provide support for Docker images.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* update readme

Signed-off-by: SammyOina <sammyoina@gmail.com>

* wrap env vars

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor main.go in cmd/cli

The main.go file in cmd/cli has been refactored to improve code readability and maintainability. The defURL constant has been removed as it is no longer needed. Additionally, unnecessary whitespace has been removed.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix linting

Signed-off-by: sammy <sammyoina@gmail.com>

* rename cocos-ai to cocos

Signed-off-by: sammy <sammyoina@gmail.com>

* Updated README with NATS setup instructions and correct systemd path

Expanded the project's README to include setup instructions for the NATS server, which is now a necessary component for agent and manager communication. Additionally, the systemd service file path has been corrected from 'systemd' to 'init/systemd' ensuring the agent's proper installation and configuration as a daemon. This facilitates a smoother setup experience and reflects the dependency on NATS for push notifications.

Ref: Agent and manager communication enhancement
Signed-off-by: SammyOina <sammyoina@gmail.com>

* Added message broker URL to agent service config

Included the environment variable for the message broker URL in the systemd service configuration to facilitate agent communication with the messaging system. This ensures the agent can connect to the designated message broker for event publishing and subscription.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* update docs to hal

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Remove TLS and timeout config from gRPC client

Refactored gRPC client and associated API code by removing unnecessary TLS configuration and timeout settings. Simplified the communication setup by trusting the environment to enforce security policies and handle operation durations, instead of hardcoding these within the application.

This brings about a cleaner, more maintainable codebase and shifts responsibility for security configurations out of the code, aligning with infrastructure-as-code practices and enabling easier scalability and environment-specific adjustments.

This change also affects the API documentation and example commands, which have been updated accordingly to reflect the simplification and to guide users with the streamlined setup process.

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
Signed-off-by: sammy <sammyoina@gmail.com>
2024-01-11 15:19:34 +01:00
Sammy Kerata Oina a5e6cae92c COCOS-44 - Add agent address to run responses (#45)
* Add agent address to run responses

The manager service's Run method now retrieves the agent address upon successful computation execution, providing more informative responses across gRPC, HTTP, and logging endpoints. This change improves service transparency by returning the agent's address to be used by client services, making the manager service's external communication more comprehensive. Updated the `RunResponse` structure in the corresponding protocol buffers definition and response handling in gRPC and HTTP APIs, ensuring that agent address information is serialized appropriately. It also necessitates a slight adjustment in the QEMU configuration to manage port forwarding rules more dynamically, simplifying the process as only agent-relevant ports are incremented with each new computation. This extra detail in responses aids in debugging and offers better integration capabilities for clients.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Allocate dynamic ports for VM guests and expand error handling

Refactored service initialization to accept host IP and incorporated dynamic port allocation for VM guests, replacing the prior static increment method. Introduced a new error type 'ErrFailedToAllocatePort' to capture instances where the system is unable to find a free port. Integrated a third-party error package for improved error wrapping and context. These changes prevent port conflicts between VM guests and enhance error diagnostics for service operations.

Resolves issue with static port allocation leading to conflicts.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Add HOST_IP to service configuration

Extend service configuration to include the host machine's IP address, allowing instances to be aware of their deployment environment. This update passes the new HostIP field to the service constructor, ensuring the service can now operate with host-specific logic.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Populate AgentAddress in gRPC Responses

Enhanced the gRPC encode/decode functions to properly populate the 'AgentAddress' field in 'RunResponse' objects. This ensures that consumers of the gRPC interface receive complete response data, which previously omitted the important 'AgentAddress' information. The change impacts both server-side response encoding and client-side response decoding, aligning the implementation with the expected interface contract.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix ci

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-11 15:08:35 +01:00
Sammy Kerata Oina c29ef354fa COCOS-24 - Add events service via http (#27)
* add status endpoint

Signed-off-by: sammy <sammyoina@gmail.com>

* feat: Update code generation tools to latest versions

Update the code generation tools, including protoc-gen-go and
protoc-gen-go-grpc, to their latest versions (v1.31.0 and v1.3.0,
respectively). This ensures compatibility with the latest features and
improvements. The updated tools also require gRPC-Go v1.32.0 or later.

The new versions bring important updates and bug fixes, enhancing the
performance and stability of the generated code. By staying up-to-date
with the latest tooling, we can take advantage of the latest
functionality and ensure a smooth development experience.

No code changes are included in this commit. These updates only impact
the code generation process.

Signed-off-by: sammy <sammyoina@gmail.com>

* Update Go version to 1.21.x

Signed-off-by: sammy <sammyoina@gmail.com>

* Refactor agent and manager services to publish event notifications

The refactoring includes changes to the agent and manager services to incorporate event notifications. By publishing events, the services can inform subscribers about the current state of the computation or any updates. Specifically, the `agentService` now includes a `cmpHash` field to store the SHA-256 hash of the computation, which is subsequently used when publishing events. The `agentService` and `managerService` now use the `publisher` interface to publish events to the topic "manager". Notably, the removed `pubsub.go` file is no longer necessary.

This commit improves the service architecture by allowing subscribers to receive relevant updates and monitor the progress of computations. It enhances the overall system by providing more transparency and enabling better coordination between the agent and manager services.

Signed-off-by: sammy <sammyoina@gmail.com>

* Improve generated Go file comparison in checkproto workflow

Refactor the file comparison logic in the checkproto workflow to use the `-p` flag instead of `-s` for improved accuracy. This change ensures that the generated Go files are thoroughly compared with the original ones, detecting any discrepancies and preventing out-of-sync files from passing the validation. By using the `-p` flag, we now check both the contents and the metadata of the files, providing more robust synchronization checks. This update enhances the reliability of the checkproto workflow and helps maintain consistency between the proto files and their corresponding generated Go files.

Signed-off-by: sammy <sammyoina@gmail.com>

* Update file comparison command to detect differences line by line

The code change updates the file comparison command used in the CI workflow to detect differences line by line instead of only reporting the first difference encountered. This change improves the accuracy of detecting inconsistencies between the original protobuf files and the generated Go files. Previously, only the first difference was reported, leading to potential missed issues. By comparing the files line by line, we can now detect and report all differences accurately. This change enhances the reliability of our CI pipeline and ensures that the generated Go files stay in sync with the protobuf files.

Signed-off-by: sammy <sammyoina@gmail.com>

* add event exporting to external server

Signed-off-by: sammy <sammyoina@gmail.com>

* feat: Add support for notification server URL

The commit adds a new environment variable, `COCOS_NOTIFICATION_SERVER_URL`, which allows specifying the server to receive notification events from the agent. This addition provides flexibility to configure the notification server URL based on the deployment environment. This change enables seamless integration with different notification server instances and enhances the extensibility of the system. It resolves the need to modify the code directly when changing the server URL.

Signed-off-by: sammy <sammyoina@gmail.com>

* Refactor gRPC client and server, remove unused handlers

The commit refactors the gRPC client and server code by removing the unused `nopDecoder` and `status` handlers from the client and server, respectively. This cleanup reduces code clutter and improves maintenance. No significant consequences are expected.

Signed-off-by: sammy <sammyoina@gmail.com>

* Ensure generated Go files stay in sync with proto files during the CI workflow

Fixes an issue in the CI workflow where proto files and their corresponding generated Go files were not being properly compared for synchronization. Previously, the `cmp -l` command was used, which only printed differing byte positions, leading to false negatives. This has been corrected by using `cmp -s` instead, which outputs nothing if the files are identical. This change ensures that any differences between the proto files and their generated Go files will be detected, helping to maintain consistency and accuracy in the codebase.

Signed-off-by: sammy <sammyoina@gmail.com>

* Enhance notification payload and endpoint

Extended the notification system to include 'status' and 'details' in the payload, improving traceability and debugging. Adapted the serialized JSON structure for clarity and added an 'originator' field to track the source service. Transitioned to a generalized event endpoint, facilitating a more streamlined event handling process.

Refactors POST request to a more appropriate endpoint and updates the notification service interface to reflect new payload requirements.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor event notification logic

Removed the legacy notifications package and consolidated event notification functionality using the new internal events service. Modified agent, manager, and main application code to use this service for consistent event reporting and error handling workflows across services. This change simplifies event management, improves error visibility, and allows for more maintainable code by centralizing event-related logic. The substitution of verbose state-specific publishEvent calls with generic status reporting aligns with the new service's capabilities.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Expand agent protobuf message types and improve error handling

The protobuf definition for agent messages has been updated to include an additional message type, facilitating future data structure expansions. Additionally, error handling for event sending in the main agent execution has been enhanced to log errors when sending 'init' events fail, ensuring issues are properly tracked. The unused `notificationTopic` constant in the manager service has been removed for cleaner code maintenance.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Optimize JSON parsing and fix header omission

Removed unnecessary unquoting of a JSON string before unmarshaling, streamlining the computation value extraction process. Also corrected a missing Content-Type header in the event sending function, ensuring proper handling of JSON requests by recipients. These changes improve performance and communication reliability.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* align vars

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Remove computation request timeout feature

The timeout feature for computation requests has been removed to simplify the computation execution flow. This involved changes across multiple files, including protobuf definitions, HTTP endpoint handling, and the internal computation logic. We eliminated the timeout field, associated logic, and error handling to ensure the system no longer supports timeouts for computations, mitigating any unintended timeout impacts on long-running processes.

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: sammy <sammyoina@gmail.com>
Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-11 14:37:14 +01:00
Sammy Kerata Oina b55b6c9734 NOISSUE - Refactor computation parameter naming and remove tracing (#42)
Standardized the variable name for computation parameter across various service and middleware implementations to improve code consistency. This enhances readability and maintainability.

Additionally, tracing functionality has been removed completely, signifying a potential shift in the telemetry strategy or removal of an unused feature. The run command associated with cli package has also been deleted, suggesting a change in the CLI tool's capabilities or its command handling strategy.

The service interface's Run method definition and its implementations now align with the updated parameter naming, ensuring coherence throughout the codebase.

Removed files:
- The entire `tracing` package has been deleted.
- Removed the `cli/run.go` file, indicating the removal of the 'run' command from the CLI.

Please note that these changes may affect any existing workflows or systems that rely on the removed tracing capabilities or the CLI run command, and appropriate adjustments will need to be made to accommodate these updates.

Refer to internal documentation or release notes for migration paths or additional context.

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-10 11:52:37 +01:00
Sammy Kerata Oina 4d9f7b1a45 COCOS-25 - Remove networking between manager and agent (#43)
* Enable passing computation details to QEMU args

Refactored the QEMU argument construction to accept computation details as JSON. The changes include updating function signatures to pass an `agent.Computation` object and serialize it into the QEMU boot parameters. These modifications allow for custom computations to be specified per VM, facilitating more dynamic and configurable virtual machine creation. This update also integrates timing and data transformation necessary for the agent computation setup.

Resolves computation configurability for virtual machines.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Enable extraction of computation value from cmdline

Introduced a feature to parse the computation parameter directly from the machine's command line, thus enabling dynamic configuration of agent computations without the need for a preset environment. This change enhances the agent's ability to adapt to different computation requirements on startup. A fallback warning informs of cases where the computation parameter was not found, ensuring traceability of operational state during service initialization.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Remove RunRequest and RunResponse from Agent gRPC

Refactor the Agent service by deleting the RunRequest and RunResponse messages along with the corresponding method implementations in the gRPC interface. This simplifies the gRPC protocol by removing an obsolete RPC method, streamlining communication between services. The deletion also impacts the manager service, which no longer uses the removed RPC method. Consequently, the service definitions across related files like endpoints, servers, and clients have been adjusted. This adjustment enforces a more direct approach for starting computations, reflecting a shift toward manager-initiated computation execution.

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-09 20:07:45 +01:00
Sammy Kerata Oina 46a91ccbc3 remove nats (#41)
Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-09 19:56:31 +01:00
Sammy Kerata Oina 8c5bb52c56 COCOS-7 - Switch qemu config to use kernel and initrd images (#39)
* Switch qemu config to use kernel and initrd images

Refactored qemu configuration to load the system using separate kernel and initial ramdisk images instead of a QCOW2 image. Removed previous disk image configurations and replaced them with directives to specify the kernel (`bzImage`) and root filesystem (`rootfs.cpio.gz`) files. Adjusted the constructQemuArgs function accordingly to set the kernel path, kernel command line options, and initrd path. Updated CreateVM function to handle copying of the new kernel and rootfs images. These changes align the virtual machine setup process with a more modular and potentially customizable boot configuration.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix lint

Signed-off-by: SammyOina <sammyoina@gmail.com>

* capcomments

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-08 18:05:35 +01:00
Sammy Kerata Oina ee7159a406 COCOS-35 - Refactor RunRequest to use structured Computation (#38)
* Refactor RunRequest to use structured Computation

The protobuf and associated service implementations for the RunRequest message were refactored to replace the raw Computation byte slice with a structured ComputationReq object. This allows clearer and more type-safe manipulation of computation requests. The grpc, http, and agent service layers were updated to build and parse ComputationReq accordingly. The ComputationReq structure includes details like IDs, names, time stamps, and metadata, forming a well-defined contract for computation tasks.

This change aligns with efforts to standardize request formats and improve clarity in inter-service communication. It impacts all systems interfacing with the RunRequest service and thus requires coordinated updates to the entire stack.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Initialize metadata maps and handle nil values

Improved the robustness of metadata handling in gRPC endpoints and SDK by initializing metadata maps and explicitly checking for nil values before converting them. This ensures that both the agent's gRPC endpoint and the SDK properly handle cases where metadata fields may be uninitialized or contain nil values, preventing potential null pointer exceptions.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor computation request handling

Refactored the endpoint to construct Computation object from gRPC request, incorporating structpb for metadata handling and timestamppb for StartTime and EndTime fields. The management service and API requests are also updated to align with these changes, improving type safety and ensuring data is correctly marshalled when making service calls.

Resolves data marshalling issues for computation requests.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* use singular

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove unuse fields

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove unused fields

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-08 17:51:46 +01:00
Sammy Kerata Oina ee1f5ebb3d NOISSUE - Optimize context deadline and error handling (#34)
Improved the timing logic for setting computation deadlines by replacing the channel-based pattern with a direct time addition. This change enhances the performance by preventing unnecessary channel operations.

Additionally, relocated the select block that checks for computation timeout and data reception errors. This alteration ensures that the socket connection acceptance routine starts before any timeouts or errors are checked, thereby avoiding potential race conditions and making the code more resilient to early timeout scenarios.

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-04 12:53:08 +01:00
Sammy Kerata Oina 7ea8e48dbb NOISSUE - Optimized Docker build (#32)
Refactored the Dockerfile to use multi-stage builds, improving the image size and separation of concerns. Removed `qemu-system-x86_64` from the initial build stage and included it in a new, minimal final image based on `alpine:latest`. This change minimizes the production image size by avoiding unnecessary build dependencies in the final artefact. Additionally, the CA certificates are now copied into the final stage to maintain SSL functionality.

The development Dockerfile has been cleaned to match new conventions.

Resolves issues with bloated Docker images and unneeded dependencies in production.

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-04 12:35:29 +01:00
Sammy Kerata Oina a3c5c765b8 NOISSUE - Connect to agent when vm is created (#33)
* Add gRPC TLS config and update protoc versions

Enhanced manager service with TLS configuration options and timeout settings for gRPC communication with agent services. Updated corresponding protobuf definitions to include new fields for CA certificates, TLS status, and timeouts. The added TLS support ensures secure inter-service communication while flexible timeout configurations improve the robustness of network interactions.

The following adjustments and additions were made:
- Included new gRPC configuration fields (ca_certs, client_tls, timeout) for agent communication in protobuf definitions.
- Injected agent gRPC configuration into service endpoints, ensuring secure TLS setup and compliance with provided settings.
- Revised main service function signatures to accept the gRPC configuration object.
- Incremented port forwarding counters post-computation to avoid port conflicts.
- Conducted compatibility update of protobuf version comments to reflect minor version bump (v4.25.0 to v4.25.1).

This change impacts service deployment that requires proper configuration of TLS credentials and mindful determination of timeouts for efficient network use.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* update proto

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Set default timeout for agent configuration

Introduced a default timeout of 60 seconds in both gRPC and HTTP endpoints for agent configuration when none is specified. This change ensures that operations do not hang indefinitely and provides a reasonable default for client interactions. Additionally, the instantiation of a new agent client is now outside the retry loop to avoid repeated setup on transient failures.

Refactors service logic to optimize client connection handling by moving the agent client setup to occur before attempting retries, which should reduce overhead and improve clarity in error situations.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Subject: Move agent client creation into retry loop

Body:
Refactored the service manager's Run method to initialize the agent gRPC client inside the exponential backoff retry loop. This change addresses intermittent connection issues by reattempting client creation on temporary network failures, ensuring a robust setup before calling the Run method on the client.

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2024-01-04 12:34:57 +01:00
Sammy Kerata Oina 34c5472485 NOISSUE - Remove multiple brokers (#31)
* remove multiple brokers

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Standardize build process on NATS messaging

Removed conditional build flags for different message broker types, making NATS the default and only option. Simplified the Makefile by eliminating the toggleable message broker configuration and related docker-based setup. Updated the NATS URL in docker `.env` and docker-compose service dependency to reflect this change. This adjustment streamlines the build process and reduces configuration complexity.

Resolves issues with inconsistent messaging setups across various environments.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor message broker configuration

Standardized the environment variable for the message broker URL across services and updated documentation to reflect this change. Renamed the environment variable from COCOS_NATS_URL to COCOS_MESSAGE_BROKER_URL to improve clarity and maintain consistency in service configuration. This alteration facilitates future support for different message broker backends beyond NATS without further variable name changes.

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2023-12-24 19:45:04 +01:00
Sammy Kerata Oina 1fec5fe3d4 add repo readme (#30)
Signed-off-by: SammyOina <sammyoina@gmail.com>
2023-12-24 15:46:31 +01:00
Dusan Borovcanin 4c53fd26e3 NOISSUE - Fix CI Docker build
Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>
2023-12-21 17:43:03 +01:00
Sammy Kerata Oina 668552256f NOISSUE - Create and publish a Docker image (#29)
* Create and publish a Docker image

This commit adds a new file `.github/workflows/build.yml` which contains the workflow configuration for creating and publishing a Docker image. The workflow is triggered on push events to the `main` branch. It sets environment variables for the registry and image name. The job runs on `ubuntu-latest` and has necessary permissions for reading contents and writing packages. The steps include checking out the repository, logging in to the container registry using the GitHub token, and extracting metadata for Docker.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor build workflow and update Makefile

The build workflow has been refactored to build the Manager image instead of the API Gateway image. The Makefile has also been updated.

The changes include:
- Renaming the build step to "Build Manager and push Docker image"
- Updating the image name to include "/manager"
- Updating the build arguments to use "SVC=manager"
- Updating the tags to use the output from the metadata action

These changes ensure that the correct Docker image is built and pushed.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove labels

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2023-12-21 17:26:34 +01:00
Danko Miladinovic 3e7fc09233 Update documentation (#28)
* Modify external.desc and README

* Added a blank line at end of external.desc file
2023-12-08 16:45:02 +01:00
Drasko DRASKOVIC 0dac01d752 NOISSUE - Add HAL (#26)
* Add HAL

Signed-off-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com>

* Add Agent package in HAL

Signed-off-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com>

---------

Signed-off-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com>
2023-12-05 15:08:49 +01:00
Sammy Kerata Oina 18508796c1 add linters (#23)
- switchTrue
      - importShadow
      - httpNoBody
      - paramTypeCombine
      - emptyStringTest
      - builtinShadow
      - exposedSyncMutex
      - importas

Signed-off-by: SammyOina <sammyoina@gmail.com>
2023-11-24 18:59:42 +01:00
Sammy Kerata Oina 5adf0349a3 COCOS-9 - Dockerize manager (#18)
* Fix bug in agent service and state

The commit fixes a bug in the agent service and state files.
Previously, the condition to check the state in the agent service
was incorrect. It was checking the state directly instead of
using the GetState() method. This has been fixed by using the
GetState() method to check the state.

Additionally, a new GetState() method has been added to the
StateMachine struct in the state file. This method retrieves
the current state by acquiring a lock and returning the state
value.

The changes have been tested and verified to resolve the bug
and improve the accuracy of state checking in the agent service.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix bug in agent state machine

The bug in the agent state machine caused an error when attempting an invalid transition. This commit fixes the bug by properly locking and unlocking the state machine before and after transitioning to the next state. Additionally, the logger now correctly logs the current and next state during a valid transition.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix race condition in state machine

The commit fixes a race condition in the state machine implementation in the `Start` method. The race condition occurs when multiple goroutines try to access and modify the state concurrently. To fix this, a mutex lock and unlock are added around the critical sections of code to ensure exclusive access to the state variable. This prevents race conditions and ensures the state transitions are executed correctly.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix race condition in StateMachine.Start()

The StateMachine.Start() method was experiencing a race condition
when multiple events were being processed concurrently. This was
caused by not properly locking and unlocking the state machine
before and after updating the state. This commit fixes the issue
by adding proper locking and unlocking around the state update
operation. Additionally, the logging statement has been updated
to include the previous and next states for better debugging.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* add magistrala dep

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove mainflux

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Add Docker environment variables for Nats, RabbitMQ, Message Broker, and Jaeger.

The commit message should be:

"Add Docker environment variables for Nats, RabbitMQ, Message Broker, and Jaeger"

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix Makefile to properly set DOCKER_PROJECT and COCOS_MESSAGE_BROKER_TYPE

The Makefile has been updated to fix an issue with setting the DOCKER_PROJECT and COCOS_MESSAGE_BROKER_TYPE variables. The USER_REPO variable is now used to generate the DOCKER_PROJECT name following the Docker Compose guidelines. Additionally, the COCOS_MESSAGE_BROKER_TYPE variable is now properly set to "nats" if it is empty. This ensures that the correct values are used when compiling and installing the service.

Summary:
Fix Makefile to properly set DOCKER_PROJECT and COCOS_MESSAGE_BROKER_TYPE

Details:
- Update USER_REPO variable to generate DOCKER_PROJECT name
- Set COCOS_MESSAGE_BROKER_TYPE to "nats" if empty

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix notification topic in agent service and update NATS ports in Docker environment variables

The agent service's notification topic was incorrectly set to "channels.manager" instead of "agent". This commit fixes the issue by updating the notification topic.

Additionally, the NATS ports in the Docker environment variables were incorrect. The COCOS_NATS_PORT and COCOS_NATS_HTTP_PORT have been updated to the correct values.

These changes ensure that the agent service uses the correct notification topic and the NATS ports are properly configured.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Add Dockerfiles for production and development environments

This commit adds two new Dockerfiles, one for the production environment and one for the development environment. The production Dockerfile sets up the necessary dependencies and builds the application, while the development Dockerfile simply copies the built application. Both Dockerfiles include the necessary SSL certificates for the application to work properly.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor Makefile and add new targets for building Docker images

The Makefile has been refactored to include new targets for building Docker images. The `make_docker` and `make_docker_dev` functions have been defined to handle the Docker build process. The `dockers` and `dockers_dev` targets have been added to build the Docker images for all services and development environments respectively.

This commit introduces changes to the Makefile to improve the build process and provide support for Docker images.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix makefile to generate Docker images for services

- Added DOCKERS and DOCKERS_DEV variables to generate Docker images for services
- Updated the dockers target to include DOCKERS
- Updated the dockers_dev target to include DOCKERS_DEV
- Updated the $(DOCKERS) and $(DOCKERS_DEV) targets to call the respective make_docker and make_docker_dev functions

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor Makefile and Dockerfile

The Makefile has been refactored to remove unnecessary sed commands and improve code readability. The changes include:

- Removed sed commands related to changing the broker in docker-compose.yml for nats and rabbitmq profiles.
- Removed the eer target from the Makefile.

The Dockerfile has been modified to include the WORKDIR directive.

These changes improve the maintainability and readability of the codebase.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix NATS URL in .env file and add Manager configuration in docker-compose.yml

The NATS URL in the .env file was updated to use the correct hostname for the broker. Additionally, the Manager configuration was added to the docker-compose.yml file.

This commit fixes the NATS URL in the .env file and adds the necessary Manager configuration to the docker-compose.yml file.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix incorrect host and port values in Makefile and .env

The commit updates the host and port values in the Makefile and .env files to fix incorrect values. The host and port values are updated to "cocos-manager" and "7003" respectively. This ensures that the correct host and port are used for the Manager HTTP and gRPC services.

This commit resolves the issue with the incorrect host and port values and ensures that the Manager services are configured correctly.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix Dockerfile and docker-compose.yml configurations

The Dockerfile and docker-compose.yml configurations have been fixed to address the following issues:

- Removed unnecessary COPY commands in the Dockerfile.
- Removed the "privileged" flag in the docker-compose.yml file.

These changes ensure that the Docker image is built correctly and the container is launched with the appropriate configurations.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove manual assignment

Signed-off-by: SammyOina <sammyoina@gmail.com>

* update protoc CI

Signed-off-by: SammyOina <sammyoina@gmail.com>

* add paths

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove profiles

Signed-off-by: SammyOina <sammyoina@gmail.com>

* restore default config

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix Docker project name in Makefile

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2023-11-24 18:57:31 +01:00
Sammy Kerata Oina 0f831706f9 NOISSUE - Add CoCos-AI Manager API specification (#19)
* Add CoCos-AI Manager API specification

This commit adds the CoCos-AI Manager API specification
in the form of a YAML file. The specification includes
information about the title, description, contact,
license, and version of the API. It also defines the
servers where the API is hosted and the paths and
operations available, such as running computation on
a virtual machine.

The API specification is based on OpenAPI 3.0.1 and
provides a clear and concise overview of the CoCos-AI
Manager service.

The commit also includes a link to the CoCos-AI repository
and the license information.

This commit is necessary to provide a clear and documented
API specification for the CoCos-AI Manager service.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor go.mod and go.sum files

The go.mod and go.sum files have been refactored to remove the go.opentelemetry.io/contrib/propagators/jaeger package, which is no longer needed. This package was causing compatibility issues with the current version of the project. The refactoring ensures that the project is using the latest compatible versions of the required dependencies.

This commit removes the go.opentelemetry.io/contrib/propagators/jaeger package from the go.mod file and updates the go.sum file accordingly.

Note: The go.mod file now uses go.opentelemetry.io/otel v1.19.0 and go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0.

Please review the changes to ensure compatibility and functionality.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix typo

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2023-11-24 18:54:54 +01:00
Sammy Kerata Oina 298878c96d NOISSUE - Rename module to cocos (#22)
* add stringer

Signed-off-by: SammyOina <sammyoina@gmail.com>

* rename module to cocos

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix fmt.Stringer implementation in computations.go

The fmt.Stringer implementation for Datasets and Algorithms in computations.go was fixed to correctly use pointers.

This commit addresses the issue where the String() method for Datasets and Algorithms in computations.go was not correctly implemented. The fix ensures that the String() method now correctly marshals the data to JSON and returns the string representation.

The changes made in this commit will improve the functionality and accuracy of the String() method for Datasets and Algorithms.

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2023-11-22 13:15:19 +01:00
Dušan Borovčanin 7b31e21818 NOISSUE - Fix attestation gRPC call (#21)
Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>
2023-11-21 12:25:24 +01:00
Sammy Kerata Oina 4ea9ff6531 NOISSUE - Add message broker on agent and manager (#17)
* Fix bug in agent state machine

The bug in the agent state machine caused an error when attempting an invalid transition. This commit fixes the bug by properly locking and unlocking the state machine before and after transitioning to the next state. Additionally, the logger now correctly logs the current and next state during a valid transition.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix race condition in state machine

The commit fixes a race condition in the state machine implementation in the `Start` method. The race condition occurs when multiple goroutines try to access and modify the state concurrently. To fix this, a mutex lock and unlock are added around the critical sections of code to ensure exclusive access to the state variable. This prevents race conditions and ensures the state transitions are executed correctly.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix race condition in StateMachine.Start()

The StateMachine.Start() method was experiencing a race condition
when multiple events were being processed concurrently. This was
caused by not properly locking and unlocking the state machine
before and after updating the state. This commit fixes the issue
by adding proper locking and unlocking around the state update
operation. Additionally, the logging statement has been updated
to include the previous and next states for better debugging.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* add magistrala dep

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove mainflux

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix agentService New function to include messaging.Publisher parameter

The agentService New function has been updated to include a messaging.Publisher parameter. This change allows the agent service to publish messages to a messaging system. The messaging.Publisher parameter has been added to the agentService struct and the New function signature has been updated accordingly. This change ensures that the agent service can communicate with other components using the messaging system.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Refactor service.go state functions

The commit refactors the state functions in the service.go file.
The functions for each state have been modified to use the svc.publishEvent
method to publish events with appropriate messages.

- Refactor state functions in service.go
- Use svc.publishEvent to publish events with messages for each state

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix computation run event publishing and add pubsub functionality

The computation run event publishing in the agent service was fixed to correctly call the publishEvent function. Additionally, the pubsub functionality was added to the manager package.

- Fixed computation run event publishing in agent service
- Added pubsub functionality to manager package

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix license header in pubsub.go file

The commit fixes the license header in the pubsub.go file.
The copyright and SPDX-License-Identifier have been added
to comply with the Apache-2.0 license.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Add Docker environment variables for Nats, RabbitMQ, Message Broker, and Jaeger.

The commit message should be:

"Add Docker environment variables for Nats, RabbitMQ, Message Broker, and Jaeger"

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix Makefile to properly set DOCKER_PROJECT and COCOS_MESSAGE_BROKER_TYPE

The Makefile has been updated to fix an issue with setting the DOCKER_PROJECT and COCOS_MESSAGE_BROKER_TYPE variables. The USER_REPO variable is now used to generate the DOCKER_PROJECT name following the Docker Compose guidelines. Additionally, the COCOS_MESSAGE_BROKER_TYPE variable is now properly set to "nats" if it is empty. This ensures that the correct values are used when compiling and installing the service.

Summary:
Fix Makefile to properly set DOCKER_PROJECT and COCOS_MESSAGE_BROKER_TYPE

Details:
- Update USER_REPO variable to generate DOCKER_PROJECT name
- Set COCOS_MESSAGE_BROKER_TYPE to "nats" if empty

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix Makefile Docker profile assignment and build flags

The Makefile was updated to fix the assignment of the Docker profile and build flags. The Docker profile is now assigned based on the value of COCOS_MESSAGE_BROKER_TYPE, and if it is not provided, the default value is set to "nats". The build flags were also updated to include the COCOS_MESSAGE_BROKER_TYPE value as a tag for the Go build process.

This commit addresses the issue with the Docker profile assignment and ensures that the correct build flags are used during the build process.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix makefile

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix notification topic in agent service and update NATS ports in Docker environment variables

The agent service's notification topic was incorrectly set to "channels.manager" instead of "agent". This commit fixes the issue by updating the notification topic.

Additionally, the NATS ports in the Docker environment variables were incorrect. The COCOS_NATS_PORT and COCOS_NATS_HTTP_PORT have been updated to the correct values.

These changes ensure that the agent service uses the correct notification topic and the NATS ports are properly configured.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* add pubsub

Signed-off-by: SammyOina <sammyoina@gmail.com>

* update protoc

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2023-11-10 16:12:20 +01:00
Sammy Kerata Oina 4958f9468f NOISSUE - Implement State-machine (#16)
* add state machine

Signed-off-by: SammyOina <sammyoina@gmail.com>

* This commit addresses the following changes:

- In agent/service.go:
  - Added a goroutine to start the StateMachine
  - Sent the start event to the StateMachine

- In agent/state.go:
  - Added a copyright notice and license identifier

These changes ensure that the StateMachine starts correctly and that the agent/state.go file includes the necessary copyright and license information.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix race condition in agent service initialization

The commit fixes a race condition in the agent service initialization.
Previously, the `New` function in `agent/service.go` would start the state machine
goroutine before initializing the `sm` field. This could lead to a race condition
where the state machine would access uninitialized fields.

To fix this, the `New` function now takes a `context.Context` argument and passes it
to the `Start` method of the state machine. Additionally, a `sync.Mutex` has been
added to the `StateMachine` struct to ensure thread safety.

This commit addresses the race condition and ensures proper initialization of the agent service.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix sending events when algorithms and datasets are received

This commit fixes a bug where events were not being sent when algorithms and datasets were received in the agent service. The bug was causing the events to not be triggered, leading to incorrect behavior. This commit adds the necessary code to send the events when algorithms and datasets are received, ensuring that the events are properly triggered.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix bug: computation results not ready

The computation results were not being marked as ready,
resulting in an error when trying to access them.
This commit fixes the issue by adding a check for
the computation results before returning them.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix bug in agent service and state

The commit fixes a bug in the agent service and state files.
Previously, the condition to check the state in the agent service
was incorrect. It was checking the state directly instead of
using the GetState() method. This has been fixed by using the
GetState() method to check the state.

Additionally, a new GetState() method has been added to the
StateMachine struct in the state file. This method retrieves
the current state by acquiring a lock and returning the state
value.

The changes have been tested and verified to resolve the bug
and improve the accuracy of state checking in the agent service.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* check for time outs

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix bug in agent state machine

The bug in the agent state machine caused an error when attempting an invalid transition. This commit fixes the bug by properly locking and unlocking the state machine before and after transitioning to the next state. Additionally, the logger now correctly logs the current and next state during a valid transition.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix race condition in state machine

The commit fixes a race condition in the state machine implementation in the `Start` method. The race condition occurs when multiple goroutines try to access and modify the state concurrently. To fix this, a mutex lock and unlock are added around the critical sections of code to ensure exclusive access to the state variable. This prevents race conditions and ensures the state transitions are executed correctly.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix race condition in StateMachine.Start()

The StateMachine.Start() method was experiencing a race condition
when multiple events were being processed concurrently. This was
caused by not properly locking and unlocking the state machine
before and after updating the state. This commit fixes the issue
by adding proper locking and unlocking around the state update
operation. Additionally, the logging statement has been updated
to include the previous and next states for better debugging.

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2023-11-10 14:41:05 +01:00
Washington Kigani Kamadi 4eea9c1a4c Add attestation endpoint (#5)
* vendor

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* Return agent changes

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* remove vendor

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* Add context to sdk functions

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* Fix comment

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* Add context to functions

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* Remove context variable

Signed-off-by: WashingtonKK
<washingtonkigan@gmail.com>

---------

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
2023-11-10 14:05:17 +01:00
Sammy Kerata Oina 8c7d4a76ec NOISSUE - Remove HTTP server from agent and update agent service (#15)
* Update agent.pb.go to include a new field "Provider" in the AlgoRequest struct.

Signed-off-by: SammyOina <sammyoina@gmail.com>

* fix build

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix undeclared consumer error in agent service

The commit fixes an error in the agent service where an undeclared consumer was requesting results in the computation manifest. The error is resolved by adding an error message for the undeclared consumer case.

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
2023-11-10 13:52:25 +01:00
Sammy Kerata Oina da590bfb63 NOISSUE - Add linters and config file (#12)
* vendor

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* remove vendor

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

---------

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
Co-authored-by: WashingtonKK <washingtonkigan@gmail.com>
2023-11-10 13:49:05 +01:00
Sammy Kerata Oina 70785b96e6 return hashes on agent service. (#14)
Co-authored-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-11-01 13:23:01 +01:00
Sammy Kerata Oina f1f8f95653 NOISSUE - Fix dependencies (#13)
* vendor

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* Return agent changes

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* Add missing import

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* remove vendor

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* Fix formatting

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* Formatting errors

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* Update agent/api/grpc/client.go

Signed off: WashingtonKK

washingtonkigan@gmail.com

Co-authored-by: Sammy Kerata Oina <44265300+SammyOina@users.noreply.github.com>

* add linters and fix

Signed-off-by: SammyOina <sammyoina@gmail.com>

* update ci

Signed-off-by: SammyOina <sammyoina@gmail.com>

* remove deprecated dependencies and
 use local agent and manager

Signed-off-by: SammyOina <sammyoina@gmail.com>

* update mainflux

Signed-off-by: SammyOina <sammyoina@gmail.com>

* Fix Jaeger URL in agent and manager main.go files

The Jaeger URL in the agent and manager main.go files was incorrect. This commit fixes the Jaeger URL by updating it to "http://localhost::4318/v1/traces".

Signed-off-by: SammyOina <sammyoina@gmail.com>

---------

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
Signed-off-by: SammyOina <sammyoina@gmail.com>
Co-authored-by: WashingtonKK <washingtonkigan@gmail.com>
2023-10-27 22:12:53 +02:00
Washington Kigani Kamadi 7d47ed7a20 Fix CI (#6)
* Fix CI

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* Fix CI

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

* Use single make

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>

---------

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
2023-10-20 17:25:14 +02:00
Drasko Draskovic 79d1834173 Fix compilation
Signed-off-by: Drasko Draskovic <drasko.draskovic@gmail.com>
2023-10-19 18:23:53 +02:00
Drasko Draskovic a63cafc4d0 Fix non-vendor compilation
Signed-off-by: Drasko Draskovic <drasko.draskovic@gmail.com>
2023-10-19 17:58:23 +02:00
Drasko Draskovic 63d8035e46 Fix dir structure
Signed-off-by: Drasko Draskovic <drasko.draskovic@gmail.com>
2023-10-19 17:34:38 +02:00
Drasko Draskovic 96e3c48fcb Remove vendoring
Signed-off-by: Drasko Draskovic <drasko.draskovic@gmail.com>
2023-10-19 17:31:55 +02:00
Drasko DRASKOVIC 91c9274885 Merge pull request #2 from SammyOina/CA-1
CA-1 - Fix build
2023-10-19 15:31:00 +02:00
SammyOina f9a2fd0b96 Fix Makefile version and commit variables
The Makefile was updated to fix the version and commit variables.
Previously, the VERSION variable was using "git describe" to get the latest tag,
but it was failing when there were no tags available.
The updated VERSION variable now uses "git describe --always" to fallback to the commit hash if no tags are available.
The COMMIT variable was also updated to use "git rev-parse HEAD" to get the commit hash.

Summary:
Fix Makefile version and commit variables

Body:
- Update VERSION variable to use "git describe --always" to fallback to commit hash
- Update COMMIT variable to use "git rev-parse HEAD" to get commit hash

Signed-off-by: SammyOina <sammyoina@gmail.com>
2023-10-19 12:58:20 +03:00
SammyOina 7cb04499e8 Update Go version to 1.21.x in GitHub Actions workflow
The Go version in the GitHub Actions workflow was updated from 1.20.x to 1.21.x. This change ensures that the correct version of Go is used during the workflow execution.

Signed-off-by: SammyOina <sammyoina@gmail.com>
2023-10-19 12:30:00 +03:00
SammyOina 7657f8bd7a fix build
Signed-off-by: SammyOina <sammyoina@gmail.com>
2023-10-19 12:22:52 +03:00
Drasko Draskovic dd08b7d0b1 Fix vendoring
Signed-off-by: Drasko Draskovic <drasko.draskovic@gmail.com>
2023-10-18 21:35:35 +02:00
Drasko Draskovic e9d143a7d3 Merge remote-tracking branch 'manager/main'
Signed-off-by: Drasko Draskovic <drasko.draskovic@gmail.com>
2023-10-18 12:59:28 +02:00
Drasko Draskovic f690c286f2 Merge remote-tracking branch 'agent/main'
Signed-off-by: Drasko Draskovic <drasko.draskovic@gmail.com>
2023-10-18 12:50:08 +02:00
Drasko DRASKOVIC 194fd29d60 Initial commit 2023-10-18 12:05:53 +02:00
Darko Draskovic 740a631287 Merge pull request #45 from ultravioletrs/qemuExponentialBackoff
Qemu VM exponential backoff
2023-10-09 17:21:16 +02:00
WashingtonKK 514cc18bf8 Remove debug logs
Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
2023-10-09 17:46:13 +03:00
WashingtonKK d96b3414c5 Add backoff
Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
2023-10-09 17:00:40 +03:00
WashingtonKK c8d1ad4793 vendor docs
Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
2023-10-09 17:00:19 +03:00
WashingtonKK 7302e82173 Fix variables
Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
2023-10-09 15:56:25 +03:00
WashingtonKK 2d6487790b Reduce time delay
Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
2023-10-09 14:59:20 +03:00
WashingtonKK 0ae70d9d75 Add retry loop
Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
2023-10-09 14:43:42 +03:00
Darko Draskovic 2e0f3e9240 Merge pull request #38 from ultravioletrs/remove_domain_endpoint
Remove create libvirt domain and create QEMU VM endpoints
2023-09-21 15:52:56 +02:00
Darko Draskovic 4f05805600 Add instructions for AMD-SEV tests (#46)
* Use .venv for AMD-SEV tests

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add instructions for VM

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

---------

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-21 15:38:56 +02:00
Drasko DRASKOVIC 5171882634 Merge pull request #45 from ultravioletrs/algo_data
Add basic business logic of training a model on a dataset
2023-09-21 11:43:29 +02:00
Darko Draskovic b0b22aeed3 Add manual test procedure for CLI
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-21 10:47:31 +02:00
Darko Draskovic 16cb51563c Unexport AgentSDK by renaming to agentSDK
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-21 10:22:57 +02:00
Darko Draskovic b78b15efb6 Fix algorithms cobra command to send file and not string
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-21 10:20:33 +02:00
Darko Draskovic 10f9ec8517 Rename results.go to result.go
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-19 15:37:58 +02:00
Darko Draskovic 7cb1916e7a Move unix socket handling to separate pkg and update api yaml doc
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-19 13:58:02 +02:00
Darko Draskovic 0ab28aa3cc Replace stdout pipe with unix socket
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-19 00:35:23 +02:00
Darko Draskovic 54e03f3373 Refactor /result to perform actual computation
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-18 18:09:19 +02:00
Darko Draskovic 91dd8dd7b4 Add py script std out capture by in memory io.Writer
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-18 17:00:31 +02:00
Darko Draskovic e9f4d0c8d4 Add run func to apply python script (algo) to csv data (dataset)
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-18 15:52:51 +02:00
Darko Draskovic 4d09a9f4c3 Add basic business logic of training a model on a dataset and returning a model
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-18 15:08:27 +02:00
Darko Draskovic 115ccc9f7b Remove print to console statements
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-07 16:53:43 +02:00
Darko Draskovic 70840e2a62 Update proto files
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-07 15:03:43 +02:00
Darko Draskovic 83270dc9bc Move libvirt connect func to libvirt package
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-07 14:57:16 +02:00
Darko Draskovic 4354f0574c Add separate libvirt package and move qemu related functions to qemu package
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-07 14:57:16 +02:00
Darko Draskovic db991b529c Remove custom settings from go vendor system
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-07 14:57:16 +02:00
Darko Draskovic ec865c8d68 Add instructions for focal server preparation
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-07 14:57:16 +02:00
Darko Draskovic da7705de61 Refactor README to use blob for computation run req
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-07 14:57:16 +02:00
Darko Draskovic de9feccc51 Refactor run service func to create vm
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-07 14:57:16 +02:00
Darko Draskovic 0049ce2b28 Add temporary sh script to start vm used for testing
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-07 14:57:16 +02:00
Darko Draskovic c4cc8b48bf Remove create libvirt domain and create QEMU VM endpoints
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-07 14:57:16 +02:00
Darko Draskovic eb230b5aa6 Merge pull request #40 from ultravioletrs/checkproto
Bump proto version in github actions
2023-09-07 14:56:47 +02:00
Darko Draskovic e54d2731cd Bump proto version in github actions
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-07 14:15:45 +02:00
Drasko DRASKOVIC a3c4664497 Merge pull request #43 from ultravioletrs/focal
Refactor README to simplify VM setup procedure
2023-09-05 16:51:47 +02:00
Darko Draskovic 38558dbe53 Remove obsolete agent in VM configuration info
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-09-05 16:32:37 +02:00
Darko Draskovic d70d9fe7e7 Remove alpine and packer related files
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-18 17:14:08 +02:00
Darko Draskovic c3443c5375 Refactor README to simplify VM setup procedure
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-18 13:14:39 +02:00
Drasko DRASKOVIC 2cf6e1ac3e Merge pull request #10 from ultravioletrs/manger_SEV
Refactor manager to start AMD SEV encrypted VM
2023-08-16 15:21:48 +02:00
Darko Draskovic 5028946731 Replace literal strings by consts and properly format godoc comments
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-16 11:08:38 +02:00
Darko Draskovic b3ad784ee0 Add file.go and temporary file creation to enable multi instance VM launch
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-15 21:47:23 +02:00
Darko Draskovic 0b38e94787 Add uuid to VM creation config id fields
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-15 20:28:04 +02:00
Darko Draskovic 1536c6cbf5 Revert to env var VM parametrization
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-15 16:03:26 +02:00
Darko Draskovic 6b4a7080e7 Add CreateQemuVM endoint
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-15 15:32:42 +02:00
Darko Draskovic 4137ad3513 Amend VM launch troubleshooting instructions with port forwaring settings
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-15 11:53:55 +02:00
Darko Draskovic 5558a4f72b Add ExecutableAndArgs generator func to qemu and qemuCmd struct to service
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-14 22:32:36 +02:00
Darko Draskovic 08f26af910 Add VM launch troubleshooting instructions
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-14 20:45:26 +02:00
Darko Draskovic 88e05aea0b Refactor README to use focal-server-cloudimg-amd64.img
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-14 16:22:56 +02:00
Darko Draskovic ce6131e5fd Add programmatic qemu bin abs path config
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-13 01:47:32 +02:00
Darko Draskovic 475004cc84 Add use sudo option to qemu command ctor
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-13 01:03:51 +02:00
Darko Draskovic 51e69d8ab4 Replace sh script for ctor of qemu cmd line with go code
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-12 23:14:36 +02:00
Darko Draskovic d7aca933bd Move cmd funcs to internal/cmd.go
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-10 16:49:26 +02:00
Darko Draskovic 7e21a17317 Remove tmp file creation and capture stdout with buffer
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-10 10:57:34 +02:00
Darko Draskovic 1012d2cb0e Add sudo env var
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-09 16:05:40 +02:00
Darko Draskovic 3caaf6a631 Add a tmp file to read qemu cmd line constr output
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-09 15:57:37 +02:00
Darko Draskovic 9c545d3c7c Replace cmd.Output() with cmd.Start()
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-08 18:10:47 +02:00
Darko Draskovic fd68c9712b Merge pull request #36 from ultravioletrs/CLIReadme
Write Readme.md for Agent CLI
2023-08-08 17:13:19 +02:00
fbugarski dab603fb5f Makefile clean, and Readme installation part fix.
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-08-08 16:50:25 +02:00
Darko Draskovic ff47905247 Remove sudo necessity
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-08 14:29:14 +02:00
fbugarski 44f742fdb0 Add missing parts to Readme
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-08-07 18:39:42 +02:00
Darko Draskovic 6294117de8 Add ConstructQemuCommand and fix guestgrpc bug in sh
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-07 18:37:44 +02:00
Darko Draskovic ada7cb96b7 Parse env vars for qemu cmd line config
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-07 17:46:46 +02:00
Darko Draskovic f6d5b616d2 Add uefi bios vars, exec cmd line and log to file parameters
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-08-07 17:21:14 +02:00
fbugarski a29737b296 Add instalation to Readme
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-08-07 16:53:27 +02:00
fbugarski 5762136b0a fix remarks
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-08-07 15:57:25 +02:00
fbugarski 95a6957f4e Organize help output
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-08-04 16:33:05 +02:00
fbugarski 38cdf9405b remove extra code from makefile
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-08-04 13:39:59 +02:00
fbugarski 1a1785e1c7 Write Readme.md for Agent CLI
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-08-04 13:19:44 +02:00
Darko Draskovic b92806c3b5 Refactor dom.xml to start focal-server-cloudimg-amd64.qcow2
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-07-31 17:32:59 +02:00
Darko Draskovic b92c698800 Add host-guest http and grpc port parametrization
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-07-31 12:23:49 +02:00
Darko Draskovic eaef7ddf9a Add proper formatting
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-07-31 12:23:49 +02:00
Darko Draskovic 10e2a6d0da Refactor manager to start AMD SEV encrypted VM
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-07-31 12:23:49 +02:00
Drasko DRASKOVIC 6aff8ab0bd Merge pull request #26 from ultravioletrs/NOISSUE-update
NOISSUE - Change Default Port For GRPC Client To 7001
2023-07-28 15:49:11 +02:00
rodneyosodo 4dac375b87 Change Default Port For Client To 7001 as in main
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-27 13:51:25 +03:00
Darko Draskovic 376f204f54 Merge pull request #25 from ultravioletrs/NOISSUE-update
NOISSUE - Update Version of Agent
2023-07-27 12:40:59 +02:00
rodneyosodo 2847a28a0f Update Version of Agent
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-27 13:35:16 +03:00
Darko Draskovic c2240066f9 Merge pull request #33 from ultravioletrs/NOISSUE-cleanup
NOISSUE - Update ldflags
2023-07-27 12:29:42 +02:00
Darko Draskovic f561f6c4c9 Merge pull request #34 from ultravioletrs/NOISSUE-update
NOISSUE - Upgrade Go and Dependencies
2023-07-27 12:29:07 +02:00
Darko Draskovic a7ce9b1d87 Merge pull request #23 from ultravioletrs/NOISSUE-cleanup
DRAFT - Update ProtoC workflow
2023-07-27 12:28:12 +02:00
Darko Draskovic c9a7695b64 Merge pull request #24 from ultravioletrs/NOISSUE-update
DRAFT - Upgrade Go and Dependencies
2023-07-27 12:27:21 +02:00
rodneyosodo 15d97f64cb Upgrade Go and Dependencies
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-27 12:23:45 +03:00
rodneyosodo b82b2c6269 Upgrade Go and Dependencies
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-27 12:20:28 +03:00
rodneyosodo f73c829d27 Update ProtoC workflow
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-27 12:10:59 +03:00
rodneyosodo 20962362b6 Update ldflags
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-27 12:06:34 +03:00
Darko Draskovic ac4d20e07e Merge pull request #22 from ultravioletrs/NOISSUE-rmmfxkit
NOISSUE - Remove MFXKIT Dep
2023-07-27 11:02:18 +02:00
Darko Draskovic bd884cbcc4 Merge pull request #32 from ultravioletrs/NOISSUE-rmmfxkit
NOISSUE - Remove Docker Composition
2023-07-27 11:00:07 +02:00
rodneyosodo f5f645db0a Remove MFXKIT Dep
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-27 11:59:59 +03:00
rodneyosodo d802f65450 Remove Env File
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-27 11:29:44 +03:00
rodneyosodo f6f7152015 Remove Docker Composition
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-27 11:20:15 +03:00
Darko Draskovic 9747a0b18d Merge pull request #31 from ultravioletrs/NOISSUE-rmmfxkit
NOISSUE - Remove MFXKIT Dep
2023-07-26 17:04:55 +02:00
rodneyosodo 0bf5985f5b Rename Package Name
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-26 18:03:24 +03:00
rodneyosodo d1b40f9a06 Remove MFXKIT Dep
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-26 18:01:14 +03:00
Darko Draskovic 972e15376f Merge pull request #30 from ultravioletrs/NOISSUE-cleanup
NOISSUE - Update Protocol Buffer workflow
2023-07-26 16:59:25 +02:00
rodneyosodo d2fff75874 Update ProtoC workflow
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-26 15:34:29 +03:00
Darko Draskovic 5c3413ff74 Merge pull request #21 from ultravioletrs/NOISSUE-servicelayertracing
NOISSUE - Add Service Layer Tracing
2023-07-26 13:17:46 +02:00
rodneyosodo 897e58faec Update MANAGER_JAEGER_URL
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-26 14:06:41 +03:00
rodneyosodo f5d3b7c15b Move From OpenTracing To OpenTelemetry
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-25 18:56:53 +03:00
Darko Draskovic 0d3630a31b Merge pull request #29 from ultravioletrs/NOISSUE-servicelayertracing
NOISSUE - Add Service Layer Tracing
2023-07-25 17:44:25 +02:00
rodneyosodo 8ea5dda282 Propagate context
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-25 18:38:16 +03:00
rodneyosodo c88d77ac6f Add context to agent functions
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-25 17:16:51 +03:00
rodneyosodo e46a2f137b Move From OpenTracing To OpenTelemetry
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-25 17:03:29 +03:00
rodneyosodo 60070be4d5 Add Service Layer Tracing
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-25 16:24:27 +03:00
rodneyosodo fb596ab1ee Add Service Layer Tracing
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-25 16:07:18 +03:00
Darko Draskovic f0e7c183e0 Merge pull request #20 from ultravioletrs/NOISSUE-agentclient
NOISSUE - Connect To Agent
2023-07-25 14:58:08 +02:00
rodneyosodo f379123aa7 Remove Empty Line
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-25 15:51:48 +03:00
rodneyosodo 54072fc052 Connect To Agent
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-25 15:42:17 +03:00
Darko Draskovic 2175ae3f1a Merge pull request #19 from ultravioletrs/NOISSUE-grpcclient
NOISSUE - Add GRPC Client
2023-07-25 14:33:24 +02:00
Darko Draskovic a903ca23cd Merge pull request #27 from ultravioletrs/NOISSUE-grpcclient
NOISSUE - Add GRPC Client
2023-07-25 13:55:43 +02:00
rodneyosodo d5ac5fd3a9 Add GRPC Client
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-25 14:39:48 +03:00
rodneyosodo 7fec10fb56 Remove IsSecure
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-25 14:38:50 +03:00
rodneyosodo b6809fa5b2 Rename newClient
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-25 14:32:15 +03:00
rodneyosodo 9e2af2c525 Rename agentGRPCConfig
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-25 13:58:52 +03:00
rodneyosodo 9c74a0e7db Add GRPC Client
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-25 13:08:24 +03:00
Darko Draskovic 7c9a5315a7 Merge pull request #18 from ultravioletrs/NOISSUE-updateserver
NOISSUE - Move HTTP and GRPC Server Implementations To Internal
2023-07-25 10:45:43 +02:00
Darko Draskovic 5bce3a8839 Merge pull request #25 from ultravioletrs/NOISSUE-updateserver
NOISSUE - Move HTTP and GRPC Server Implementations To Internal
2023-07-25 10:36:58 +02:00
rodneyosodo 9484a44eb2 Rename stopAllServers
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-25 10:51:07 +03:00
rodneyosodo 150b7ab81c Move HTTP and GRPC Server Implementations To Internal
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-24 21:32:06 +03:00
rodneyosodo a1b4a21cb6 Reformat stopAllServer
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-24 19:42:11 +03:00
rodneyosodo b82c62d9b4 Add Inline Err Check
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-24 19:21:05 +03:00
rodneyosodo 94a22d2282 Use Channel of Size 1
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-24 19:06:49 +03:00
rodneyosodo 7ac8372720 Rename StopHandler
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-24 18:57:44 +03:00
rodneyosodo 76b2bed007 Fix Remarks
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-24 15:52:00 +03:00
rodneyosodo 885f4c9be1 Move HTTP and GRPC Server Implementations To Internal
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-24 14:57:05 +03:00
Darko Draskovic 03d637b5bf Merge pull request #17 from ultravioletrs/NOISSUE-updateMF
NOISSUE - Update Mainflux Dependency
2023-07-24 11:41:26 +02:00
Darko Draskovic 0f15d8c731 Merge pull request #16 from ultravioletrs/NOISSUE-metric
NOISSUE - Add Metric To Internal Package
2023-07-24 11:40:51 +02:00
rodneyosodo 0d9aa5d88e Update Mainflux Module
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-24 12:29:45 +03:00
rodneyosodo 300cabbaca Add Metric To Internal Package
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-24 12:25:19 +03:00
Darko Draskovic bb88a71eef Merge pull request #24 from ultravioletrs/NOISSUE-updateMF
NOISSUE - Update Mainflux Dependency
2023-07-24 11:22:10 +02:00
rodneyosodo 8505deedc6 Update Mainflux Module
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-24 12:16:30 +03:00
Darko Draskovic 6cecedd1a1 Merge pull request #23 from ultravioletrs/NOISSUE-metric
NOISSUE - Add Metric To Internal Package
2023-07-24 11:15:11 +02:00
rodneyosodo c09383ac72 Add Metric To Internal Package
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-24 12:00:28 +03:00
Darko Draskovic 8c87ef947b Merge pull request #15 from ultravioletrs/NOISSUE-env
NOISSUE - Change How To Load Env Variables
2023-07-21 18:25:17 +02:00
Darko Draskovic 3a57c8d7a4 Merge pull request #22 from ultravioletrs/NOISSUE-env
NOISSUE - Change How To Load Env Variables
2023-07-21 18:24:46 +02:00
rodneyosodo 1829afd123 Change How To Load Env Variables
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-21 19:20:35 +03:00
rodneyosodo 2c354c3977 Remove MFXKIT Env Vars
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-21 19:18:26 +03:00
rodneyosodo d59b9293cb Initialixe Epty Vars More Idomatic
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-21 19:02:54 +03:00
rodneyosodo b5e64528b1 Make config items Public
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-21 18:55:30 +03:00
rodneyosodo f18e82efa7 Change How To Load Env Variables
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-21 18:20:40 +03:00
Drasko DRASKOVIC 5b60f079b5 Merge pull request #12 from ultravioletrs/docs
Amend README with default domain creation instructions
2023-07-19 13:35:50 +02:00
Darko Draskovic 52e681c28d Amend README with default domain creation instructions
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-07-19 10:43:25 +02:00
Darko Draskovic a3619098dc Merge pull request #19 from ultravioletrs/CLISDK
Connect CLI and SDK
2023-07-17 17:45:14 +02:00
fbugarski bd61a3bd9f Remove println
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-17 16:59:30 +02:00
fbugarski f4ff0feb3c fix err check
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-17 16:39:01 +02:00
fbugarski cc078a1910 Add err check
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-17 16:32:22 +02:00
fbugarski 8f0fd5a1fa Add run, and fix response ,and loglevel
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-17 16:23:22 +02:00
fbugarski 311dc7e1a7 Fix load config
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-17 12:53:46 +02:00
fbugarski cfb0918c95 Remove unused
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-17 12:36:42 +02:00
fbugarski 74c9c306e6 Fix logger error and parse duration
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-17 12:28:15 +02:00
fbugarski 31b1f397d6 Move cfg to main
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-14 18:09:48 +02:00
fbugarski 30d6f97976 Remove unused
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-14 14:16:32 +02:00
fbugarski 5b1403edfc Agent timeout
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-14 13:49:27 +02:00
fbugarski 2ec9df770c Fix grpc connection
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-14 11:21:35 +02:00
Darko Draskovic 62455e35b2 Merge pull request #9 from ultravioletrs/NOISSUE-ci
NOISSUE - Add CI
2023-07-13 09:40:25 +02:00
rodneyosodo 074186dd55 Add Error Check
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-12 19:06:44 +03:00
fbugarski 9a33eb828c Connect CLI and SDK
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-12 14:33:47 +02:00
Darko Draskovic 5938760f8f Merge pull request #16 from ultravioletrs/NOISSUE-gotidy
NOISSUE - Add CI
2023-07-12 14:21:41 +02:00
rodneyosodo 2c54aa78d3 Update Build Command
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-12 13:34:56 +03:00
rodneyosodo d32fd050f7 Initial Commit: Add CI
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-10 15:12:00 +03:00
rodneyosodo f4e71e74b2 Initial Commit: Add CI
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-07-10 15:06:45 +03:00
Dušan Borovčanin 45a92ec842 Merge pull request #18 from ultravioletrs/agentsdk
Agent service SDK
2023-07-07 12:53:20 +02:00
fbugarski 87ea08b08a Add comments and fix url's
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-07 12:43:34 +02:00
fbugarski 0b4fbd5efe Implement SDK funcs
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-07 10:49:17 +02:00
fbugarski f3cc5848ef DRAFT - Agent service SDK
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-07-07 06:24:43 +02:00
Darko Draskovic 71b5617ab3 Add wait time for Linux VM boot
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-26 17:49:30 +02:00
Drasko DRASKOVIC a917c4ba0c Merge pull request #13 from ultravioletrs/cli_openapi
Add open api spec for Agent CLI
2023-06-26 16:05:47 +02:00
fbugarski 93b47a5897 Add initial structs for CLI commands
Signed-off-by: fbugarski <filipbugarski@gmail.com>
2023-06-26 11:53:02 +02:00
Drasko DRASKOVIC 6bd89b08fd Merge pull request #15 from ultravioletrs/c_onciseness
Change client to c for consistency and conciseness
2023-06-22 19:46:38 +02:00
Darko Draskovic 6b7a81799c Change client to c for consistency and conciseness
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-22 19:41:16 +02:00
Darko Draskovic 05ce62c158 Merge pull request #14 from ultravioletrs/grpc_algo_data_result
Add grpc server stub for algo, data and result
2023-06-22 19:37:55 +02:00
Darko Draskovic b5c38308f4 Add Result grpc endpoint and service stub
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-22 14:51:05 +02:00
Darko Draskovic 1c140ba4ee Fix grpc client encode run func to start with user domain req
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-22 11:11:35 +02:00
Darko Draskovic 5277f44e41 Add Algo and Data grpc client funcs
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-21 15:34:26 +02:00
Darko Draskovic 4036dd3c85 Add grpc server stub for algo, data and result
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-21 13:52:45 +02:00
Drasko DRASKOVIC 62234dc7b1 Merge pull request #12 from ultravioletrs/cocosagent.service
Add systemd cocos agent init script
2023-06-20 15:33:40 +02:00
Darko Draskovic ce4726081a Rename cocosagent.service to cocos-agent.service
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-20 15:31:23 +02:00
Darko Draskovic 5296340326 Use /run/cocos for agent.pid file and create /var/log/cocos via systemd script
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-20 15:29:07 +02:00
Darko Draskovic d4e3811640 Use different stderr and stdout agent log files
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-20 15:03:52 +02:00
Darko Draskovic c8d2e96437 Fix Alpine script and README to use /cocos/agent name and location
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-20 12:48:44 +02:00
Darko Draskovic 53370ba0f6 Add /var/log/agent and /cocos dirs to systemd script
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-19 17:02:59 +02:00
Darko Draskovic 5a03d2ae4a Remove /status endpoint
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-19 16:32:46 +02:00
Darko Draskovic 5496af3af2 Remove redundant setup-cocosagent.sh script
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-19 16:07:45 +02:00
Darko Draskovic 01a9f27deb Remove /computation manifest and add /result endpoint
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-19 14:34:29 +02:00
Darko Draskovic d212c77e22 Replace algorithm/dataset endpoint with algorithms/datasets/endpoint
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-19 14:16:20 +02:00
Darko Draskovic 4be83a9888 Add open api spec for Agent CLI
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-19 12:50:33 +02:00
Darko Draskovic 1e9fa759dd Add log files and setup script
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-19 12:15:21 +02:00
Darko Draskovic 066c8ecfe9 Add systemd cococ agent init script
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-15 10:48:43 +02:00
Darko Draskovic f2c58adef6 Add instructions for checking if ports on guest are open
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-14 16:19:19 +02:00
Darko Draskovic 72b56ee40a Merge pull request #8 from ultravioletrs/update-gomod
NOISSUE - Update Version For Agent to Match Latest
2023-06-14 10:26:56 +02:00
rodneyosodo b7c6eadf4f Update Version For Agent to Match Latest
Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
2023-06-14 10:24:46 +03:00
Darko Draskovic e05aca0b74 Add instructions related to VM management
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-13 20:41:59 +02:00
Darko Draskovic 49feeb96ee Add instructions for checking if ports on guest are open
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-12 15:54:17 +02:00
Darko Draskovic 5030a20af6 Remove redundant agent dir
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-06-12 15:18:18 +02:00
Darko Draskovic 7b18467800 Remove redundant manager dir
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-05-30 14:17:34 +02:00
Darko Draskovic a6d0734212 Refactor run request to use slice of bytes to represent computation
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-05-30 11:27:43 +02:00
Darko Draskovic d3acfd1718 Add agent gRPC client
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-05-30 11:26:45 +02:00
Darko Draskovic a150433982 Add instructions related to VM management
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-05-26 12:54:44 +02:00
Darko Draskovic cea3e059fe Add packer json for alpine qcow2 creation
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-05-23 14:11:55 +02:00
Darko Draskovic 5e2ee315f6 Add instructions related to VM management
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-05-19 14:34:55 +02:00
Darko Draskovic 79ce0e34f9 Add instructions for interaction with cocos computations microservice
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-05-19 14:34:07 +02:00
Darko Draskovic 90cea0d143 Add copy files and run computation instructions
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-05-18 18:42:51 +02:00
Darko Draskovic 2e8603208b Add fun to replace rel with abs paths in xml files
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-05-18 15:31:00 +02:00
Darko Draskovic 4191560130 Fix wrong xml filepath creation
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-05-17 15:14:17 +02:00
Darko Draskovic e9e9b8d15c Fix VM creation error when snapshot does not exist
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-05-17 14:43:37 +02:00
Darko Draskovic f02a500c2d Fix agent rc script to use grpc addr visible from host
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-05-17 14:03:53 +02:00
Darko Draskovic c1f9fa6328 Add agent grpc svc and client and Run endpoint
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-05-15 16:24:58 +02:00
Darko Draskovic 750bed0d76 Add run svc endpoint
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-05-12 12:52:00 +02:00
Darko Draskovic 306fa302dc Add OpenRC agent script
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-04-18 16:14:23 +02:00
Darko Draskovic 780c620b30 Add Makefile targets for build and copy to VM agent
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-04-18 10:12:30 +02:00
Darko Draskovic 7383186143 Add libvirt funcs to revert to snapshot
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-04-11 14:43:11 +02:00
Darko Draskovic 023d28ea22 Fix vol and dom config to use qcow2 format to enable snapshots
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-04-10 18:17:59 +02:00
Darko Draskovic 16fb3710ac Add Run client endpoint
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-04-10 17:28:10 +02:00
Darko Draskovic fe7c3d9014 Add Run gRPC endpoint
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-03-31 17:17:02 +02:00
Darko Draskovic eb4a0943f6 Add Run endpoint
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-03-31 16:55:32 +02:00
Darko Draskovic b400210738 Add gRPC server start routine
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-03-29 15:27:22 +02:00
Darko Draskovic 7c12be6a24 Add grpc client skeleton
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-03-29 11:02:04 +02:00
Darko Draskovic 6f014156b3 Add grpc server skeleton
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-03-28 17:17:12 +02:00
Darko Draskovic 122b214299 Remove ping endpoint and svc func
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-03-28 15:07:15 +02:00
Darko Draskovic 8831a4f957 Add create qemu domain endpoint
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-03-28 14:10:01 +02:00
Darko Draskovic e25abcf5e0 Replace 'cocosvm' with 'manager'
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-03-27 17:01:03 +02:00
Darko Draskovic ad60e95736 Rename mfxkit to agent
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-03-27 16:37:52 +02:00
Darko Draskovic 6ec53d074f Add CLI skeleton
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-03-27 15:40:14 +02:00
Darko Draskovic 35c62cb273 first commit 2023-03-27 13:56:05 +02:00
Darko Draskovic 4d3bcf99b4 Move xml strings to xml files
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-03-22 14:01:17 +01:00
Darko Draskovic 39c5cc2dd5 Add virtual machine creation
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-03-15 15:38:31 +01:00
Darko Draskovic 278331dc81 Add libvirt
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-03-15 11:50:39 +01:00
Darko Draskovic b7a1fbb2fa Rename mfxkit to cocos
Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2023-03-14 15:47:26 +01:00
Darko Draskovic 22c743c4dd first commit 2023-03-14 15:12:23 +01:00
1410 changed files with 8263 additions and 456973 deletions
+33
View File
@@ -0,0 +1,33 @@
## Jaeger
COCOS_JAEGER_PORT=6831
COCOS_JAEGER_FRONTEND=16686
COCOS_JAEGER_COLLECTOR=14268
COCOS_JAEGER_CONFIGS=5778
COCOS_JAEGER_URL=http://jaeger:14268/api/traces
COCOS_JAEGER_TRACE_RATIO=1.0
## Core Services
### Manager
MANAGER_HTTP_HOST="cocos-manager"
MANAGER_HTTP_PORT=9021
MANAGER_HTTP_SERVER_CERT=""
MANAGER_HTTP_SERVER_KEY=""
MANAGER_GRPC_HOST="cocos-manager"
MANAGER_GRPC_PORT=7003
MANAGER_GRPC_SERVER_CERT=""
MANAGER_GRPC_SERVER_KEY=""
AGENT_GRPC_URL="192.168.100.4:7002"
AGENT_GRPC_TIMEOUT=""
AGENT_GRPC_CA_CERTS=""
AGENT_GRPC_CLIENT_TLS=""
MANAGER_INSTANCE_ID=""
MANAGER_LOG_LEVEL=debug
MANAGER_QEMU_USE_SUDO=false
MANAGER_QEMU_ENABLE_SEV=false
MANAGER_QEMU_SEV_CBITPOS=51
MANAGER_QEMU_OVMF_CODE_FILE=/usr/share/OVMF/OVMF_CODE.fd
MANAGER_QEMU_OVMF_VARS_FILE=/usr/share/OVMF/OVMF_VARS.fd
# Docker image tag
COCOS_RELEASE_TAG=latest
+49
View File
@@ -0,0 +1,49 @@
name: Bug Report
description: File a bug/issue report. Make sure to search to see if an issue already exists for the bug you encountered.
title: "Bug: <title>"
labels: ["bug", "needs-review", "help wanted"]
body:
- type: textarea
attributes:
label: What were you trying to achieve?
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
attributes:
label: What are the expected results?
description: A concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: What are the received results?
description: A concise description of what you received.
validations:
required: true
- type: textarea
attributes:
label: Steps To Reproduce
description: What are the steps to reproduce the issue?
placeholder: |
1. In this environment...
2. With this config...
3. Run '...'
4. See error...
validations:
required: false
- type: textarea
attributes:
label: In what environment did you encounter the issue?
description: A concise description of the environment you encountered the issue in.
validations:
required: true
- type: textarea
attributes:
label: Additional information you deem important
description: |
Links? References? Anything that will give us more context about the issue you are encountering!
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: false
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
@@ -0,0 +1,36 @@
name: Feature Request
description: File a feature request. Make sure to search to see if a request already exists for the feature you are requesting.
title: "Feature: <title>"
labels: ["enchancement", "needs-review"]
body:
- type: textarea
attributes:
label: Is your feature request related to a problem? Please describe.
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
validations:
required: true
- type: textarea
attributes:
label: Describe the feature you are requesting, as well as the possible use case(s) for it.
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: dropdown
attributes:
label: Indicate the importance of this feature to you.
description: This will help us prioritize the feature request.
options:
- Must-have
- Should-have
- Nice-to-have
validations:
required: true
- type: textarea
attributes:
label: Anything else?
description: |
Links? References? Anything that will give us more context about the feature that you are requesting.
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: false
+66
View File
@@ -0,0 +1,66 @@
<!--
Pull request title should be `COCOS-XXX - description` or `NOISSUE - description` where XXX is ID of the issue that this PR relate to.
Please review the [CONTRIBUTING.md](https://github.com/ultravioletrs/cocos/blob/master/CONTRIBUTING.md) file for detailed contributing guidelines.
For Work In Progress Pull Requests, please use the Draft PR feature, see https://github.blog/2019-02-14-introducing-draft-pull-requests/ for further details.
For a timely review/response, please avoid force-pushing additional commits if your PR already received reviews or comments.
- Provide tests for your changes.
- Use descriptive commit messages.
- Comment your code where appropriate.
- Squash your commits
- Update any related documentation.
-->
# What type of PR is this?
<!--This represents the type of PR you are submitting.
For example:
This is a bug fix because it fixes the following issue: #1234
This is a feature because it adds the following functionality: ...
This is a refactor because it changes the following functionality: ...
This is a documentation update because it updates the following documentation: ...
This is a dependency update because it updates the following dependencies: ...
This is an optimization because it improves the following functionality: ...
-->
## What does this do?
<!--
Please provide a brief description of what this PR is intended to do.
Include List any changes that modify/break current functionality.
-->
## Which issue(s) does this PR fix/relate to?
<!--
For pull requests that relate or close an issue, please include them below. We like to follow [Github's guidance on linking issues to pull requests](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).
For example having the text: "Resolves #1234" would connect the current pull request to issue 1234. And when we merge the pull request, Github will automatically close the issue.
-->
- Related Issue #
- Resolves #
## Have you included tests for your changes?
<!--If you have not included tests, please explain why.
For example:
Yes, I have included tests for my changes.
No, I have not included tests because I do not know how to.
-->
## Did you document any new/modified feature?
<!--If you have not included documentation, please explain why.
For example:
Yes, I have updated the documentation for the new feature.
No, I have not updated the documentation because I do not know how to.
-->
### Notes
<!--Please provide any additional information you feel is important.-->
+82
View File
@@ -0,0 +1,82 @@
name: CI
on:
push:
branches:
- main
paths:
- "manager/manager.proto"
- "pkg/manager/*.pb.go"
- "agent/agent.proto"
- "agent/*.pb.go"
pull_request:
branches:
- main
paths:
- "manager/manager.proto"
- "pkg/manager/*.pb.go"
- "agent/agent.proto"
- "agent/*.pb.go"
jobs:
checkproto:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: 1.21.x
- name: Set up protoc
run: |
PROTOC_VERSION=25.1
PROTOC_GEN_VERSION=v1.31.0
PROTOC_GRPC_VERSION=v1.3.0
# Download and install protoc
PROTOC_ZIP=protoc-$PROTOC_VERSION-linux-x86_64.zip
curl -0L -o $PROTOC_ZIP https://github.com/protocolbuffers/protobuf/releases/download/v$PROTOC_VERSION/$PROTOC_ZIP
unzip -o $PROTOC_ZIP -d protoc3
sudo mv protoc3/bin/* /usr/local/bin/
sudo mv protoc3/include/* /usr/local/include/
rm -rf $PROTOC_ZIP protoc3
# Install protoc-gen-go and protoc-gen-go-grpc
go install google.golang.org/protobuf/cmd/protoc-gen-go@$PROTOC_GEN_VERSION
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@$PROTOC_GRPC_VERSION
# Add protoc to the PATH
export PATH=$PATH:/usr/local/bin/protoc
- name: Set up Cocos-AI
run: |
# Rename .pb.go files to .pb.go.tmp to prevent conflicts
for p in $(ls manager/*.pb.go); do
mv $p $p.tmp
done
for p in $(ls agent/*.pb.go); do
mv $p $p.tmp
done
# Generate Go files from protobuf definitions
make protoc
# Compare generated Go files with the original ones
for p in $(ls manager/*.pb.go); do
if ! cmp -s $p $p.tmp; then
echo "Proto file and generated Go file $p are out of sync!"
exit 1
fi
done
for p in $(ls agent/*.pb.go); do
if ! cmp -s $p $p.tmp; then
echo "Proto file and generated Go file $p are out of sync!"
exit 1
fi
done
-39
View File
@@ -1,39 +0,0 @@
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
strategy:
matrix:
go-version: [1.19.x]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@v2
- name: Run go vet
run: go vet ./...
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
args: --no-config --disable-all --enable gosimple --enable govet --enable unused --enable deadcode --timeout 3m
- name: Build
run: go build -v ./...
- name: Run tests
run: go test -mod=vendor -v --race -covermode=atomic -coverprofile cover.out ./...
+73
View File
@@ -0,0 +1,73 @@
name: Build and Release
on:
push:
tags:
- '*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Update Ubuntu
run: |
sudo apt-get update
sudo apt-get upgrade -y
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: 1.21.x
cache-dependency-path: "go.sum"
- name: Checkout cocos
uses: actions/checkout@v4
with:
repository: 'ultravioletrs/cocos'
path: cocos
- name: Checkout buildroot
uses: actions/checkout@v4
with:
repository: 'buildroot/buildroot'
path: buildroot
- name: Build
run: |
cd buildroot
make BR2_EXTERNAL=../cocos/hal/linux cocos_defconfig
make
- name: Create Release
id: create_release
uses: actions/create-release@latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
- name: Upload Release Asset
id: upload-release-kernel
uses: actions/upload-release-asset@latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./buildroot/output/images/bzImage
asset_name: bzImage
asset_content_type: application/octet-stream
- name: Upload Release Asset
id: upload-release-rootfs
uses: actions/upload-release-asset@latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./buildroot/output/images/rootfs.cpio.gz
asset_name: rootfs.cpio.gz
asset_content_type: application/gzip
+34
View File
@@ -0,0 +1,34 @@
name: CI
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
ci:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: 1.21.x
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
- name: Build
run: |
make
- name: Run tests
run: go test -v --race -covermode=atomic -coverprofile cover.out ./...
+7
View File
@@ -1 +1,8 @@
build
build
cmd/manager/img
cmd/manager/iso
cmd/manager/tmp
.cov
+86
View File
@@ -0,0 +1,86 @@
run:
timeout: 3m
issues:
max-issues-per-linter: 10
max-same-issues: 10
linters-settings:
importas:
no-unaliased: true
no-extra-aliases: false
alias:
- pkg: github.com/absmach/magistrala/logger
alias: mglog
gocritic:
enabled-checks:
- captLocal
- dupImport
- singleCaseSwitch
- switchTrue
- importShadow
- httpNoBody
- paramTypeCombine
- emptyStringTest
- builtinShadow
- exposedSyncMutex
disabled-checks:
- appendAssign
enabled-tags:
- diagnostic
disabled-tags:
- performance
- style
- experimental
- opinionated
misspell:
ignore-words:
- "mosquitto"
stylecheck:
checks: ["-ST1000", "-ST1003", "-ST1020", "-ST1021", "-ST1022"]
goheader:
template: |-
Copyright (c) Ultraviolet
SPDX-License-Identifier: Apache-2.0
linters:
disable-all: true
enable:
- importas
- gocritic
- gosimple
- errcheck
- govet
- unused
- goconst
- godot
- godox
- ineffassign
- misspell
- stylecheck
- whitespace
- gci
- gofmt
- goimports
- loggercheck
- goheader
- asasalint
- asciicheck
- bidichk
- contextcheck
- decorder
- dogsled
- errchkjson
- errname
- execinquery
- exportloopref
- ginkgolinter
- gocheckcompilerdirectives
- gofumpt
- goprintffuncname
- importas
- makezero
- mirror
- nakedret
- dupword
@@ -1,11 +1,11 @@
# Contributing to Mainflux
# Contributing to CoCos
The following is a set of guidelines to contribute to Mainflux and its libraries, which are
hosted on the [Mainflux Organization](https://github.com/mainflux) on GitHub.
The following is a set of guidelines to contribute to CoCos and its libraries, which are
hosted on the [Ultraviolet Organization](https://github.com/ultravioletrs) on GitHub.
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0).
By participating, you are expected to uphold this code. Please report unacceptable behavior to
[abuse@mainflux.com](mailto:abuse@mainflux.com).
[abuse@ultraviolet.rs](mailto:abuse@ultraviolet.rs).
## Reporting issues
@@ -13,7 +13,7 @@ Reporting issues are a great way to contribute to the project. We are perpetuall
thorough bug report.
Before raising a new issue, check [our issue
list](https://github.com/mainflux/mainflux/issues) to determine if it already contains the
list](https://github.com/ultravioletrs/cocos/issues) to determine if it already contains the
problem that you are facing.
A good bug report shouldn't leave others needing to chase you for more information. Please be as detailed as possible. The following questions might serve as a template for writing a detailed
@@ -41,23 +41,23 @@ To contribute to the project, [fork](https://help.github.com/articles/fork-a-rep
clone your fork repository, and configure the remotes:
```
git clone https://github.com/<your-username>/mainflux.git
cd mainflux
git remote add upstream https://github.com/mainflux/mainflux.git
git clone https://github.com/<your-username>/cocos.git
cd cocos
git remote add upstream https://github.com/ultravioletrs/cocos.git
```
If your cloned repository is behind the upstream commits, then get the latest changes from upstream:
```
git checkout master
git pull --rebase upstream master
git pull --rebase upstream main
```
Create a new topic branch from `master` using the naming convention `MF-[issue-number]`
Create a new topic branch from `master` using the naming convention `COCOS-[issue-number]`
to help us keep track of your contribution scope:
```
git checkout -b MF-[issue-number]
git checkout -b COCOS-[issue-number]
```
Commit your changes in logical chunks. When you are ready to commit, make sure
@@ -74,13 +74,13 @@ and `user.email` git configs, you can sign your commit automatically with `git c
Locally merge (or rebase) the upstream development branch into your topic branch:
```
git pull --rebase upstream master
git pull --rebase upstream main
```
Push your topic branch up to your fork:
```
git push origin MF-[issue-number]
git push origin COCOS-[issue-number]
```
[Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title
-201
View File
@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+16 -62
View File
@@ -1,81 +1,35 @@
COCOS_DOCKER_IMAGE_NAME_PREFIX ?= cocos
BUILD_DIR = build
SERVICES = computations datasets
DOCKERS = $(addprefix docker_,$(SERVICES))
DOCKERS_DEV = $(addprefix docker_dev_,$(SERVICES))
SERVICES = manager agent cli
CGO_ENABLED ?= 0
GOARCH ?= amd64
VERSION ?= $(shell git describe --abbrev=0 --tags)
VERSION ?= $(shell git describe --abbrev=0 --tags --always)
COMMIT ?= $(shell git rev-parse HEAD)
TIME ?= $(shell date +%F_%T)
CLI_SOURCE = ./cmd/cli/main.go
CLI_BIN = ${BUILD_DIR}/cocos-cli
empty:=
space:= $(empty) $(empty)
define compile_service
CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) \
go build -mod=vendor -ldflags "-s -w \
-X 'github.com/ultravioletrs/cocos/internal/http.BuildTime=$(TIME)' \
-X 'github.com/ultravioletrs/cocos/internal/http.Version=$(VERSION)' \
-X 'github.com/ultravioletrs/cocos/internal/http.Commit=$(COMMIT)'" \
go build -ldflags "-s -w \
-X 'github.com/absmach/magistrala.BuildTime=$(TIME)' \
-X 'github.com/absmach/magistrala.Version=$(VERSION)' \
-X 'github.com/absmach/magistrala.Commit=$(COMMIT)'" \
-o ${BUILD_DIR}/cocos-$(1) cmd/$(1)/main.go
endef
define make_docker
$(eval svc=$(subst docker_,,$(1)))
docker build \
--no-cache \
--build-arg SVC=$(svc) \
--build-arg GOARCH=$(GOARCH) \
--build-arg GOARM=$(GOARM) \
--build-arg VERSION=$(VERSION) \
--build-arg COMMIT=$(COMMIT) \
--build-arg TIME=$(TIME) \
--tag=$(COCOS_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
-f docker/Dockerfile .
endef
define make_docker_dev
$(eval svc=$(subst docker_dev_,,$(1)))
docker build \
--no-cache \
--build-arg SVC=$(svc) \
--tag=$(COCOS_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
-f docker/Dockerfile.dev ./build
endef
.PHONY: all $(SERVICES)
all: $(SERVICES)
.PHONY: all $(SERVICES) dockers dockers_dev latest release
clean:
rm -rf ${BUILD_DIR}
cleandocker:
# Stops containers and removes containers, networks, volumes, and images created by up
docker-compose -f docker/docker-compose.yml down --rmi all -v --remove-orphans
ifdef pv
# Remove unused volumes
docker volume ls -f name=$(MF_DOCKER_IMAGE_NAME_PREFIX) -f dangling=true -q | xargs -r docker volume rm
endif
install:
cp ${BUILD_DIR}/* $(GOBIN)
test:
go test -mod=vendor -v -race -count 1 -tags test $(shell go list ./... | grep -v 'vendor\|cmd')
$(SERVICES):
$(call compile_service,$(@))
$(DOCKERS):
$(call make_docker,$(@),$(GOARCH))
$(DOCKERS_DEV):
$(call make_docker_dev,$(@))
install-cli: cli
cp ${CLI_BIN} ~/.local/bin/cocos-cli
dockers: $(DOCKERS)
dockers_dev: $(DOCKERS_DEV)
run:
docker-compose -f docker/docker-compose.yml up
protoc:
protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative agent/agent.proto
protoc -I. --go_out=./pkg --go_opt=paths=source_relative --go-grpc_out=./pkg --go-grpc_opt=paths=source_relative manager/manager.proto
+3 -32
View File
@@ -12,36 +12,6 @@ Data is always encrypted, protected by hardware secure enclaves (Trusted Executi
attested via secure remote attestation protocols, and invisible to cloud processors or any other
3rd party to which computation is offloaded.
## Install
The following prerequisites are needed to run Cocos:
- [Docker](https://docs.docker.com/install/)
- [Docker compose](https://docs.docker.com/compose/install/)
### Build Docker Images
Currenty, there is no Docker registry, so Cocos images must be built by hand:
```
make dockers
```
For this you might be needing to setup DNS servers in your `/etc/resolf.conf` as explained
[here](https://github.com/docker/cli/issues/2618) (i.e. add Google's `nameserver 8.8.8.8`).
### Run Composition
Once the images are built (`docker images` command should show you `cocos/computations` and `cocos/datasets`),
composition can be run:
```bash
docker-compose -f docker/docker-compose.yml up
```
This will bring up the Cocos docker services and interconnect them. This command can also be executed using the project's included Makefile:
```bash
make run
```
## Usage
The quickest way to start using Cocos is via the CLI. The latest version can be downloaded from the [official releases page][rel].
@@ -53,11 +23,11 @@ make cli
./build/cocos-cli version
```
Additional details on using the CLI can be found in the [CLI documentation](https://docs.mainflux.io/cli).
Additional details on using the CLI can be found in the [CLI documentation](https://docs.cocos.ai/cli).
## Documentation
Official documentation is hosted at [Cocos official docs page][docs]. Documentation is auto-generated, checkout the instructions on [official docs repository](https://github.com/cocos/docs).
Official documentation is hosted at [Cocos official docs page][docs]. Documentation is auto-generated, checkout the instructions on [official docs repository](https://github.com/ultravioletrs/docs).
## License
Cocos AI is a proprietary product created by Ultraviolet company.
@@ -66,3 +36,4 @@ Cocos AI is a proprietary product created by Ultraviolet company.
[cocos]: https://cocos.ai/
[rel]: https://github.com/ultraviolet/cocos/releases
[tee]: https://en.wikipedia.org/wiki/Trusted_execution_environment
+40
View File
@@ -0,0 +1,40 @@
# Agent
Agent service provides a barebones HTTP and gRPC API and Service interface implementation for the development of the agent service.
## Configuration
The service is configured using the environment variables from the following table. Note that any unset variables will be replaced with their default values.
| Variable | Description | Default |
| ----------------------------- | ------------------------------------------------------ | ------------------------------ |
| AGENT_LOG_LEVEL | Log level for agent service (debug, info, warn, error) | info |
| AGENT_GRPC_HOST | Agent service gRPC host | "" |
| AGENT_GRPC_PORT | Agent service gRPC port | 7002 |
| AGENT_GRPC_SERVER_CERT | Path to gRPC server certificate in pem format | "" |
| AGENT_GRPC_SERVER_KEY | Path to gRPC server key in pem format | "" |
| AGENT_GRPC_SERVER_CA_CERTS | Path to gRPC server CA certificate | "" |
| AGENT_GRPC_CLIENT_CA_CERTS | Path to gRPC client CA certificate | "" |
| COCOS_NOTIFICATION_SERVER_URL | Server to receive notification events from agent. | http:/localhost:9000 |
## Deployment
To start the service outside of the container, execute the following shell script:
```bash
# download the latest version of the service
go get github.com/ultravioletrs/cocos
cd $GOPATH/src/github.com/ultravioletrs/cocos
# compile the agent
make agent
# set the environment variables and run the service
./build/cocos-agent
```
## Usage
For more information about service capabilities and its usage, please check out the [README documentation](../README.md).
+624
View File
@@ -0,0 +1,624 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.31.0
// protoc v4.25.1
// source: agent/agent.proto
package agent
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type AlgoRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Algorithm []byte `protobuf:"bytes,1,opt,name=algorithm,proto3" json:"algorithm,omitempty"`
Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"`
Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *AlgoRequest) Reset() {
*x = AlgoRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_agent_agent_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AlgoRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AlgoRequest) ProtoMessage() {}
func (x *AlgoRequest) ProtoReflect() protoreflect.Message {
mi := &file_agent_agent_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AlgoRequest.ProtoReflect.Descriptor instead.
func (*AlgoRequest) Descriptor() ([]byte, []int) {
return file_agent_agent_proto_rawDescGZIP(), []int{0}
}
func (x *AlgoRequest) GetAlgorithm() []byte {
if x != nil {
return x.Algorithm
}
return nil
}
func (x *AlgoRequest) GetProvider() string {
if x != nil {
return x.Provider
}
return ""
}
func (x *AlgoRequest) GetId() string {
if x != nil {
return x.Id
}
return ""
}
type AlgoResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *AlgoResponse) Reset() {
*x = AlgoResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_agent_agent_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AlgoResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AlgoResponse) ProtoMessage() {}
func (x *AlgoResponse) ProtoReflect() protoreflect.Message {
mi := &file_agent_agent_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AlgoResponse.ProtoReflect.Descriptor instead.
func (*AlgoResponse) Descriptor() ([]byte, []int) {
return file_agent_agent_proto_rawDescGZIP(), []int{1}
}
type DataRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Dataset []byte `protobuf:"bytes,1,opt,name=dataset,proto3" json:"dataset,omitempty"`
Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"`
Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *DataRequest) Reset() {
*x = DataRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_agent_agent_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DataRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DataRequest) ProtoMessage() {}
func (x *DataRequest) ProtoReflect() protoreflect.Message {
mi := &file_agent_agent_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DataRequest.ProtoReflect.Descriptor instead.
func (*DataRequest) Descriptor() ([]byte, []int) {
return file_agent_agent_proto_rawDescGZIP(), []int{2}
}
func (x *DataRequest) GetDataset() []byte {
if x != nil {
return x.Dataset
}
return nil
}
func (x *DataRequest) GetProvider() string {
if x != nil {
return x.Provider
}
return ""
}
func (x *DataRequest) GetId() string {
if x != nil {
return x.Id
}
return ""
}
type DataResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *DataResponse) Reset() {
*x = DataResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_agent_agent_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DataResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DataResponse) ProtoMessage() {}
func (x *DataResponse) ProtoReflect() protoreflect.Message {
mi := &file_agent_agent_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DataResponse.ProtoReflect.Descriptor instead.
func (*DataResponse) Descriptor() ([]byte, []int) {
return file_agent_agent_proto_rawDescGZIP(), []int{3}
}
type ResultRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Consumer string `protobuf:"bytes,1,opt,name=consumer,proto3" json:"consumer,omitempty"`
}
func (x *ResultRequest) Reset() {
*x = ResultRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_agent_agent_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ResultRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResultRequest) ProtoMessage() {}
func (x *ResultRequest) ProtoReflect() protoreflect.Message {
mi := &file_agent_agent_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ResultRequest.ProtoReflect.Descriptor instead.
func (*ResultRequest) Descriptor() ([]byte, []int) {
return file_agent_agent_proto_rawDescGZIP(), []int{4}
}
func (x *ResultRequest) GetConsumer() string {
if x != nil {
return x.Consumer
}
return ""
}
type ResultResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
File []byte `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"`
}
func (x *ResultResponse) Reset() {
*x = ResultResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_agent_agent_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ResultResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResultResponse) ProtoMessage() {}
func (x *ResultResponse) ProtoReflect() protoreflect.Message {
mi := &file_agent_agent_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ResultResponse.ProtoReflect.Descriptor instead.
func (*ResultResponse) Descriptor() ([]byte, []int) {
return file_agent_agent_proto_rawDescGZIP(), []int{5}
}
func (x *ResultResponse) GetFile() []byte {
if x != nil {
return x.File
}
return nil
}
type AttestationRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ReportData []byte `protobuf:"bytes,1,opt,name=report_data,json=reportData,proto3" json:"report_data,omitempty"`
}
func (x *AttestationRequest) Reset() {
*x = AttestationRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_agent_agent_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AttestationRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AttestationRequest) ProtoMessage() {}
func (x *AttestationRequest) ProtoReflect() protoreflect.Message {
mi := &file_agent_agent_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AttestationRequest.ProtoReflect.Descriptor instead.
func (*AttestationRequest) Descriptor() ([]byte, []int) {
return file_agent_agent_proto_rawDescGZIP(), []int{6}
}
func (x *AttestationRequest) GetReportData() []byte {
if x != nil {
return x.ReportData
}
return nil
}
type AttestationResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
File []byte `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"`
}
func (x *AttestationResponse) Reset() {
*x = AttestationResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_agent_agent_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AttestationResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AttestationResponse) ProtoMessage() {}
func (x *AttestationResponse) ProtoReflect() protoreflect.Message {
mi := &file_agent_agent_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AttestationResponse.ProtoReflect.Descriptor instead.
func (*AttestationResponse) Descriptor() ([]byte, []int) {
return file_agent_agent_proto_rawDescGZIP(), []int{7}
}
func (x *AttestationResponse) GetFile() []byte {
if x != nil {
return x.File
}
return nil
}
var File_agent_agent_proto protoreflect.FileDescriptor
var file_agent_agent_proto_rawDesc = []byte{
0x0a, 0x11, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x05, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x22, 0x57, 0x0a, 0x0b, 0x41, 0x6c,
0x67, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x6c, 0x67,
0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x61, 0x6c,
0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69,
0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69,
0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x02, 0x69, 0x64, 0x22, 0x0e, 0x0a, 0x0c, 0x41, 0x6c, 0x67, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x53, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x07, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08,
0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x0e, 0x0a, 0x0c, 0x44, 0x61, 0x74, 0x61,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e,
0x73, 0x75, 0x6d, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x6e,
0x73, 0x75, 0x6d, 0x65, 0x72, 0x22, 0x24, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x35, 0x0a, 0x12, 0x41,
0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x44, 0x61,
0x74, 0x61, 0x22, 0x29, 0x0a, 0x13, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x32, 0xf5, 0x01,
0x0a, 0x0c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x31,
0x0a, 0x04, 0x41, 0x6c, 0x67, 0x6f, 0x12, 0x12, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41,
0x6c, 0x67, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x67, 0x65,
0x6e, 0x74, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x00, 0x12, 0x31, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x2e, 0x61, 0x67, 0x65, 0x6e,
0x74, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e,
0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14,
0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73,
0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a,
0x0b, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x61,
0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e,
0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_agent_agent_proto_rawDescOnce sync.Once
file_agent_agent_proto_rawDescData = file_agent_agent_proto_rawDesc
)
func file_agent_agent_proto_rawDescGZIP() []byte {
file_agent_agent_proto_rawDescOnce.Do(func() {
file_agent_agent_proto_rawDescData = protoimpl.X.CompressGZIP(file_agent_agent_proto_rawDescData)
})
return file_agent_agent_proto_rawDescData
}
var file_agent_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_agent_agent_proto_goTypes = []interface{}{
(*AlgoRequest)(nil), // 0: agent.AlgoRequest
(*AlgoResponse)(nil), // 1: agent.AlgoResponse
(*DataRequest)(nil), // 2: agent.DataRequest
(*DataResponse)(nil), // 3: agent.DataResponse
(*ResultRequest)(nil), // 4: agent.ResultRequest
(*ResultResponse)(nil), // 5: agent.ResultResponse
(*AttestationRequest)(nil), // 6: agent.AttestationRequest
(*AttestationResponse)(nil), // 7: agent.AttestationResponse
}
var file_agent_agent_proto_depIdxs = []int32{
0, // 0: agent.AgentService.Algo:input_type -> agent.AlgoRequest
2, // 1: agent.AgentService.Data:input_type -> agent.DataRequest
4, // 2: agent.AgentService.Result:input_type -> agent.ResultRequest
6, // 3: agent.AgentService.Attestation:input_type -> agent.AttestationRequest
1, // 4: agent.AgentService.Algo:output_type -> agent.AlgoResponse
3, // 5: agent.AgentService.Data:output_type -> agent.DataResponse
5, // 6: agent.AgentService.Result:output_type -> agent.ResultResponse
7, // 7: agent.AgentService.Attestation:output_type -> agent.AttestationResponse
4, // [4:8] is the sub-list for method output_type
0, // [0:4] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_agent_agent_proto_init() }
func file_agent_agent_proto_init() {
if File_agent_agent_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_agent_agent_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AlgoRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_agent_agent_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AlgoResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_agent_agent_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DataRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_agent_agent_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DataResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_agent_agent_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ResultRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_agent_agent_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ResultResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_agent_agent_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AttestationRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_agent_agent_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AttestationResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_agent_agent_proto_rawDesc,
NumEnums: 0,
NumMessages: 8,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_agent_agent_proto_goTypes,
DependencyIndexes: file_agent_agent_proto_depIdxs,
MessageInfos: file_agent_agent_proto_msgTypes,
}.Build()
File_agent_agent_proto = out.File
file_agent_agent_proto_rawDesc = nil
file_agent_agent_proto_goTypes = nil
file_agent_agent_proto_depIdxs = nil
}
+47
View File
@@ -0,0 +1,47 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
syntax = "proto3";
package agent;
option go_package = "./agent";
service AgentService {
rpc Algo(AlgoRequest) returns (AlgoResponse) {}
rpc Data(DataRequest) returns (DataResponse) {}
rpc Result(ResultRequest) returns (ResultResponse) {}
rpc Attestation(AttestationRequest) returns (AttestationResponse) {}
}
message AlgoRequest {
bytes algorithm = 1;
string provider = 2;
string id = 3;
}
message AlgoResponse {}
message DataRequest {
bytes dataset = 1;
string provider = 2;
string id = 3;
}
message DataResponse {}
message ResultRequest {
string consumer = 1;
}
message ResultResponse {
bytes file = 1;
}
message AttestationRequest {
bytes report_data = 1;
}
message AttestationResponse {
bytes file = 1;
}
+223
View File
@@ -0,0 +1,223 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc v4.25.1
// source: agent/agent.proto
package agent
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
const (
AgentService_Algo_FullMethodName = "/agent.AgentService/Algo"
AgentService_Data_FullMethodName = "/agent.AgentService/Data"
AgentService_Result_FullMethodName = "/agent.AgentService/Result"
AgentService_Attestation_FullMethodName = "/agent.AgentService/Attestation"
)
// AgentServiceClient is the client API for AgentService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type AgentServiceClient interface {
Algo(ctx context.Context, in *AlgoRequest, opts ...grpc.CallOption) (*AlgoResponse, error)
Data(ctx context.Context, in *DataRequest, opts ...grpc.CallOption) (*DataResponse, error)
Result(ctx context.Context, in *ResultRequest, opts ...grpc.CallOption) (*ResultResponse, error)
Attestation(ctx context.Context, in *AttestationRequest, opts ...grpc.CallOption) (*AttestationResponse, error)
}
type agentServiceClient struct {
cc grpc.ClientConnInterface
}
func NewAgentServiceClient(cc grpc.ClientConnInterface) AgentServiceClient {
return &agentServiceClient{cc}
}
func (c *agentServiceClient) Algo(ctx context.Context, in *AlgoRequest, opts ...grpc.CallOption) (*AlgoResponse, error) {
out := new(AlgoResponse)
err := c.cc.Invoke(ctx, AgentService_Algo_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *agentServiceClient) Data(ctx context.Context, in *DataRequest, opts ...grpc.CallOption) (*DataResponse, error) {
out := new(DataResponse)
err := c.cc.Invoke(ctx, AgentService_Data_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *agentServiceClient) Result(ctx context.Context, in *ResultRequest, opts ...grpc.CallOption) (*ResultResponse, error) {
out := new(ResultResponse)
err := c.cc.Invoke(ctx, AgentService_Result_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *agentServiceClient) Attestation(ctx context.Context, in *AttestationRequest, opts ...grpc.CallOption) (*AttestationResponse, error) {
out := new(AttestationResponse)
err := c.cc.Invoke(ctx, AgentService_Attestation_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// AgentServiceServer is the server API for AgentService service.
// All implementations must embed UnimplementedAgentServiceServer
// for forward compatibility
type AgentServiceServer interface {
Algo(context.Context, *AlgoRequest) (*AlgoResponse, error)
Data(context.Context, *DataRequest) (*DataResponse, error)
Result(context.Context, *ResultRequest) (*ResultResponse, error)
Attestation(context.Context, *AttestationRequest) (*AttestationResponse, error)
mustEmbedUnimplementedAgentServiceServer()
}
// UnimplementedAgentServiceServer must be embedded to have forward compatible implementations.
type UnimplementedAgentServiceServer struct {
}
func (UnimplementedAgentServiceServer) Algo(context.Context, *AlgoRequest) (*AlgoResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Algo not implemented")
}
func (UnimplementedAgentServiceServer) Data(context.Context, *DataRequest) (*DataResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Data not implemented")
}
func (UnimplementedAgentServiceServer) Result(context.Context, *ResultRequest) (*ResultResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Result not implemented")
}
func (UnimplementedAgentServiceServer) Attestation(context.Context, *AttestationRequest) (*AttestationResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Attestation not implemented")
}
func (UnimplementedAgentServiceServer) mustEmbedUnimplementedAgentServiceServer() {}
// UnsafeAgentServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to AgentServiceServer will
// result in compilation errors.
type UnsafeAgentServiceServer interface {
mustEmbedUnimplementedAgentServiceServer()
}
func RegisterAgentServiceServer(s grpc.ServiceRegistrar, srv AgentServiceServer) {
s.RegisterService(&AgentService_ServiceDesc, srv)
}
func _AgentService_Algo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AlgoRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AgentServiceServer).Algo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AgentService_Algo_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AgentServiceServer).Algo(ctx, req.(*AlgoRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AgentService_Data_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DataRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AgentServiceServer).Data(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AgentService_Data_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AgentServiceServer).Data(ctx, req.(*DataRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AgentService_Result_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ResultRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AgentServiceServer).Result(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AgentService_Result_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AgentServiceServer).Result(ctx, req.(*ResultRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AgentService_Attestation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AttestationRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AgentServiceServer).Attestation(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AgentService_Attestation_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AgentServiceServer).Attestation(ctx, req.(*AttestationRequest))
}
return interceptor(ctx, in, info, handler)
}
// AgentService_ServiceDesc is the grpc.ServiceDesc for AgentService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var AgentService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "agent.AgentService",
HandlerType: (*AgentServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Algo",
Handler: _AgentService_Algo_Handler,
},
{
MethodName: "Data",
Handler: _AgentService_Data_Handler,
},
{
MethodName: "Result",
Handler: _AgentService_Result_Handler,
},
{
MethodName: "Attestation",
Handler: _AgentService_Attestation_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "agent/agent.proto",
}
+6
View File
@@ -0,0 +1,6 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
// Package api contains API-related concerns: endpoint definitions, middlewares
// and all resource representations.
package api
+218
View File
@@ -0,0 +1,218 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package grpc
import (
"context"
"fmt"
"time"
"github.com/go-kit/kit/endpoint"
kitgrpc "github.com/go-kit/kit/transport/grpc"
"github.com/ultravioletrs/cocos/agent"
"google.golang.org/grpc"
)
const svcName = "agent.AgentService"
type grpcClient struct {
algo endpoint.Endpoint
data endpoint.Endpoint
result endpoint.Endpoint
attestation endpoint.Endpoint
timeout time.Duration
}
// NewClient returns new gRPC client instance.
func NewClient(conn *grpc.ClientConn, timeout time.Duration) agent.AgentServiceClient {
return &grpcClient{
algo: kitgrpc.NewClient(
conn,
svcName,
"Algo",
encodeAlgoRequest,
decodeAlgoResponse,
agent.AlgoResponse{},
).Endpoint(),
data: kitgrpc.NewClient(
conn,
svcName,
"Data",
encodeDataRequest,
decodeDataResponse,
agent.DataResponse{},
).Endpoint(),
result: kitgrpc.NewClient(
conn,
svcName,
"Result",
encodeResultRequest,
decodeResultResponse,
agent.ResultResponse{},
).Endpoint(),
attestation: kitgrpc.NewClient(
conn,
svcName,
"Attestation",
encodeAttestationRequest,
decodeAttestationResponse,
agent.AttestationResponse{},
).Endpoint(),
timeout: timeout,
}
}
// encodeAlgoRequest is a transport/grpc.EncodeRequestFunc that
// converts a user-domain algoReq to a gRPC request.
func encodeAlgoRequest(_ context.Context, request interface{}) (interface{}, error) {
req, ok := request.(*algoReq)
if !ok {
return nil, fmt.Errorf("invalid request type: %T", request)
}
return &agent.AlgoRequest{
Algorithm: req.Algorithm,
Provider: req.Provider,
Id: req.Id,
}, nil
}
// decodeAlgoResponse is a transport/grpc.DecodeResponseFunc that
// converts a gRPC AlgoResponse to a user-domain response.
func decodeAlgoResponse(_ context.Context, grpcResponse interface{}) (interface{}, error) {
_, ok := grpcResponse.(*agent.AlgoResponse)
if !ok {
return nil, fmt.Errorf("invalid response type: %T", grpcResponse)
}
return algoRes{}, nil
}
// encodeDataRequest is a transport/grpc.EncodeRequestFunc that
// converts a user-domain dataReq to a gRPC request.
func encodeDataRequest(_ context.Context, request interface{}) (interface{}, error) {
req, ok := request.(*dataReq)
if !ok {
return nil, fmt.Errorf("invalid request type: %T", request)
}
return &agent.DataRequest{
Dataset: req.Dataset,
Provider: req.Provider,
Id: req.Id,
}, nil
}
// decodeDataResponse is a transport/grpc.DecodeResponseFunc that
// converts a gRPC DataResponse to a user-domain response.
func decodeDataResponse(_ context.Context, grpcResponse interface{}) (interface{}, error) {
_, ok := grpcResponse.(*agent.DataResponse)
if !ok {
return nil, fmt.Errorf("invalid response type: %T", grpcResponse)
}
return dataRes{}, nil
}
// encodeResultRequest is a transport/grpc.EncodeRequestFunc that
// converts a user-domain resultReq to a gRPC request.
func encodeResultRequest(_ context.Context, request interface{}) (interface{}, error) {
req, ok := request.(*resultReq)
if !ok {
return nil, fmt.Errorf("invalid request type: %T", request)
}
return &agent.ResultRequest{
Consumer: req.Consumer,
}, nil
}
// decodeResultResponse is a transport/grpc.DecodeResponseFunc that
// converts a gRPC ResultResponse to a user-domain response.
func decodeResultResponse(_ context.Context, grpcResponse interface{}) (interface{}, error) {
response, ok := grpcResponse.(*agent.ResultResponse)
if !ok {
return nil, fmt.Errorf("invalid response type: %T", grpcResponse)
}
return resultRes{
File: response.File,
}, nil
}
// encodeAttestationRequest is a transport/grpc.EncodeRequestFunc that
// converts a user-domain attestationReq to a gRPC request.
func encodeAttestationRequest(_ context.Context, request interface{}) (interface{}, error) {
req, ok := request.(*attestationReq)
if !ok {
return nil, fmt.Errorf("invalid request type: %T", request)
}
return &agent.AttestationRequest{ReportData: req.ReportData}, nil
}
// decodeAttestationResponse is a transport/grpc.DecodeResponseFunc that
// converts a gRPC AttestationResponse to a user-domain response.
func decodeAttestationResponse(_ context.Context, grpcResponse interface{}) (interface{}, error) {
response, ok := grpcResponse.(*agent.AttestationResponse)
if !ok {
return nil, fmt.Errorf("invalid response type: %T", grpcResponse)
}
return attestationRes{
File: response.File,
}, nil
}
// Algo implements the Algo method of the agent.AgentServiceClient interface.
func (c grpcClient) Algo(ctx context.Context, request *agent.AlgoRequest, _ ...grpc.CallOption) (*agent.AlgoResponse, error) {
ctx, cancel := context.WithTimeout(ctx, c.timeout)
defer cancel()
_, err := c.algo(ctx, &algoReq{Algorithm: request.Algorithm, Provider: request.Provider, Id: request.Id})
if err != nil {
return nil, err
}
return &agent.AlgoResponse{}, nil
}
// Data implements the Data method of the agent.AgentServiceClient interface.
func (c grpcClient) Data(ctx context.Context, request *agent.DataRequest, _ ...grpc.CallOption) (*agent.DataResponse, error) {
ctx, cancel := context.WithTimeout(ctx, c.timeout)
defer cancel()
_, err := c.data(ctx, &dataReq{Dataset: request.Dataset, Provider: request.Provider, Id: request.Id})
if err != nil {
return nil, err
}
return &agent.DataResponse{}, nil
}
// Result implements the Result method of the agent.AgentServiceClient interface.
func (c grpcClient) Result(ctx context.Context, request *agent.ResultRequest, _ ...grpc.CallOption) (*agent.ResultResponse, error) {
ctx, cancel := context.WithTimeout(ctx, c.timeout)
defer cancel()
res, err := c.result(ctx, &resultReq{Consumer: request.Consumer})
if err != nil {
return nil, err
}
resultRes := res.(resultRes)
return &agent.ResultResponse{File: resultRes.File}, nil
}
// Result implements the Result method of the agent.AgentServiceClient interface.
func (c grpcClient) Attestation(ctx context.Context, request *agent.AttestationRequest, _ ...grpc.CallOption) (*agent.AttestationResponse, error) {
ctx, cancel := context.WithTimeout(ctx, c.timeout)
defer cancel()
res, err := c.attestation(ctx, &attestationReq{ReportData: request.ReportData})
if err != nil {
return nil, err
}
attestationRes := res.(attestationRes)
return &agent.AttestationResponse{File: attestationRes.File}, nil
}
+5
View File
@@ -0,0 +1,5 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
// Package grpc contains implementation of kit service gRPC API.
package grpc
+80
View File
@@ -0,0 +1,80 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package grpc
import (
"context"
"github.com/go-kit/kit/endpoint"
"github.com/ultravioletrs/cocos/agent"
)
func algoEndpoint(svc agent.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(algoReq)
if err := req.validate(); err != nil {
return algoRes{}, err
}
algo := agent.Algorithm{Algorithm: req.Algorithm, Provider: req.Provider, ID: req.Id}
err := svc.Algo(ctx, algo)
if err != nil {
return algoRes{}, err
}
return algoRes{}, nil
}
}
func dataEndpoint(svc agent.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(dataReq)
if err := req.validate(); err != nil {
return dataRes{}, err
}
dataset := agent.Dataset{Dataset: req.Dataset, Provider: req.Provider, ID: req.Id}
err := svc.Data(ctx, dataset)
if err != nil {
return dataRes{}, err
}
return dataRes{}, nil
}
}
func resultEndpoint(svc agent.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(resultReq)
if err := req.validate(); err != nil {
return resultRes{}, err
}
file, err := svc.Result(ctx, req.Consumer)
if err != nil {
return resultRes{}, err
}
return resultRes{File: file}, nil
}
}
func attestationEndpoint(svc agent.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(attestationReq)
if err := req.validate(); err != nil {
return attestationRes{}, err
}
file, err := svc.Attestation(ctx, req.ReportData)
if err != nil {
return attestationRes{}, err
}
return attestationRes{File: file}, nil
}
}
+65
View File
@@ -0,0 +1,65 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package grpc
import (
"errors"
)
type algoReq struct {
Algorithm []byte `protobuf:"bytes,1,opt,name=algorithm,proto3" json:"algorithm,omitempty"`
Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"`
Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"`
}
func (req algoReq) validate() error {
if len(req.Algorithm) == 0 {
return errors.New("algorithm binary is required")
}
if req.Id == "" {
return errors.New("malformed entity")
}
if req.Provider == "" {
return errors.New("malformed entity")
}
return nil
}
type dataReq struct {
Dataset []byte `protobuf:"bytes,1,opt,name=dataset,proto3" json:"dataset,omitempty"`
Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"`
Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"`
}
func (req dataReq) validate() error {
if len(req.Dataset) == 0 {
return errors.New("dataset CSV file is required")
}
if req.Id == "" {
return errors.New("malformed entity")
}
if req.Provider == "" {
return errors.New("malformed entity")
}
return nil
}
type resultReq struct {
Consumer string `protobuf:"bytes,1,opt,name=consumer,proto3" json:"consumer,omitempty"`
}
func (req resultReq) validate() error {
// No request parameters to validate, so no validation logic needed
return nil
}
type attestationReq struct {
ReportData []byte
}
func (req attestationReq) validate() error {
if req.ReportData == nil {
return errors.New("malformed entity")
}
return nil
}
+15
View File
@@ -0,0 +1,15 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package grpc
type algoRes struct{}
type dataRes struct{}
type resultRes struct {
File []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
}
type attestationRes struct {
File []byte
}
+132
View File
@@ -0,0 +1,132 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package grpc
import (
"context"
"github.com/go-kit/kit/transport/grpc"
"github.com/ultravioletrs/cocos/agent"
)
type grpcServer struct {
algo grpc.Handler
data grpc.Handler
result grpc.Handler
attestation grpc.Handler
agent.UnimplementedAgentServiceServer
}
// NewServer returns new AgentServiceServer instance.
func NewServer(svc agent.Service) agent.AgentServiceServer {
return &grpcServer{
algo: grpc.NewServer(
algoEndpoint(svc),
decodeAlgoRequest,
encodeAlgoResponse,
),
data: grpc.NewServer(
dataEndpoint(svc),
decodeDataRequest,
encodeDataResponse,
),
result: grpc.NewServer(
resultEndpoint(svc),
decodeResultRequest,
encodeResultResponse,
),
attestation: grpc.NewServer(
attestationEndpoint(svc),
decodeAttestationRequest,
encodeAttestationResponse,
),
}
}
func decodeAlgoRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
req := grpcReq.(*agent.AlgoRequest)
return algoReq{
Algorithm: req.Algorithm,
Provider: req.Provider,
Id: req.Id,
}, nil
}
func encodeAlgoResponse(_ context.Context, response interface{}) (interface{}, error) {
return &agent.AlgoResponse{}, nil
}
func decodeDataRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
req := grpcReq.(*agent.DataRequest)
return dataReq{
Dataset: req.Dataset,
Provider: req.Provider,
Id: req.Id,
}, nil
}
func encodeDataResponse(_ context.Context, response interface{}) (interface{}, error) {
return &agent.DataResponse{}, nil
}
func decodeResultRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
req := grpcReq.(*agent.ResultRequest)
return resultReq{Consumer: req.Consumer}, nil
}
func encodeResultResponse(_ context.Context, response interface{}) (interface{}, error) {
res := response.(resultRes)
return &agent.ResultResponse{
File: res.File,
}, nil
}
func decodeAttestationRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
req := grpcReq.(*agent.AttestationRequest)
return attestationReq{ReportData: req.ReportData}, nil
}
func encodeAttestationResponse(_ context.Context, response interface{}) (interface{}, error) {
res := response.(attestationRes)
return &agent.AttestationResponse{
File: res.File,
}, nil
}
func (s *grpcServer) Algo(ctx context.Context, req *agent.AlgoRequest) (*agent.AlgoResponse, error) {
_, res, err := s.algo.ServeGRPC(ctx, req)
if err != nil {
return nil, err
}
ar := res.(*agent.AlgoResponse)
return ar, nil
}
func (s *grpcServer) Data(ctx context.Context, req *agent.DataRequest) (*agent.DataResponse, error) {
_, res, err := s.data.ServeGRPC(ctx, req)
if err != nil {
return nil, err
}
dr := res.(*agent.DataResponse)
return dr, nil
}
func (s *grpcServer) Result(ctx context.Context, req *agent.ResultRequest) (*agent.ResultResponse, error) {
_, res, err := s.result.ServeGRPC(ctx, req)
if err != nil {
return nil, err
}
rr := res.(*agent.ResultResponse)
return rr, nil
}
func (s *grpcServer) Attestation(ctx context.Context, req *agent.AttestationRequest) (*agent.AttestationResponse, error) {
_, res, err := s.attestation.ServeGRPC(ctx, req)
if err != nil {
return nil, err
}
rr := res.(*agent.AttestationResponse)
return rr, nil
}
+80
View File
@@ -0,0 +1,80 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
//go:build !test
// +build !test
package api
import (
"context"
"fmt"
"log/slog"
"time"
"github.com/ultravioletrs/cocos/agent"
)
var _ agent.Service = (*loggingMiddleware)(nil)
type loggingMiddleware struct {
logger *slog.Logger
svc agent.Service
}
// LoggingMiddleware adds logging facilities to the core service.
func LoggingMiddleware(svc agent.Service, logger *slog.Logger) agent.Service {
return &loggingMiddleware{logger, svc}
}
func (lm *loggingMiddleware) Algo(ctx context.Context, algorithm agent.Algorithm) (err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method Algo took %s to complete", time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors", message))
}(time.Now())
return lm.svc.Algo(ctx, algorithm)
}
func (lm *loggingMiddleware) Data(ctx context.Context, dataset agent.Dataset) (err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method Data took %s to complete", time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors", message))
}(time.Now())
return lm.svc.Data(ctx, dataset)
}
func (lm *loggingMiddleware) Result(ctx context.Context, consumer string) (response []byte, err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method Result took %s to complete", time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors", message))
}(time.Now())
return lm.svc.Result(ctx, consumer)
}
func (lm *loggingMiddleware) Attestation(ctx context.Context, reportData []byte) (response []byte, err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method Attestation took %s to complete", time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors", message))
}(time.Now())
return lm.svc.Attestation(ctx, reportData)
}
+69
View File
@@ -0,0 +1,69 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
//go:build !test
// +build !test
package api
import (
"context"
"time"
"github.com/go-kit/kit/metrics"
"github.com/ultravioletrs/cocos/agent"
)
var _ agent.Service = (*metricsMiddleware)(nil)
type metricsMiddleware struct {
counter metrics.Counter
latency metrics.Histogram
svc agent.Service
}
// MetricsMiddleware instruments core service by tracking request count and
// latency.
func MetricsMiddleware(svc agent.Service, counter metrics.Counter, latency metrics.Histogram) agent.Service {
return &metricsMiddleware{
counter: counter,
latency: latency,
svc: svc,
}
}
func (ms *metricsMiddleware) Algo(ctx context.Context, algorithm agent.Algorithm) error {
defer func(begin time.Time) {
ms.counter.With("method", "algo").Add(1)
ms.latency.With("method", "algo").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.Algo(ctx, algorithm)
}
func (ms *metricsMiddleware) Data(ctx context.Context, dataset agent.Dataset) error {
defer func(begin time.Time) {
ms.counter.With("method", "data").Add(1)
ms.latency.With("method", "data").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.Data(ctx, dataset)
}
func (ms *metricsMiddleware) Result(ctx context.Context, consumer string) ([]byte, error) {
defer func(begin time.Time) {
ms.counter.With("method", "result").Add(1)
ms.latency.With("method", "result").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.Result(ctx, consumer)
}
func (ms *metricsMiddleware) Attestation(ctx context.Context, reportData []byte) ([]byte, error) {
defer func(begin time.Time) {
ms.counter.With("method", "attestation").Add(1)
ms.latency.With("method", "attestation").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.Attestation(ctx, reportData)
}
+82
View File
@@ -0,0 +1,82 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package agent
import (
"encoding/json"
"fmt"
"reflect"
)
var (
_ fmt.Stringer = (*Datasets)(nil)
_ fmt.Stringer = (*Algorithms)(nil)
)
type AgentConfig struct {
LogLevel string `json:"log_level"`
Host string `json:"host"`
Port string `json:"port"`
CertFile string `json:"cert_file"`
KeyFile string `json:"server_key"`
ServerCAFile string `json:"server_ca_file"`
ClientCAFile string `json:"client_ca_file"`
}
type Computation struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Datasets Datasets `json:"datasets,omitempty"`
Algorithms Algorithms `json:"algorithms,omitempty"`
ResultConsumers []string `json:"result_consumers,omitempty"`
AgentConfig AgentConfig `json:"agent_config,omitempty"`
}
func (d *Datasets) String() string {
dat, err := json.Marshal(d)
if err != nil {
return ""
}
return string(dat)
}
func (a *Algorithms) String() string {
dat, err := json.Marshal(a)
if err != nil {
return ""
}
return string(dat)
}
type Dataset struct {
Dataset []byte `json:"-"`
Hash [32]byte `json:"hash,omitempty"`
Provider string `json:"provider,omitempty"`
ID string `json:"id,omitempty"`
}
type Datasets []Dataset
type Algorithm struct {
Algorithm []byte `json:"-"`
Hash [32]byte `json:"hash,omitempty"`
Provider string `json:"provider,omitempty"`
ID string `json:"id,omitempty"`
}
type Algorithms []Algorithm
func containsID(slice interface{}, id string) int {
rangeOnMe := reflect.ValueOf(slice)
for i := 0; i < rangeOnMe.Len(); i++ {
s := rangeOnMe.Index(i)
f := s.FieldByName("ID")
if f.IsValid() {
if f.Interface() == id {
return i
}
}
}
return -1
}
+4
View File
@@ -0,0 +1,4 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package agent
+68
View File
@@ -0,0 +1,68 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package events
import (
"encoding/json"
"time"
"github.com/mdlayher/vsock"
"github.com/ultravioletrs/cocos/pkg/manager"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/timestamppb"
)
type service struct {
service string
computationID string
conn *vsock.Conn
}
type AgentEvent struct {
EventType string `json:"event_type"`
Timestamp time.Time `json:"timestamp"`
ComputationID string `json:"computation_id,omitempty"`
Details json.RawMessage `json:"details,omitempty"`
Originator string `json:"originator"`
Status string `json:"status,omitempty"`
}
type Service interface {
SendEvent(event, status string, details json.RawMessage) error
Close() error
}
func New(svc, computationID string, sockPort uint32) (Service, error) {
conn, err := vsock.Dial(vsock.Host, sockPort, nil)
if err != nil {
return nil, err
}
return &service{
service: svc,
computationID: computationID,
conn: conn,
}, nil
}
func (s *service) SendEvent(event, status string, details json.RawMessage) error {
body := manager.ClientStreamMessage{Message: &manager.ClientStreamMessage_AgentEvent{AgentEvent: &manager.AgentEvent{
EventType: event,
Timestamp: timestamppb.Now(),
ComputationId: s.computationID,
Originator: s.service,
Status: status,
Details: details,
}}}
protoBody, err := proto.Marshal(&body)
if err != nil {
return err
}
if _, err := s.conn.Write(protoBody); err != nil {
return err
}
return nil
}
func (s *service) Close() error {
return s.conn.Close()
}
+254
View File
@@ -0,0 +1,254 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package agent
import (
"context"
"crypto/sha512"
"encoding/json"
"errors"
"fmt"
"log/slog"
"os/exec"
"slices"
"github.com/google/go-sev-guest/client"
"github.com/ultravioletrs/cocos/agent/events"
"github.com/ultravioletrs/cocos/pkg/socket"
"golang.org/x/crypto/sha3"
)
var _ Service = (*agentService)(nil)
var (
// ErrMalformedEntity indicates malformed entity specification (e.g.
// invalid username or password).
ErrMalformedEntity = errors.New("malformed entity specification")
// ErrUnauthorizedAccess indicates missing or invalid credentials provided
// when accessing a protected resource.
ErrUnauthorizedAccess = errors.New("missing or invalid credentials provided")
// errUndeclaredAlgorithm indicates algorithm was not declared in computation manifest.
errUndeclaredAlgorithm = errors.New("algorithm not declared in computation manifest")
// errUndeclaredAlgorithm indicates algorithm was not declared in computation manifest.
errUndeclaredDataset = errors.New("dataset not declared in computation manifest")
// errProviderMissmatch algorithm/dataset provider does not match computation manifest.
errProviderMissmatch = errors.New("provider does not match declaration on manifest")
// errAllManifestItemsReceived indicates no new computation manifest items expected.
errAllManifestItemsReceived = errors.New("all expected manifest Items have been received")
// errUndeclaredConsumer indicates the consumer requesting results in not declared in computation manifest.
errUndeclaredConsumer = errors.New("result consumer is undeclared in computation manifest")
// errResultsNotReady indicates the computation results are not ready.
errResultsNotReady = errors.New("computation results are not yet ready")
// errStateNotReady agent received a request in the wrong state.
errStateNotReady = errors.New("agent not expecting this operation in the current state")
// errHashMismatch provided algorithm/dataset does not match hash in manifest.
errHashMismatch = errors.New("malformed data, hash does not match manifest")
)
// Service specifies an API that must be fullfiled by the domain service
// implementation, and all of its decorators (e.g. logging & metrics).
type Service interface {
Algo(ctx context.Context, algorithm Algorithm) error
Data(ctx context.Context, dataset Dataset) error
Result(ctx context.Context, consumer string) ([]byte, error)
Attestation(ctx context.Context, reportData []byte) ([]byte, error)
}
type agentService struct {
computation Computation // Holds the current computation request details.
algorithms [][]byte // Stores the algorithms received for the computation.
datasets [][]byte // Stores the datasets received for the computation.
result []byte // Stores the result of the computation.
sm *StateMachine // Manages the state transitions of the agent service.
runError error // Stores any error encountered during the computation run.
eventSvc events.Service // Service for publishing events related to computation.
}
const (
socketPath = "unix_socket"
pyRuntime = "python3"
)
var _ Service = (*agentService)(nil)
// New instantiates the agent service implementation.
func New(ctx context.Context, logger *slog.Logger, eventSvc events.Service, cmp Computation) Service {
svc := &agentService{
sm: NewStateMachine(logger),
eventSvc: eventSvc,
}
go svc.sm.Start(ctx)
svc.sm.SendEvent(start)
svc.sm.StateFunctions[idle] = svc.publishEvent("in-progress", json.RawMessage{})
svc.sm.StateFunctions[receivingManifests] = svc.publishEvent("in-progress", json.RawMessage{})
svc.sm.StateFunctions[receivingAlgorithms] = svc.publishEvent("in-progress", json.RawMessage{})
svc.sm.StateFunctions[receivingData] = svc.publishEvent("in-progress", json.RawMessage{})
svc.sm.StateFunctions[resultsReady] = svc.publishEvent("in-progress", json.RawMessage{})
svc.sm.StateFunctions[complete] = svc.publishEvent("in-progress", json.RawMessage{})
svc.sm.StateFunctions[running] = svc.runComputation
svc.computation = cmp
svc.sm.SendEvent(manifestsReceived)
return svc
}
func (as *agentService) Algo(ctx context.Context, algorithm Algorithm) error {
if as.sm.GetState() != receivingAlgorithms {
return errStateNotReady
}
if len(as.computation.Algorithms) == 0 {
return errAllManifestItemsReceived
}
hash := sha3.Sum256(algorithm.Algorithm)
index := containsID(as.computation.Algorithms, algorithm.ID)
switch index {
case -1:
return errUndeclaredAlgorithm
default:
if as.computation.Algorithms[index].Provider != algorithm.Provider {
return errProviderMissmatch
}
if hash != as.computation.Algorithms[index].Hash {
return errHashMismatch
}
as.computation.Algorithms = slices.Delete(as.computation.Algorithms, index, index+1)
}
as.algorithms = append(as.algorithms, algorithm.Algorithm)
if len(as.computation.Algorithms) == 0 {
as.sm.SendEvent(algorithmsReceived)
}
return nil
}
func (as *agentService) Data(ctx context.Context, dataset Dataset) error {
if as.sm.GetState() != receivingData {
return errStateNotReady
}
if len(as.computation.Datasets) == 0 {
return errAllManifestItemsReceived
}
hash := sha3.Sum256(dataset.Dataset)
index := containsID(as.computation.Datasets, dataset.ID)
switch index {
case -1:
return errUndeclaredDataset
default:
if as.computation.Datasets[index].Provider != dataset.Provider {
return errProviderMissmatch
}
if hash != as.computation.Datasets[index].Hash {
return errHashMismatch
}
as.computation.Datasets = slices.Delete(as.computation.Datasets, index, index+1)
}
as.datasets = append(as.datasets, dataset.Dataset)
if len(as.computation.Datasets) == 0 {
as.sm.SendEvent(dataReceived)
}
return nil
}
func (as *agentService) Result(ctx context.Context, consumer string) ([]byte, error) {
if as.sm.GetState() != resultsReady {
return []byte{}, errResultsNotReady
}
if len(as.computation.ResultConsumers) == 0 {
return []byte{}, errAllManifestItemsReceived
}
index := slices.Index(as.computation.ResultConsumers, consumer)
switch index {
case -1:
return []byte{}, errUndeclaredConsumer
default:
as.computation.ResultConsumers = slices.Delete(as.computation.ResultConsumers, index, index+1)
}
if len(as.computation.ResultConsumers) == 0 {
as.sm.SendEvent(resultsConsumed)
}
// Return the result file or an error
return as.result, as.runError
}
func (as *agentService) Attestation(ctx context.Context, reportData []byte) ([]byte, error) {
provider, err := client.GetQuoteProvider()
if err != nil {
return []byte{}, err
}
rawQuote, err := provider.GetRawQuote(sha512.Sum512(reportData))
if err != nil {
return []byte{}, err
}
return rawQuote, nil
}
func (as *agentService) runComputation() {
as.publishEvent("starting", json.RawMessage{})()
as.sm.logger.Debug("computation run started")
defer as.sm.SendEvent(runComplete)
as.publishEvent("in-progress", json.RawMessage{})()
result, err := run(as.algorithms[0], as.datasets[0])
if err != nil {
as.runError = err
as.publishEvent("failed", json.RawMessage{})()
return
}
as.publishEvent("complete", json.RawMessage{})()
as.result = result
}
func (as *agentService) publishEvent(status string, details json.RawMessage) func() {
return func() {
if err := as.eventSvc.SendEvent(as.sm.State.String(), status, details); err != nil {
as.sm.logger.Warn(err.Error())
}
}
}
func run(algoContent, dataContent []byte) ([]byte, error) {
listener, err := socket.StartUnixSocketServer(socketPath)
if err != nil {
return nil, fmt.Errorf("error creating stdout pipe: %v", err)
}
defer listener.Close()
// Create channels for received data and errors
dataChannel := make(chan []byte)
errorChannel := make(chan error)
var result []byte
go socket.AcceptConnection(listener, dataChannel, errorChannel)
// Construct the Python script content with CSV data as a command-line argument
script := string(algoContent)
data := string(dataContent)
cmd := exec.Command(pyRuntime, "-c", script, data, socketPath)
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("error starting Python script: %v", err)
}
if err := cmd.Wait(); err != nil {
return nil, fmt.Errorf("python script execution error: %v", err)
}
select {
case result = <-dataChannel:
return result, nil
case err = <-errorChannel:
return nil, fmt.Errorf("error receiving data: %v", err)
}
}
+117
View File
@@ -0,0 +1,117 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package agent
import (
"context"
"fmt"
"log/slog"
"sync"
)
//go:generate stringer -type=state
type state int
const (
idle state = iota
receivingManifests
receivingAlgorithms
receivingData
running
resultsReady
complete
)
type event int
const (
start event = iota
manifestsReceived
algorithmsReceived
dataReceived
runComplete
resultsConsumed
)
// StateMachine represents the state machine.
type StateMachine struct {
mu sync.Mutex
State state
EventChan chan event
Transitions map[state]map[event]state
StateFunctions map[state]func()
logger *slog.Logger
}
// NewStateMachine creates a new StateMachine.
func NewStateMachine(logger *slog.Logger) *StateMachine {
sm := &StateMachine{
State: idle,
EventChan: make(chan event),
Transitions: make(map[state]map[event]state),
StateFunctions: make(map[state]func()),
logger: logger,
}
sm.Transitions[idle] = make(map[event]state)
sm.Transitions[idle][start] = receivingManifests
sm.Transitions[receivingManifests] = make(map[event]state)
sm.Transitions[receivingManifests][manifestsReceived] = receivingAlgorithms
sm.Transitions[receivingAlgorithms] = make(map[event]state)
sm.Transitions[receivingAlgorithms][algorithmsReceived] = receivingData
sm.Transitions[receivingData] = make(map[event]state)
sm.Transitions[receivingData][dataReceived] = running
sm.Transitions[running] = make(map[event]state)
sm.Transitions[running][runComplete] = resultsReady
sm.Transitions[resultsReady] = make(map[event]state)
sm.Transitions[resultsReady][resultsConsumed] = complete
return sm
}
// Start the state machine.
func (sm *StateMachine) Start(ctx context.Context) {
for {
select {
case event := <-sm.EventChan:
nextState, valid := sm.Transitions[sm.GetState()][event]
if valid {
sm.mu.Lock()
sm.State = nextState
sm.mu.Unlock()
sm.logger.Debug(fmt.Sprintf("Transition: %v -> %v\n", sm.GetState(), nextState))
} else {
sm.logger.Error(fmt.Sprintf("Invalid transition: %v -> ???\n", sm.GetState()))
}
stateFunc, exists := sm.StateFunctions[sm.GetState()]
if exists {
go stateFunc()
}
case <-ctx.Done():
return
}
}
}
// SendEvent sends an event to the state machine.
func (sm *StateMachine) SendEvent(event event) {
sm.EventChan <- event
}
func (sm *StateMachine) GetState() state {
sm.mu.Lock()
state := sm.State
sm.mu.Unlock()
return state
}
func (sm *StateMachine) SetState(state state) {
sm.mu.Lock()
sm.State = state
sm.mu.Unlock()
}
+29
View File
@@ -0,0 +1,29 @@
// Code generated by "stringer -type=state"; DO NOT EDIT.
package agent
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[idle-0]
_ = x[receivingManifests-1]
_ = x[receivingAlgorithms-2]
_ = x[receivingData-3]
_ = x[running-4]
_ = x[resultsReady-5]
_ = x[complete-6]
}
const _state_name = "idlereceivingManifestsreceivingAlgorithmsreceivingDatarunningresultsReadycomplete"
var _state_index = [...]uint8{0, 4, 22, 41, 54, 61, 73, 81}
func (i state) String() string {
if i < 0 || i >= state(len(_state_index)-1) {
return "state(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _state_name[_state_index[i]:_state_index[i+1]]
}
+63
View File
@@ -0,0 +1,63 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package agent
import (
"context"
"fmt"
"testing"
mglog "github.com/absmach/magistrala/logger"
)
func TestStateMachineTransitions(t *testing.T) {
testCases := []struct {
fromState state
event event
expected state
}{
{idle, start, receivingManifests},
{receivingManifests, manifestsReceived, receivingAlgorithms},
{receivingAlgorithms, algorithmsReceived, receivingData},
{receivingData, dataReceived, running},
{running, runComplete, resultsReady},
{resultsReady, resultsConsumed, complete},
}
for _, testCase := range testCases {
t.Run(fmt.Sprintf("Transition from %v to %v", testCase.fromState, testCase.expected), func(t *testing.T) {
sm := NewStateMachine(mglog.NewMock())
done := make(chan struct{})
ctx, cancel := context.WithCancel(context.Background())
go func() {
sm.Start(ctx)
close(done)
}()
sm.SetState(testCase.fromState)
sm.SendEvent(testCase.event)
if sm.GetState() != testCase.expected {
t.Errorf("Expected state %v after the event, but got %v", testCase.expected, sm.GetState())
}
close(sm.EventChan)
cancel()
<-done
})
}
}
func TestStateMachineInvalidTransition(t *testing.T) {
sm := NewStateMachine(mglog.NewMock())
ctx, cancel := context.WithCancel(context.Background())
go sm.Start(ctx)
sm.SetState(idle)
sm.SendEvent(dataReceived)
if sm.State != idle {
t.Errorf("State should not change on an invalid event, but got %v", sm.State)
}
cancel()
}
-471
View File
@@ -1,471 +0,0 @@
openapi: 3.0.1
info:
title: Computations service
description: HTTP API for managing computations
version: "1.0.0"
paths:
/computations:
post:
summary: Add new computation
description: |
Adds new computation to the list of computations owned by user identified using
the provided access token.
tags:
- computations
requestBody:
$ref: "#/components/requestBodies/ComputationCreateReq"
responses:
'201':
$ref: "#/components/responses/ComputationRes"
'400':
description: Failed due to malformed JSON.
'401':
description: Missing or invalid access token provided.
'409':
description: Entity already exist.
'415':
description: Missing or invalid content type.
'422':
description: Database can't process request.
'500':
$ref: "#/components/responses/ServiceError"
get:
summary: Retrieves computations
description: |
Retrieves a list of computations. Due to performance concerns, data
is retrieved in subsets. The API user must ensure that the entire
dataset is consumed either by making subsequent requests, or by
increasing the subset size of the initial request.
tags:
- computations
parameters:
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/Offset"
- $ref: "#/components/parameters/Name"
- $ref: "#/components/parameters/Order"
- $ref: "#/components/parameters/Direction"
- $ref: "#/components/parameters/Metadata"
responses:
'200':
$ref: "#/components/responses/ComputationsPageRes"
'400':
description: Failed due to malformed query parameters.
'401':
description: Missing or invalid access token provided.
'404':
description: A non-existent entity request.
'422':
description: Database can't process request.
'500':
$ref: "#/components/responses/ServiceError"
/computations/search:
post:
summary: Search and retrieves computations
description: |
Retrieves a list of computations with name and metadata filtering.
Due to performance concerns, data is retrieved in subsets.
The API user must ensure that the entire
dataset is consumed either by making subsequent requests, or by
increasing the subset size of the initial request.
tags:
- computations
requestBody:
$ref: "#/components/requestBodies/ComputationsSearchReq"
responses:
'200':
$ref: "#/components/responses/ComputationsPageRes"
'400':
description: Failed due to malformed query parameters.
'401':
description: Missing or invalid access token provided.
'404':
description: A non-existent entity request.
'422':
description: Unprocessable Entity
'500':
$ref: "#/components/responses/ServiceError"
/computations/{Id}:
get:
summary: Retrieves computation info
tags:
- computation
parameters:
- $ref: "#/components/parameters/Id"
responses:
'200':
$ref: "#/components/responses/ComputationRes"
'401':
description: Missing or invalid access token provided.
'404':
description: Computation does not exist.
'422':
description: Database can't process request.
'500':
$ref: "#/components/responses/ServiceError"
put:
summary: Updates computation info
description: |
Update is performed by replacing the current resource data with values
provided in a request payload.
tags:
- computations
parameters:
- $ref: "#/components/parameters/Id"
requestBody:
$ref: "#/components/requestBodies/ComputationUpdateReq"
responses:
'200':
description: Computation updated.
'400':
description: Failed due to malformed JSON.
'401':
description: Missing or invalid access token provided.
'404':
description: Computation does not exist.
'415':
description: Missing or invalid content type.
'500':
$ref: "#/components/responses/ServiceError"
delete:
summary: Removes a computation
description: |
Removes a computation.
tags:
- computation
parameters:
- $ref: "#/components/parameters/Id"
responses:
'204':
description: Computation removed.
'400':
description: Failed due to malformed ID.
'401':
description: Missing or invalid access token provided.
'500':
$ref: "#/components/responses/ServiceError"
components:
schemas:
Key:
type: string
format: uuid
description: |
Computation key that is used for computation auth. If there is
not one provided service will generate one in UUID
format.
Identity:
type: object
properties:
id:
type: string
format: uuid
description: Computation unique identifier. This can be either
provided by the user or left blank. If the user provides a UUID,
it would be validated. If there is not one provided then
the service will generate one in UUID format.
ComputationReqSchema:
type: object
properties:
name:
type: string
description: Free-form name.
description:
type: string
description: Free-form description
datasets:
type: array
description: An array of datasets.
minItems: 0
uniqueItems: true
items:
type: string
algorithms:
type: array
description: An array of algorithms.
minItems: 1
uniqueItems: true
items:
type: string
startTime:
type: number
description: Start timestamp of the computations
endTime:
type: number
description: End of the computation
status:
type: string
description: Current status of the computation
owner:
type: string
description: ID of the user who started computation
datasetProviders:
type: array
description: List of IDs of users who provided datasets
minItems: 0
uniqueItems: true
items:
type: string
algorithmProviders:
type: array
description: List of IDs of users who provided algorithms
minItems: 1
uniqueItems: true
items:
type: string
ttl:
type: number
description: Period for computation to live in an inactive state
metadata:
type: object
description: Arbitrary, object-encoded data.
ComputationsReqSchema:
type: object
properties:
name:
type: string
description: Name filter. Filtering is performed as a case-insensitive partial match.
metadata:
type: object
description: Metadata filter. Filtering is performed matching the parameter with metadata on top level. Parameter is json.
total:
type: integer
description: Total number of items.
offset:
type: integer
description: Number of items to skip during retrieval.
default: 0
minimum: 0
limit:
type: integer
description: Size of the subset to retrieve.
default: 10
maximum: 100
minimum: 1
order:
type: string
description: Order type.
default: id
enum:
- name
- id
dir:
type: string
description: Order direction.
default: desc
enum:
- asc
- desc
ComputationResSchema:
type: object
properties:
id:
type: string
format: uuid
description: Unique identifier generated by the service.
name:
type: string
description: Free-form name.
key:
type: string
format: uuid
description: Auto-generated access key.
metadata:
type: object
description: Arbitrary, object-encoded data.
required:
- id
- type
- key
ComputationsPage:
type: object
properties:
computations:
type: array
minItems: 0
uniqueItems: true
items:
$ref: "#/components/schemas/ComputationResSchema"
total:
type: integer
description: Total number of items.
offset:
type: integer
description: Number of items to skip during retrieval.
limit:
type: integer
description: Maximum number of items to return in one page.
required:
- computations
parameters:
Id:
name: Id
description: Unique identifier.
in: path
schema:
type: string
format: uuid
required: true
Limit:
name: limit
description: Size of the subset to retrieve.
in: query
schema:
type: integer
default: 10
maximum: 100
minimum: 1
required: false
Offset:
name: offset
description: Number of items to skip during retrieval.
in: query
schema:
type: integer
default: 0
minimum: 0
required: false
Name:
name: name
description: Name filter. Filtering is performed as a case-insensitive partial match.
in: query
schema:
type: string
required: false
Order:
name: order
description: Order type.
in: query
schema:
type: string
default: id
enum:
- name
- id
required: false
Direction:
name: dir
description: Order direction.
in: query
schema:
type: string
default: desc
enum:
- asc
- desc
required: false
Metadata:
name: metadata
description: Metadata filter. Filtering is performed matching the parameter with metadata on top level. Parameter is json.
in: query
required: false
schema:
type: object
additionalProperties: {}
requestBodies:
ComputationCreateReq:
description: JSON-formatted document describing the new computaton.
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ComputationReqSchema"
ComputationsCreateReq:
description: JSON-formatted document describing the new computation.
required: true
content:
application/json:
schema:
type: object
properties:
key:
$ref: "#/components/schemas/Key"
computations:
type: array
items:
$ref: "#/components/schemas/ComputationsReqSchema"
ComputationUpdateReq:
description: Arbitrary, object-encoded data.
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: Free-form name.
metadata:
type: object
ComputationsSearchReq:
description: JSON-formatted document describing search parameters.
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ComputationReqSchema"
KeyUpdateReq:
required: true
description: JSON containing computations.
content:
application/json:
schema:
type: object
properties:
key:
type: string
format: uuid
description: Computation key that is used for computation auth.
responses:
CreateComputationRes:
description: Computation registered.
headers:
Location:
content:
text/plain:
schema:
type: string
description: Created computation's relative URL.
example: /computations/{id}
ComputationRes:
description: Data retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/ComputationResSchema"
ComputationsPageRes:
description: Data retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/ComputationsPage"
IdentityRes:
description: ID returned.
content:
application/json:
schema:
$ref: "#/components/schemas/Identity"
ServiceError:
description: Unexpected server-side error occurred.
content:
application/json:
schema:
type: string
format: byte
HealthRes:
description: Service Health Check.
content:
application/json:
schema:
$ref: "./schemas/HealthInfo.yml"
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
* Users access: "Authorization: Bearer <user_token>"
security:
- bearerAuth: []
-446
View File
@@ -1,446 +0,0 @@
openapi: 3.0.1
info:
title: Datasets service
description: HTTP API for managing datasets
version: "1.0.0"
paths:
/datasets:
post:
summary: Add new dataset
description: |
Adds new dataset to the list of datasets owned by user identified using
the provided access token.
tags:
- datasets
requestBody:
$ref: "#/components/requestBodies/DatasetCreateReq"
responses:
'201':
$ref: "#/components/responses/DatasetRes"
'400':
description: Failed due to malformed JSON.
'401':
description: Missing or invalid access token provided.
'409':
description: Entity already exist.
'415':
description: Missing or invalid content type.
'422':
description: Database can't process request.
'500':
$ref: "#/components/responses/ServiceError"
get:
summary: Retrieves datasets
description: |
Retrieves a list of datasets. Due to performance concerns, data
is retrieved in subsets. The API user must ensure that the entire
dataset is consumed either by making subsequent requests, or by
increasing the subset size of the initial request.
tags:
- datasets
parameters:
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/Offset"
- $ref: "#/components/parameters/Name"
- $ref: "#/components/parameters/Order"
- $ref: "#/components/parameters/Direction"
- $ref: "#/components/parameters/Metadata"
responses:
'200':
$ref: "#/components/responses/DatasetsPageRes"
'400':
description: Failed due to malformed query parameters.
'401':
description: Missing or invalid access token provided.
'404':
description: A non-existent entity request.
'422':
description: Database can't process request.
'500':
$ref: "#/components/responses/ServiceError"
/datasets/search:
post:
summary: Search and retrieves datasets
description: |
Retrieves a list of datasets with name and metadata filtering.
Due to performance concerns, data is retrieved in subsets.
The API user must ensure that the entire
dataset is consumed either by making subsequent requests, or by
increasing the subset size of the initial request.
tags:
- datasets
requestBody:
$ref: "#/components/requestBodies/DatasetsSearchReq"
responses:
'200':
$ref: "#/components/responses/DatasetsPageRes"
'400':
description: Failed due to malformed query parameters.
'401':
description: Missing or invalid access token provided.
'404':
description: A non-existent entity request.
'422':
description: Unprocessable Entity
'500':
$ref: "#/components/responses/ServiceError"
/datasets/{Id}:
get:
summary: Retrieves dataset info
tags:
- dataset
parameters:
- $ref: "#/components/parameters/Id"
responses:
'200':
$ref: "#/components/responses/DatasetRes"
'401':
description: Missing or invalid access token provided.
'404':
description: Dataset does not exist.
'422':
description: Database can't process request.
'500':
$ref: "#/components/responses/ServiceError"
put:
summary: Updates dataset info
description: |
Update is performed by replacing the current resource data with values
provided in a request payload.
tags:
- datasets
parameters:
- $ref: "#/components/parameters/Id"
requestBody:
$ref: "#/components/requestBodies/DatasetUpdateReq"
responses:
'200':
description: dataset updated.
'400':
description: Failed due to malformed JSON.
'401':
description: Missing or invalid access token provided.
'404':
description: Dataset does not exist.
'415':
description: Missing or invalid content type.
'500':
$ref: "#/components/responses/ServiceError"
delete:
summary: Removes a dataset
description: |
Removes a dataset.
tags:
- dataset
parameters:
- $ref: "#/components/parameters/Id"
responses:
'204':
description: Dataset removed.
'400':
description: Failed due to malformed ID.
'401':
description: Missing or invalid access token provided.
'500':
$ref: "#/components/responses/ServiceError"
components:
schemas:
DatasetReqSchema:
type: object
properties:
name:
type: string
description: Free-form name.
description:
type: string
description: Free-form description
datasets:
type: array
description: An array of datasets.
minItems: 0
uniqueItems: true
items:
type: string
algorithms:
type: array
description: An array of algorithms.
minItems: 1
uniqueItems: true
items:
type: string
startTime:
type: number
description: Start timestamp of the datasets
endTime:
type: number
description: End of the dataset
status:
type: string
description: Current status of the dataset
owner:
type: string
description: ID of the user who started dataset
datasetProviders:
type: array
description: List of IDs of users who provided datasets
minItems: 0
uniqueItems: true
items:
type: string
algorithmProviders:
type: array
description: List of IDs of users who provided algorithms
minItems: 1
uniqueItems: true
items:
type: string
ttl:
type: number
description: Period for dataset to live in an inactive state
metadata:
type: object
description: Arbitrary, object-encoded data.
DatasetsReqSchema:
type: object
properties:
name:
type: string
description: Name filter. Filtering is performed as a case-insensitive partial match.
metadata:
type: object
description: Metadata filter. Filtering is performed matching the parameter with metadata on top level. Parameter is json.
total:
type: integer
description: Total number of items.
offset:
type: integer
description: Number of items to skip during retrieval.
default: 0
minimum: 0
limit:
type: integer
description: Size of the subset to retrieve.
default: 10
maximum: 100
minimum: 1
order:
type: string
description: Order type.
default: id
enum:
- name
- id
dir:
type: string
description: Order direction.
default: desc
enum:
- asc
- desc
DatasetResSchema:
type: object
properties:
id:
type: string
format: uuid
description: Unique identifier generated by the service.
name:
type: string
description: Free-form name.
key:
type: string
format: uuid
description: Auto-generated access key.
metadata:
type: object
description: Arbitrary, object-encoded data.
required:
- id
- type
- key
DatasetsPage:
type: object
properties:
datasets:
type: array
minItems: 0
uniqueItems: true
items:
$ref: "#/components/schemas/DatasetResSchema"
total:
type: integer
description: Total number of items.
offset:
type: integer
description: Number of items to skip during retrieval.
limit:
type: integer
description: Maximum number of items to return in one page.
required:
- datasets
parameters:
Id:
name: Id
description: Unique identifier.
in: path
schema:
type: string
format: uuid
required: true
Limit:
name: limit
description: Size of the subset to retrieve.
in: query
schema:
type: integer
default: 10
maximum: 100
minimum: 1
required: false
Offset:
name: offset
description: Number of items to skip during retrieval.
in: query
schema:
type: integer
default: 0
minimum: 0
required: false
Name:
name: name
description: Name filter. Filtering is performed as a case-insensitive partial match.
in: query
schema:
type: string
required: false
Order:
name: order
description: Order type.
in: query
schema:
type: string
default: id
enum:
- name
- id
required: false
Direction:
name: dir
description: Order direction.
in: query
schema:
type: string
default: desc
enum:
- asc
- desc
required: false
Metadata:
name: metadata
description: Metadata filter. Filtering is performed matching the parameter with metadata on top level. Parameter is json.
in: query
required: false
schema:
type: object
additionalProperties: {}
requestBodies:
DatasetCreateReq:
description: JSON-formatted document describing the new dataset.
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DatasetReqSchema"
DatasetsCreateReq:
description: JSON-formatted document describing the new dataset.
required: true
content:
application/json:
schema:
type: object
properties:
datasets:
type: array
items:
$ref: "#/components/schemas/DatasetsReqSchema"
DatasetUpdateReq:
description: Arbitrary, object-encoded data.
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: Free-form name.
metadata:
type: object
DatasetsSearchReq:
description: JSON-formatted document describing search parameters.
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DatasetReqSchema"
KeyUpdateReq:
required: true
description: JSON containing datasets.
content:
application/json:
schema:
type: object
properties:
key:
type: string
format: uuid
description: Thing key that is used for thing auth.
responses:
CreateDatasetRes:
description: Dataset registered.
headers:
Location:
content:
text/plain:
schema:
type: string
description: Created dataset's relative URL.
example: /datasets/{id}
DatasetRes:
description: Data retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/DatasetResSchema"
DatasetsPageRes:
description: Data retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/DatasetsPage"
ServiceError:
description: Unexpected server-side error occurred.
content:
application/json:
schema:
type: string
format: byte
HealthRes:
description: Service Health Check.
content:
application/json:
schema:
$ref: "./schemas/HealthInfo.yml"
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
* Users access: "Authorization: Bearer <user_token>"
security:
- bearerAuth: []
@@ -1,84 +0,0 @@
{
"info": {
"_postman_id": "5ed31077-ca87-496e-9b98-b8793ce7c5d2",
"name": "CoCoS",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Create Computation",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"Calculate salary\",\n \"description\": \"my test computation\",\n \"ttl\": 1243\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:9000/computations",
"protocol": "http",
"host": [
"localhost"
],
"port": "9000",
"path": [
"computations"
]
}
},
"response": []
},
{
"name": "View Computation",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:9000/computations/c89b53d3-c088-4b5a-addd-51a90ea94325",
"protocol": "http",
"host": [
"localhost"
],
"port": "9000",
"path": [
"computations",
"c89b53d3-c088-4b5a-addd-51a90ea94325"
]
}
},
"response": []
}
],
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
}
],
"variable": [
{
"key": "jwt",
"value": "",
"type": "string"
}
]
}
+69
View File
@@ -0,0 +1,69 @@
# Agent CLI
This repository contains the command-line interface (CLI) tool for interacting with the Agent and manager service. The CLI allows you to perform various tasks such as running computations, uploading algorithms and datasets, and retrieving results.
## Build
From the project root:
```bash
make cli
```
## Usage
#### Run Computation
To run a computation, use the following command:
```bash
./build/cocos-cli manager run --computation '{"name": "my-computation"}'
```
#### Get attestation
To retrieve attestation from agent, use the following command:
```bash
./build/cocos-cli agent attestation get '<report_data>'
```
#### Validate attestation
To validate and verify attestation from agent, use the following command:
```bash
./build/cocos-cli agent attestation validate '<attestation>' '<report_data>'
```
#### Upload Algorithm
To upload an algorithm, use the following command:
```bash
./build/cocos-cli agent algo /path/to/algorithm
```
#### Upload Dataset
To upload a dataset, use the following command:
```bash
./build/cocos-cli agent data /path/to/dataset.csv
```
#### Retrieve result
To retrieve the computation result, use the following command:
```bash
./build/cocos-cli agent result
```
## Installtion
To use the CLI, you have the option to install it globally on your system. Here's how:
### Build the CLI:
Navigate to the project root and run the following command to build the CLI binary:
```bash
make install-cli
```
+42
View File
@@ -0,0 +1,42 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"log"
"os"
"github.com/spf13/cobra"
"github.com/ultravioletrs/cocos/agent"
)
func (cli *CLI) NewAlgorithmsCmd() *cobra.Command {
return &cobra.Command{
Use: "algo",
Short: "Upload an algorithm binary",
Example: "algo <algo_file> <id> <provider>",
Args: cobra.ExactArgs(3),
Run: func(cmd *cobra.Command, args []string) {
algorithmFile := args[0]
log.Println("Uploading algorithm binary:", algorithmFile)
algorithm, err := os.ReadFile(algorithmFile)
if err != nil {
log.Fatalf("Error reading algorithm file: %v", err)
}
algoReq := agent.Algorithm{
Algorithm: algorithm,
ID: args[1],
Provider: args[2],
}
if err := cli.agentSDK.Algo(cmd.Context(), algoReq); err != nil {
log.Fatalf("Error uploading algorithm with ID %s and provider %s: %v", algoReq.ID, algoReq.Provider, err)
}
log.Println("Successfully uploaded algorithm")
},
}
}
+101
View File
@@ -0,0 +1,101 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"fmt"
"log"
"os"
"github.com/google/go-sev-guest/abi"
"github.com/google/go-sev-guest/validate"
"github.com/google/go-sev-guest/verify"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
const attestationFilePath = "attestation.txt"
func (cli *CLI) NewAttestationCmd() *cobra.Command {
return &cobra.Command{
Use: "attestation [command]",
Short: "Get and validate attestations",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Get and validate attestations\n\n")
fmt.Printf("Usage:\n %s [command]\n\n", cmd.CommandPath())
fmt.Printf("Available Commands:\n")
// Filter out "completion" command
availableCommands := make([]*cobra.Command, 0)
for _, subCmd := range cmd.Commands() {
if subCmd.Name() != "completion" {
availableCommands = append(availableCommands, subCmd)
}
}
for _, subCmd := range availableCommands {
fmt.Printf(" %-15s%s\n", subCmd.Name(), subCmd.Short)
}
fmt.Printf("\nFlags:\n")
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
fmt.Printf(" -%s, --%s %s\n", flag.Shorthand, flag.Name, flag.Usage)
})
fmt.Printf("\nUse \"%s [command] --help\" for more information about a command.\n", cmd.CommandPath())
},
}
}
func (cli *CLI) NewGetAttestationCmd() *cobra.Command {
return &cobra.Command{
Use: "get",
Short: "Retrieve attestation information from agent",
Example: "report <report_data>",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
log.Println("Getting attestation")
result, err := cli.agentSDK.Attestation(cmd.Context(), []byte(args[0]))
if err != nil {
log.Fatalf("Error retrieving attestation: %v", err)
}
if err = os.WriteFile(attestationFilePath, result, 0o644); err != nil {
log.Fatalf("Error saving attestation result: %v", err)
}
log.Println("Attestation result retrieved and saved successfully!")
},
}
}
func (cli *CLI) NewValidateAttestationValidationCmd() *cobra.Command {
return &cobra.Command{
Use: "validate",
Short: "Validate and verify attestation information",
Example: "validate <attestation> <report_data>",
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
log.Println("Checking attestation")
if err := verifyAndValidateAttestation([]byte(args[0]), []byte(args[1])); err != nil {
log.Fatalf("attestation validation and veification failed with error: %s", err)
}
log.Println("Attestation validation and verification is successful!")
},
}
}
func verifyAndValidateAttestation(attestation, reportData []byte) error {
attestationPB, err := abi.ReportCertsToProto(attestation)
if err != nil {
return err
}
if err = verify.SnpAttestation(attestationPB, verify.DefaultOptions()); err != nil {
return err
}
if err = validate.SnpAttestation(attestationPB, &validate.Options{ReportData: reportData}); err != nil {
return err
}
return nil
}
+42
View File
@@ -0,0 +1,42 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"log"
"os"
"github.com/spf13/cobra"
"github.com/ultravioletrs/cocos/agent"
)
func (cli *CLI) NewDatasetsCmd() *cobra.Command {
return &cobra.Command{
Use: "data",
Short: "Upload a dataset CSV file",
Example: "data <dataset.csv> <id> <provider>",
Args: cobra.ExactArgs(3),
Run: func(cmd *cobra.Command, args []string) {
datasetFile := args[0]
log.Println("Uploading dataset CSV:", datasetFile)
dataset, err := os.ReadFile(datasetFile)
if err != nil {
log.Fatalf("Error reading dataset file: %v", err)
}
dataReq := agent.Dataset{
Dataset: dataset,
ID: args[1],
Provider: args[2],
}
if err := cli.agentSDK.Data(cmd.Context(), dataReq); err != nil {
log.Fatalf("Error uploading dataset: %v", err)
}
log.Println("Successfully uploaded dataset")
},
}
}
+34
View File
@@ -0,0 +1,34 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"log"
"os"
"github.com/spf13/cobra"
)
const resultFilePath = "result.bin"
func (cli *CLI) NewResultsCmd() *cobra.Command {
return &cobra.Command{
Use: "result",
Short: "Retrieve computation result file",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
log.Println("Retrieving computation result file")
result, err := cli.agentSDK.Result(cmd.Context(), args[0])
if err != nil {
log.Fatalf("Error retrieving computation result: %v", err)
}
if err := os.WriteFile(resultFilePath, result, 0o644); err != nil {
log.Fatalf("Error saving computation result to %s: %v", resultFilePath, err)
}
log.Println("Computation result retrieved and saved successfully!")
},
}
}
+17
View File
@@ -0,0 +1,17 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"github.com/ultravioletrs/cocos/agent"
)
type CLI struct {
agentSDK agent.Service
}
func New(agentSDK agent.Service) *CLI {
return &CLI{
agentSDK: agentSDK,
}
}
+129
View File
@@ -0,0 +1,129 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"log/slog"
"github.com/mdlayher/vsock"
"github.com/ultravioletrs/cocos/agent"
"github.com/ultravioletrs/cocos/agent/api"
agentgrpc "github.com/ultravioletrs/cocos/agent/api/grpc"
"github.com/ultravioletrs/cocos/agent/events"
"github.com/ultravioletrs/cocos/internal"
agentlogger "github.com/ultravioletrs/cocos/internal/logger"
"github.com/ultravioletrs/cocos/internal/server"
grpcserver "github.com/ultravioletrs/cocos/internal/server/grpc"
"github.com/ultravioletrs/cocos/manager"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
)
const (
svcName = "agent"
defSvcGRPCPort = "7002"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
cfg, err := readConfig()
if err != nil {
log.Fatalf("failed to read agent configuration from vsock %s", err.Error())
}
conn, err := vsock.Dial(vsock.Host, manager.ManagerVsockPort, nil)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
var level slog.Level
if err := level.UnmarshalText([]byte(cfg.AgentConfig.LogLevel)); err != nil {
log.Println(err)
return
}
handler := agentlogger.NewProtoHandler(conn, &slog.HandlerOptions{Level: level})
logger := slog.New(handler)
eventSvc, err := events.New(svcName, cfg.ID, manager.ManagerVsockPort)
if err != nil {
log.Printf("failed to create events service %s", err.Error())
return
}
defer eventSvc.Close()
svc := newService(ctx, logger, eventSvc, cfg)
grpcServerConfig := server.Config{
Port: cfg.AgentConfig.Port,
Host: cfg.AgentConfig.Host,
CertFile: cfg.AgentConfig.CertFile,
KeyFile: cfg.AgentConfig.KeyFile,
ServerCAFile: cfg.AgentConfig.ServerCAFile,
ClientCAFile: cfg.AgentConfig.ClientCAFile,
}
registerAgentServiceServer := func(srv *grpc.Server) {
reflection.Register(srv)
agent.RegisterAgentServiceServer(srv, agentgrpc.NewServer(svc))
}
gs := grpcserver.New(ctx, cancel, svcName, grpcServerConfig, registerAgentServiceServer, logger)
g.Go(func() error {
return gs.Start()
})
g.Go(func() error {
return server.StopHandler(ctx, cancel, logger, svcName, gs)
})
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("%s service terminated: %s", svcName, err))
}
}
func newService(ctx context.Context, logger *slog.Logger, eventSvc events.Service, cmp agent.Computation) agent.Service {
svc := agent.New(ctx, logger, eventSvc, cmp)
svc = api.LoggingMiddleware(svc, logger)
counter, latency := internal.MakeMetrics(svcName, "api")
svc = api.MetricsMiddleware(svc, counter, latency)
return svc
}
func readConfig() (agent.Computation, error) {
l, err := vsock.Listen(manager.VsockConfigPort, nil)
if err != nil {
return agent.Computation{}, err
}
defer l.Close()
conn, err := l.Accept()
if err != nil {
return agent.Computation{}, err
}
defer conn.Close()
b := make([]byte, 1024)
n, err := conn.Read(b)
if err != nil {
return agent.Computation{}, err
}
ac := agent.Computation{
AgentConfig: agent.AgentConfig{},
}
if err := json.Unmarshal(b[:n], &ac); err != nil {
return agent.Computation{}, err
}
if ac.AgentConfig.LogLevel == "" {
ac.AgentConfig.LogLevel = "info"
}
if ac.AgentConfig.Port == "" {
ac.AgentConfig.Port = defSvcGRPCPort
}
return ac, nil
}
+101
View File
@@ -0,0 +1,101 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package main
import (
"fmt"
"log"
"os"
mglog "github.com/absmach/magistrala/logger"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/ultravioletrs/cocos/cli"
"github.com/ultravioletrs/cocos/internal/env"
"github.com/ultravioletrs/cocos/pkg/clients/grpc"
"github.com/ultravioletrs/cocos/pkg/clients/grpc/agent"
"github.com/ultravioletrs/cocos/pkg/sdk"
)
const (
svcName = "cli"
envPrefixAgentGRPC = "AGENT_GRPC_"
completion = "completion"
)
type config struct {
LogLevel string `env:"AGENT_LOG_LEVEL" envDefault:"info"`
}
func main() {
var cfg config
if err := env.Parse(&cfg); err != nil {
log.Fatalf("failed to load %s configuration : %s", svcName, err)
}
logger, err := mglog.New(os.Stdout, cfg.LogLevel)
if err != nil {
log.Fatalf("Error creating logger: %s", err)
}
agentGRPCConfig := grpc.Config{}
if err := env.Parse(&agentGRPCConfig, env.Options{Prefix: envPrefixAgentGRPC}); err != nil {
logger.Error(fmt.Sprintf("failed to load %s gRPC client configuration : %s", svcName, err))
return
}
agentGRPCClient, agentClient, err := agent.NewAgentClient(agentGRPCConfig)
if err != nil {
logger.Error(err.Error())
return
}
defer agentGRPCClient.Close()
agentSDK := sdk.NewAgentSDK(logger, agentClient)
cliSVC := cli.New(agentSDK)
rootCmd := &cobra.Command{
Use: "cocos-cli [command]",
Short: "CLI application for CoCos Service API",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("CLI application for CoCos Service API\n\n")
fmt.Printf("Usage:\n %s [command]\n\n", cmd.CommandPath())
fmt.Printf("Available Commands:\n")
// Filter out "completion" command
availableCommands := make([]*cobra.Command, 0)
for _, subCmd := range cmd.Commands() {
if subCmd.Name() != completion {
availableCommands = append(availableCommands, subCmd)
}
}
for _, subCmd := range availableCommands {
fmt.Printf(" %-15s%s\n", subCmd.Name(), subCmd.Short)
}
fmt.Printf("\nFlags:\n")
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
fmt.Printf(" -%s, --%s %s\n", flag.Shorthand, flag.Name, flag.Usage)
})
fmt.Printf("\nUse \"%s [command] --help\" for more information about a command.\n", cmd.CommandPath())
},
}
// Agent Commands
rootCmd.AddCommand(cliSVC.NewAlgorithmsCmd())
rootCmd.AddCommand(cliSVC.NewDatasetsCmd())
rootCmd.AddCommand(cliSVC.NewResultsCmd())
attestaionCmd := cliSVC.NewAttestationCmd()
rootCmd.AddCommand(attestaionCmd)
// Attestation commands
attestaionCmd.AddCommand(cliSVC.NewGetAttestationCmd())
attestaionCmd.AddCommand(cliSVC.NewValidateAttestationValidationCmd())
if err := rootCmd.Execute(); err != nil {
logger.Error(fmt.Sprintf("Command execution failed: %s", err))
return
}
}
-208
View File
@@ -1,208 +0,0 @@
package main
import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"strconv"
"time"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/opentracing/opentracing-go"
jconfig "github.com/uber/jaeger-client-go/config"
"github.com/ultravioletrs/clients"
authapi "github.com/ultravioletrs/clients/api/grpc"
"github.com/ultravioletrs/cocos/computations"
"github.com/ultravioletrs/cocos/computations/api/api"
"github.com/ultravioletrs/cocos/computations/postgres"
"github.com/ultravioletrs/cocos/internal/db"
"github.com/ultravioletrs/cocos/internal/env"
"github.com/ultravioletrs/cocos/internal/errors"
"github.com/ultravioletrs/cocos/internal/http"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
const (
defLogLevel = "debug"
defDBHost = "localhost"
defDBPort = "5432"
defDBUser = "cocos"
defDBPass = "cocos"
defDB = "computations"
defDBSSLMode = "disable"
defDBSSLCert = ""
defDBSSLKey = ""
defDBSSLRootCert = ""
defHTTPPort = "9000"
defServerCert = ""
defServerKey = ""
defJaegerURL = ""
defAuthTLS = "false"
defAuthCACerts = ""
defAuthURL = "localhost:8181"
defAuthTimeout = "1s"
envLogLevel = "COCOS_COMPUTATIONS_LOG_LEVEL"
envDBHost = "COCOS_COMPUTATIONS_DB_HOST"
envDBPort = "COCOS_COMPUTATIONS_DB_PORT"
envDBUser = "COCOS_COMPUTATIONS_DB_USER"
envDBPass = "COCOS_COMPUTATIONS_DB_PASS"
envDB = "COCOS_COMPUTATIONS_DB"
envDBSSLMode = "COCOS_COMPUTATIONS_DB_SSL_MODE"
envDBSSLCert = "COCOS_COMPUTATIONS_DB_SSL_CERT"
envDBSSLKey = "COCOS_COMPUTATIONS_DB_SSL_KEY"
envDBSSLRootCert = "COCOS_COMPUTATIONS_DB_SSL_ROOT_CERT"
envHTTPPort = "COCOS_COMPUTATIONS_HTTP_PORT"
envServerCert = "COCOS_COMPUTATIONS_SERVER_CERT"
envServerKey = "COCOS_COMPUTATIONS_SERVER_KEY"
envJaegerURL = "MF_JAEGER_URL"
envAuthTLS = "COCOS_COMPUTATIONS_AUTH_CLIENT_TLS"
envAuthCACerts = "COCOS_COMPUTATIONS_AUTH_CA_CERTS"
envAuthURL = "COCOS_COMPUTATIONS_AUTH_GRPC_URL"
envAuthTimeout = "COCOS_COMPUTATIONS_AUTH_GRPC_TIMEOUT"
)
const svcName = "Computations"
type config struct {
logLevel string
dbConfig db.Config
httpPort string
serverCert string
serverKey string
jaegerURL string
authTLS bool
authCACerts string
authURL string
authTimeout time.Duration
}
func loadConfig() config {
authTimeout, err := time.ParseDuration(mainflux.Env(envAuthTimeout, defAuthTimeout))
if err != nil {
log.Fatalf("Invalid %s value: %s", envAuthTimeout, err.Error())
}
tls, err := strconv.ParseBool(mainflux.Env(envAuthTLS, defAuthTLS))
if err != nil {
log.Fatalf("Invalid value passed for %s\n", envAuthTLS)
}
dbConfig := db.Config{
Host: env.Load(envDBHost, defDBHost),
Port: env.Load(envDBPort, defDBPort),
User: env.Load(envDBUser, defDBUser),
Pass: env.Load(envDBPass, defDBPass),
Name: env.Load(envDB, defDB),
SSLMode: env.Load(envDBSSLMode, defDBSSLMode),
SSLCert: env.Load(envDBSSLCert, defDBSSLCert),
SSLKey: env.Load(envDBSSLKey, defDBSSLKey),
SSLRootCert: env.Load(envDBSSLRootCert, defDBSSLRootCert),
Migrations: postgres.Migrations,
}
return config{
dbConfig: dbConfig,
authTLS: tls,
authTimeout: authTimeout,
logLevel: env.Load(envLogLevel, defLogLevel),
httpPort: env.Load(envHTTPPort, defHTTPPort),
serverCert: env.Load(envServerCert, defServerCert),
serverKey: env.Load(envServerKey, defServerKey),
authCACerts: env.Load(envAuthCACerts, defAuthCACerts),
jaegerURL: env.Load(envJaegerURL, defJaegerURL),
authURL: env.Load(envAuthURL, defAuthURL),
}
}
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
g, ctx := errgroup.WithContext(ctx)
l, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
log.Fatalf(err.Error())
}
db, err := db.Connect(cfg.dbConfig)
if err != nil {
log.Fatalf(err.Error())
}
authTracer, closer := initJaeger("auth", cfg.jaegerURL, l)
defer closer.Close()
auth, close := connectToAuth(cfg, authTracer, l)
if close != nil {
defer close()
}
repo := postgres.NewRepository(db)
idp := uuid.New()
svc := computations.NewService(repo, idp, auth)
svc = api.LoggingMiddleware(svc, l)
h := api.MakeHandler(svc, nil, l)
g.Go(func() error {
return http.StartServer(ctx, svcName, cfg.httpPort, cfg.serverCert, cfg.serverKey, h, l)
})
g.Go(errors.Handle(svcName, l, ctx, cancel))
if err := g.Wait(); err != nil {
l.Error(fmt.Sprintf("%s service terminated: %s", svcName, err))
}
}
func initJaeger(svcName, url string, logger logger.Logger) (opentracing.Tracer, io.Closer) {
if url == "" {
return opentracing.NoopTracer{}, ioutil.NopCloser(nil)
}
tracer, closer, err := jconfig.Configuration{
ServiceName: svcName,
Sampler: &jconfig.SamplerConfig{
Type: "const",
Param: 1,
},
Reporter: &jconfig.ReporterConfig{
LocalAgentHostPort: url,
LogSpans: true,
},
}.NewTracer()
if err != nil {
logger.Error(fmt.Sprintf("Failed to init Jaeger: %s", err))
os.Exit(1)
}
return tracer, closer
}
func connectToAuth(cfg config, tracer opentracing.Tracer, logger logger.Logger) (clients.AuthServiceClient, func() error) {
var opts []grpc.DialOption
if cfg.authTLS {
if cfg.authCACerts != "" {
tpc, err := credentials.NewClientTLSFromFile(cfg.authCACerts, "")
if err != nil {
logger.Error(fmt.Sprintf("Failed to create tls credentials: %s", err))
os.Exit(1)
}
opts = append(opts, grpc.WithTransportCredentials(tpc))
}
} else {
opts = append(opts, grpc.WithInsecure())
logger.Info("gRPC communication is not encrypted")
}
conn, err := grpc.Dial(cfg.authURL, opts...)
if err != nil {
logger.Error(fmt.Sprintf("Failed to connect to auth service: %s", err))
os.Exit(1)
}
return authapi.NewClient(tracer, conn, cfg.authTimeout), conn.Close
}
-141
View File
@@ -1,141 +0,0 @@
package main
import (
"context"
"fmt"
"log"
"os"
"strconv"
"time"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/ultravioletrs/cocos/datasets"
"github.com/ultravioletrs/cocos/datasets/api"
"github.com/ultravioletrs/cocos/datasets/postgres"
"github.com/ultravioletrs/cocos/internal/db"
"github.com/ultravioletrs/cocos/internal/env"
"github.com/ultravioletrs/cocos/internal/errors"
"github.com/ultravioletrs/cocos/internal/http"
"golang.org/x/sync/errgroup"
)
const (
defLogLevel = "debug"
defDBHost = "localhost"
defDBPort = "5432"
defDBUser = "cocos"
defDBPass = "cocos"
defDB = "datasets"
defDBSSLMode = "disable"
defDBSSLCert = ""
defDBSSLKey = ""
defDBSSLRootCert = ""
defHTTPPort = "9001"
defServerCert = ""
defServerKey = ""
defAuthTLS = "false"
defAuthCACerts = ""
defAuthURL = "localhost:8181"
defAuthTimeout = "1s"
envLogLevel = "COCOS_DATASETS_LOG_LEVEL"
envDBHost = "COCOS_DATASETS_DB_HOST"
envDBPort = "COCOS_DATASETS_DB_PORT"
envDBUser = "COCOS_DATASETS_DB_USER"
envDBPass = "COCOS_DATASETS_DB_PASS"
envDB = "COCOS_DATASETS_DB"
envDBSSLMode = "COCOS_DATASETS_DB_SSL_MODE"
envDBSSLCert = "COCOS_DATASETS_DB_SSL_CERT"
envDBSSLKey = "COCOS_DATASETS_DB_SSL_KEY"
envDBSSLRootCert = "COCOS_DATASETS_DB_SSL_ROOT_CERT"
envHTTPPort = "COCOS_DATASETS_HTTP_PORT"
envServerCert = "COCOS_DATASETS_SERVER_CERT"
envServerKey = "COCOS_DATASETS_SERVER_KEY"
envAuthTLS = "COCOS_DATASETS_AUTH_CLIENT_TLS"
envAuthCACerts = "COCOS_DATASETS_AUTH_CA_CERTS"
envAuthURL = "COCOS_DATASETS_AUTH_GRPC_URL"
envAuthTimeout = "COCOS_DATASETS_AUTH_GRPC_TIMEOUT"
)
const svcName = "Datasets"
type config struct {
logLevel string
dbConfig db.Config
httpPort string
serverCert string
serverKey string
authTLS bool
authCACerts string
authURL string
authTimeout time.Duration
}
func loadConfig() config {
authTimeout, err := time.ParseDuration(mainflux.Env(envAuthTimeout, defAuthTimeout))
if err != nil {
log.Fatalf("Invalid %s value: %s", envAuthTimeout, err.Error())
}
tls, err := strconv.ParseBool(mainflux.Env(envAuthTLS, defAuthTLS))
if err != nil {
log.Fatalf("Invalid value passed for %s\n", envAuthTLS)
}
dbConfig := db.Config{
Host: env.Load(envDBHost, defDBHost),
Port: env.Load(envDBPort, defDBPort),
User: env.Load(envDBUser, defDBUser),
Pass: env.Load(envDBPass, defDBPass),
Name: env.Load(envDB, defDB),
SSLMode: env.Load(envDBSSLMode, defDBSSLMode),
SSLCert: env.Load(envDBSSLCert, defDBSSLCert),
SSLKey: env.Load(envDBSSLKey, defDBSSLKey),
SSLRootCert: env.Load(envDBSSLRootCert, defDBSSLRootCert),
Migrations: postgres.Migrations,
}
return config{
dbConfig: dbConfig,
authTLS: tls,
authTimeout: authTimeout,
logLevel: env.Load(envLogLevel, defLogLevel),
httpPort: env.Load(envHTTPPort, defHTTPPort),
serverCert: env.Load(envServerCert, defServerCert),
serverKey: env.Load(envServerKey, defServerKey),
authCACerts: env.Load(envAuthCACerts, defAuthCACerts),
authURL: env.Load(envAuthURL, defAuthURL),
}
}
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
g, ctx := errgroup.WithContext(ctx)
l, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
log.Fatalf(err.Error())
}
db, err := db.Connect(cfg.dbConfig)
if err != nil {
log.Fatalf(err.Error())
}
repo := postgres.NewRepository(db)
idp := uuid.New()
svc := datasets.NewService(repo, idp)
svc = api.LoggingMiddleware(svc, l)
h := api.MakeHandler(svc, nil, l)
g.Go(func() error {
return http.StartServer(ctx, svcName, cfg.httpPort, cfg.serverCert, cfg.serverKey, h, l)
})
g.Go(errors.Handle(svcName, l, ctx, cancel))
if err := g.Wait(); err != nil {
l.Error(fmt.Sprintf("%s service terminated: %s", svcName, err))
}
}
+139
View File
@@ -0,0 +1,139 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package main
import (
"context"
"fmt"
"log"
"log/slog"
"os"
"strings"
mglog "github.com/absmach/magistrala/logger"
"github.com/absmach/magistrala/pkg/uuid"
"github.com/ultravioletrs/cocos/internal"
"github.com/ultravioletrs/cocos/internal/env"
jaegerclient "github.com/ultravioletrs/cocos/internal/jaeger"
"github.com/ultravioletrs/cocos/manager"
"github.com/ultravioletrs/cocos/manager/api"
managerapi "github.com/ultravioletrs/cocos/manager/api/grpc"
"github.com/ultravioletrs/cocos/manager/qemu"
"github.com/ultravioletrs/cocos/manager/tracing"
"github.com/ultravioletrs/cocos/pkg/clients/grpc"
managergrpc "github.com/ultravioletrs/cocos/pkg/clients/grpc/manager"
pkgmanager "github.com/ultravioletrs/cocos/pkg/manager"
"go.opentelemetry.io/otel/trace"
"golang.org/x/sync/errgroup"
)
const (
svcName = "manager"
envPrefixGRPC = "MANAGER_GRPC_"
envPrefixQemu = "MANAGER_QEMU_"
)
type config struct {
LogLevel string `env:"MANAGER_LOG_LEVEL" envDefault:"info"`
JaegerURL string `env:"COCOS_JAEGER_URL" envDefault:"http://localhost:14268/api/traces"`
InstanceID string `env:"MANAGER_INSTANCE_ID" envDefault:""`
}
func main() {
ctx := context.Background()
g, ctx := errgroup.WithContext(ctx)
var cfg config
if err := env.Parse(&cfg); err != nil {
log.Fatalf("failed to load %s configuration : %s", svcName, err)
}
logger, err := mglog.New(os.Stdout, cfg.LogLevel)
if err != nil {
log.Fatalf(err.Error())
}
if cfg.InstanceID == "" {
cfg.InstanceID, err = uuid.New().ID()
if err != nil {
logger.Error(fmt.Sprintf("Failed to generate instance ID: %s", err))
return
}
}
tp, err := jaegerclient.NewProvider(ctx, svcName, cfg.JaegerURL, cfg.InstanceID)
if err != nil {
logger.Error(fmt.Sprintf("Failed to init Jaeger: %s", err))
}
defer func() {
if err := tp.Shutdown(ctx); err != nil {
logger.Error(fmt.Sprintf("Error shutting down tracer provider: %v", err))
}
}()
tracer := tp.Tracer(svcName)
qemuCfg := qemu.Config{}
if err := env.Parse(&qemuCfg, env.Options{Prefix: envPrefixQemu}); err != nil {
logger.Error(fmt.Sprintf("failed to load QEMU configuration: %s", err))
return
}
exe, args, err := qemu.ExecutableAndArgs(qemuCfg)
if err != nil {
logger.Error(fmt.Sprintf("failed to parse QEMU configuration: %s", err))
return
}
logger.Info(fmt.Sprintf("%s %s", exe, strings.Join(args, " ")))
managerGRPCConfig := grpc.Config{}
if err := env.Parse(&managerGRPCConfig, env.Options{Prefix: envPrefixGRPC}); err != nil {
logger.Error(fmt.Sprintf("failed to load %s gRPC client configuration : %s", svcName, err))
return
}
managerGRPCClient, managerClient, err := managergrpc.NewManagerClient(managerGRPCConfig)
if err != nil {
logger.Error(err.Error())
return
}
defer managerGRPCClient.Close()
pc, err := managerClient.Process(ctx)
if err != nil {
logger.Error(err.Error())
return
}
if err := pc.Send(&pkgmanager.ClientStreamMessage{Message: &pkgmanager.ClientStreamMessage_Whoami{}}); err != nil {
logger.Error(err.Error())
return
}
eventsChan := make(chan *pkgmanager.ClientStreamMessage)
svc := newService(logger, tracer, qemuCfg, eventsChan)
mc := managerapi.NewClient(pc, svc, eventsChan)
g.Go(func() error {
return mc.Process(ctx)
})
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("%s service terminated: %s", svcName, err))
}
err = internal.DeleteFilesInDir(qemuCfg.TmpFileLoc)
if err != nil {
logger.Error(err.Error())
}
}
func newService(logger *slog.Logger, tracer trace.Tracer, qemuCfg qemu.Config, eventsChan chan *pkgmanager.ClientStreamMessage) manager.Service {
svc := manager.New(qemuCfg, logger, eventsChan)
go svc.RetrieveAgentEventsLogs()
svc = api.LoggingMiddleware(svc, logger)
counter, latency := internal.MakeMetrics(svcName, "api")
svc = api.MetricsMiddleware(svc, counter, latency)
svc = tracing.New(svc, tracer)
return svc
}
+270
View File
@@ -0,0 +1,270 @@
#!/bin/bash
#
# user changeable parameters
#
HDA_FILE="cmd/manager/img/focal-server-cloudimg-amd64.qcow2"
GUEST_SIZE_IN_MB="4096"
SEV_GUEST="1"
SMP_NCPUS="4"
CONSOLE="serial"
VNC_PORT=""
USE_VIRTIO="1"
UEFI_BIOS_CODE="/usr/share/OVMF/OVMF_CODE.fd"
UEFI_BIOS_VARS_ORIG="/usr/share/OVMF/OVMF_VARS.fd"
UEFI_BIOS_VARS_COPY="cmd/manager/img/OVMF_VARS.fd"
CBITPOS=51
HOST_HTTP_PORT=9301
GUEST_HTTP_PORT=9031
HOST_GRPC_PORT=7020
GUEST_GRPC_PORT=7002
ENABLE_FILE_LOG="0"
EXEC_QEMU_CMDLINE="0"
usage() {
echo "$0 [options]"
echo "Available <commands>:"
echo " -hda hard disk ($HDA_FILE)"
echo " -nosev disable sev support"
echo " -mem guest memory"
echo " -smp number of cpus"
echo " -console display console to use (serial or gxl)"
echo " -vnc VNC port to use"
echo " -bios bios to use (default $UEFI_BIOS_CODE)"
echo " -kernel kernel to use"
echo " -initrd initrd to use"
echo " -cdrom CDROM image"
echo " -virtio use virtio devices"
echo " -cbitpos location of the C-bit"
echo " -hosthttp host http port"
echo " -guesthttp guest http port"
echo " -hostgrpc host grpc port"
echo " -guestgrpc guest grpc port"
echo " -origuefivars UEFI BIOS vars original file (default $UEFI_BIOS_VARS_ORIG)"
echo " -copyuefivars UEFI BIOS vars copy file (default $UEFI_BIOS_VARS_COPY)"
echo " -exec execute the QEMU command (default $EXEC_QEMU_CMDLINE)"
echo " -filelog enable/disable QEMU cmd line file log (default: $ENABLE_FILE_LOG)"
exit 1
}
while [[ $1 != "" ]]; do
case "$1" in
-hda)
HDA_FILE=${2}
shift
;;
-nosev)
SEV_GUEST="0"
;;
-mem)
GUEST_SIZE_IN_MB=${2}
shift
;;
-console)
CONSOLE=${2}
shift
;;
-smp)
SMP_NCPUS=$2
shift
;;
-vnc)
VNC_PORT=$2
shift
;;
-bios)
UEFI_BIOS_CODE=$2
shift
;;
-initrd)
INITRD_FILE=$2
shift
;;
-kernel)
KERNEL_FILE=$2
shift
;;
-cdrom)
CDROM_FILE=$2
shift
;;
-virtio)
USE_VIRTIO="1"
;;
-cbitpos)
CBITPOS=$2
shift
;;
-hosthttp)
HOST_HTTP_PORT=$2
shift
;;
-guesthttp)
GUEST_HTTP_PORT=$2
shift
;;
-guestgrpc)
GUEST_GRPC_PORT=$2
shift
;;
-hostgrpc)
HOST_GRPC_PORT=$2
shift
;;
-origuefivars)
UEFI_BIOS_VARS_ORIG=$2
shift
;;
-copyuefivars)
UEFI_BIOS_VARS_COPY=$2
shift
;;
-exec)
EXEC_QEMU_CMDLINE="1"
;;
-filelog)
ENABLE_FILE_LOG="1"
;;
*)
usage;;
esac
shift
done
#
# func definitions
#
add_opts() {
echo -n "$* " >> ${QEMU_CMDLINE}
}
run_cmd() {
if ! "$@"; then
echo "Command '$*' failed"
exit 1
fi
}
# copy BIOS variables to new dest for VM use without modifying the original ones
cp "$UEFI_BIOS_VARS_ORIG" "$UEFI_BIOS_VARS_COPY"
#
# Qemu cmd line construction
#
# we add all the qemu command line options into a file
QEMU_CMDLINE=/tmp/cmdline.$$
rm -rf ${QEMU_CMDLINE}
add_opts "$(which qemu-system-x86_64)"
# Basic virtual machine property
add_opts "-enable-kvm -cpu EPYC -machine q35"
# add number of VCPUs
[ -n "$SMP_NCPUS" ] && add_opts "-smp ${SMP_NCPUS},maxcpus=64"
# define guest memory
add_opts "-m ${GUEST_SIZE_IN_MB}M,slots=5,maxmem=30G"
# The OVMF binary, including the non-volatile variable store, appears as a
# "normal" qemu drive on the host side, and it is exposed to the guest as a
# persistent flash device.
add_opts "-drive if=pflash,format=raw,unit=0,file=${UEFI_BIOS_CODE},readonly=on"
add_opts "-drive if=pflash,format=raw,unit=1,file=${UEFI_BIOS_VARS_COPY}"
# add CDROM if specified
[ -n "$CDROM_FILE" ] && add_opts "-drive file=${CDROM_FILE},media=cdrom -boot d"
add_opts "-netdev user,id=vmnic,hostfwd=tcp::2222-:22,hostfwd=tcp::$HOST_HTTP_PORT-:$GUEST_HTTP_PORT,hostfwd=tcp::$HOST_GRPC_PORT-:$GUEST_GRPC_PORT"
add_opts "-device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile="
# If harddisk file is specified then add the HDD drive
if [ -n "$HDA_FILE" ]; then
if [ "$USE_VIRTIO" = "1" ]; then
if [[ ${HDA_FILE} = *"qcow2" ]]; then
add_opts "-drive file=${HDA_FILE},if=none,id=disk0,format=qcow2"
else
add_opts "-drive file=${HDA_FILE},if=none,id=disk0,format=raw"
fi
add_opts "-device virtio-scsi-pci,id=scsi,disable-legacy=on,iommu_platform=true"
add_opts "-device scsi-hd,drive=disk0"
else
if [[ ${HDA_FILE} = *"qcow2" ]]; then
add_opts "-drive file=${HDA_FILE},format=qcow2"
else
add_opts "-drive file=${HDA_FILE},format=raw"
fi
fi
fi
# If this is SEV guest then add the encryption device objects to enable support
if [ ${SEV_GUEST} = "1" ]; then
add_opts "-object sev-guest,id=sev0,cbitpos=${CBITPOS},reduced-phys-bits=1"
add_opts "-machine memory-encryption=sev0"
fi
# if console is serial then disable graphical interface
if [ "${CONSOLE}" = "serial" ]; then
add_opts "-nographic"
else
add_opts "-vga ${CONSOLE}"
fi
# if -kernel arg is specified then use the kernel provided in command line for boot
if [ "${KERNEL_FILE}" != "" ]; then
add_opts "-kernel $KERNEL_FILE"
add_opts "-append \"console=ttyS0 earlyprintk=serial root=/dev/sda2\""
[ -n "$INITRD_FILE" ] && add_opts "-initrd ${INITRD_FILE}"
fi
# start vnc server
[ -n "$VNC_PORT" ] && add_opts "-vnc :${VNC_PORT}" && echo "Starting VNC on port ${VNC_PORT}"
# start monitor on pty
add_opts "-monitor pty"
#
# Qemu cmd line log
#
# Set the log file path if ENABLE_FILE_LOG is 1
if [ "$ENABLE_FILE_LOG" = "1" ]; then
LOG_FILE=$(pwd)/stdout.log
# Save the command line args into log file
cat "$QEMU_CMDLINE" > "$LOG_FILE"
echo >> "$LOG_FILE"
fi
# Log the command line to the console
cat "$QEMU_CMDLINE"
#
# Qemu cmd line execution
#
if [[ "${EXEC_QEMU_CMDLINE}" = "0" ]]; then
exit 0
fi
# map CTRL-C to CTRL ]
echo "Mapping CTRL-C to CTRL-]"
stty intr ^]
echo "Launching VM ..."
if [ "$ENABLE_FILE_LOG" = "1" ]; then
bash ${QEMU_CMDLINE} 2>&1 | tee -a "${LOG_FILE}"
else
bash ${QEMU_CMDLINE} 2>&1
fi
# restore the mapping
stty intr ^c
rm -rf ${QEMU_CMDLINE}
+62
View File
@@ -0,0 +1,62 @@
#!/bin/bash
# Set your default values for sudo and sev
sudo_option=false
sev_option=false
# Parse command line arguments
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
--sudo)
sudo_option=true
shift
;;
--sev)
sev_option=true
shift
;;
*)
echo "Unknown option: $key"
exit 1
;;
esac
done
build_qemu_command() {
local qemu_command="/usr/bin/qemu-system-x86_64 -enable-kvm -machine q35 -cpu EPYC -smp 4,maxcpus=64 -m 2048M,slots=5,maxmem=30G -drive if=pflash,format=raw,unit=0,file=$MANAGER_QEMU_OVMF_CODE_FILE,readonly=on -drive if=pflash,format=raw,unit=1,file=img/OVMF_VARS.fd -device virtio-scsi-pci,id=scsi,disable-legacy=on,iommu_platform=true -drive file=img/focal-server-cloudimg-amd64.img,if=none,id=disk0,format=qcow2 -device scsi-hd,drive=disk0 -netdev user,id=vmnic,hostfwd=tcp::2222-:22,hostfwd=tcp::9301-:9031,hostfwd=tcp::7020-:7002 -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= -nographic -monitor pty"
if [ "$sev_option" = true ]; then
qemu_command="$qemu_command -object sev-guest,id=sev0,cbitpos=51,reduced-phys-bits=1 -machine memory-encryption=sev0"
fi
echo "$qemu_command"
}
if [ ! -f "img/OVMF_VARS.fd" ]; then
cp "$MANAGER_QEMU_OVMF_VARS_FILE" "img/OVMF_VARS.fd"
echo "Copied $MANAGER_QEMU_OVMF_VARS_FILE to img/OVMF_VARS.fd"
else
echo "img/OVMF_VARS.fd already exists. No need to copy."
fi
echo "Launching VM ..."
qemu_command=$(build_qemu_command)
echo "$qemu_command"
echo "Mapping CTRL-C to CTRL-]"
stty intr ^]
if [ "$sudo_option" = true ]; then
# Split the command and arguments into an array; << operator is known as a "here string"
IFS=" " read -r -a qemu_command_array <<< "$qemu_command"
# Treat each element in the array as a separate word, preserving spaces within each element
sudo "${qemu_command_array[@]}"
else
$qemu_command
fi
# Restore the mapping
stty intr ^c
+62
View File
@@ -0,0 +1,62 @@
<domain type="kvm">
<name>QEmu-alpine-standard-x86_64</name>
<uuid>c7a5fdbd-cdaf-9455-926a-d65c16db1809</uuid>
<metadata>
<libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
<libosinfo:os id="http://alpinelinux.org/alpinelinux/3.15"/>
</libosinfo:libosinfo>
</metadata>
<memory unit="KiB">4194304</memory>
<currentMemory unit="KiB">4194304</currentMemory>
<vcpu placement="static">1</vcpu>
<os>
<type arch="x86_64" machine="q35">hvm</type>
<bootmenu enable="yes"/>
<loader readonly="yes" type="pflash">/usr/share/OVMF/OVMF_CODE.fd</loader>
<nvram template='/usr/share/OVMF/OVMF_VARS.fd'>./img/OVMF_VARS.fd</nvram>
<!-- <boot dev='hd'/> -->
</os>
<features>
<acpi/>
<apic/>
<vmport state="off"/>
</features>
<cpu mode="host-passthrough" check="none" migratable="on"/>
<clock offset="utc">
<timer name="rtc" tickpolicy="catchup"/>
<timer name="pit" tickpolicy="delay"/>
<timer name="hpet" present="no"/>
</clock>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<pm>
<suspend-to-mem enabled="no"/>
<suspend-to-disk enabled="no"/>
</pm>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type="file" device="disk">
<driver name="qemu" type="qcow2" discard="unmap"/>
<source file="./img/focal-server-cloudimg-amd64.qcow2"/>
<target dev="vda" bus="virtio"/>
<address type="pci" domain="0x0000" bus="0x04" slot="0x00" function="0x0"/>
<boot order="1"/>
</disk>
<graphics type="spice" autoport="yes">
<listen type="address"/>
<image compression="off"/>
</graphics>
<video>
<model type="qxl" ram="65536" vram="65536" vgamem="16384" heads="1" primary="yes"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x01" function="0x0"/>
</video>
<interface type="network">
<mac address="52:54:00:03:7b:5f"/>
<source network="default"/>
<model type="virtio"/>
<address type="pci" domain="0x0000" bus="0x01" slot="0x00" function="0x0"/>
</interface>
</devices>
</domain>
+6
View File
@@ -0,0 +1,6 @@
<pool type="dir">
<name>virtimages</name>
<target>
<path>./img</path>
</target>
</pool>
+15
View File
@@ -0,0 +1,15 @@
<volume>
<name>boot.img</name>
<allocation>0</allocation>
<capacity unit="G">1</capacity>
<target>
<format type="qcow2"/>
<path>./img/boot.img</path>
<permissions>
<owner>107</owner>
<group>107</group>
<mode>0744</mode>
<label>virt_image_t</label>
</permissions>
</target>
</volume>
-4
View File
@@ -1,4 +0,0 @@
// Package api contains API-related concerns: endpoint
// definitions, middlewares, and all resource representations.
package api
-106
View File
@@ -1,106 +0,0 @@
package api
import (
"context"
"github.com/go-kit/kit/endpoint"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/ultravioletrs/cocos/computations"
)
func create(svc computations.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(createReq)
if err := req.validate(); err != nil {
return createRes{}, err
}
cid, err := svc.CreateComputation(ctx, req.token, req.computation)
if err != nil {
return createRes{}, err
}
ret := createRes{
ID: cid,
created: true,
}
return ret, nil
}
}
func view(svc computations.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(viewReq)
if err := req.validate(); err != nil {
return viewRes{}, err
}
computation, err := svc.ViewComputation(ctx, req.token, req.id)
if err != nil {
return createRes{}, err
}
ret := viewRes{
Computation: computation,
}
return ret, nil
}
}
func list(svc computations.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(listReq)
if err := req.validate(); err != nil {
return listRes{}, err
}
res, err := svc.ListComputations(ctx, req.token, req.meta)
if err != nil {
return listRes{}, err
}
ret := listRes{
Page: res,
}
return ret, nil
}
}
func update(svc computations.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(updateReq)
if err := req.validate(); err != nil {
return nil, err
}
computation := computations.Computation{
ID: req.id,
Name: req.Name,
Description: req.Description,
Metadata: req.Metadata,
}
if err := svc.UpdateComputation(ctx, req.token, computation); err != nil {
return nil, err
}
res := createRes{ID: req.id, created: false}
return res, nil
}
}
func remove(svc computations.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(viewReq)
err := req.validate()
if err == errors.ErrNotFound {
return removeRes{}, nil
}
if err != nil {
return nil, err
}
if err := svc.RemoveComputation(ctx, req.token, req.id); err != nil {
return nil, err
}
return removeRes{}, nil
}
}
-84
View File
@@ -1,84 +0,0 @@
//go:build !test
package api
import (
"context"
"fmt"
"time"
log "github.com/mainflux/mainflux/logger"
"github.com/ultravioletrs/cocos/computations"
)
var _ computations.Service = (*loggingMiddleware)(nil)
type loggingMiddleware struct {
logger log.Logger
svc computations.Service
}
// LoggingMiddleware adds logging facilities to the core service.
func LoggingMiddleware(svc computations.Service, logger log.Logger) computations.Service {
return &loggingMiddleware{logger, svc}
}
func (lm *loggingMiddleware) CreateComputation(ctx context.Context, token string, computation computations.Computation) (id string, err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method create_computation for user %s took %s to complete", token, time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
}(time.Now())
return lm.svc.CreateComputation(ctx, token, computation)
}
func (lm *loggingMiddleware) ViewComputation(ctx context.Context, token, id string) (c computations.Computation, err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method view_computation for user %s took %s to complete", token, time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
}(time.Now())
return lm.svc.ViewComputation(ctx, token, id)
}
func (lm *loggingMiddleware) ListComputations(ctx context.Context, token string, meta computations.PageMetadata) (page computations.Page, err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method list_computations for user %s took %s to complete", token, time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
}(time.Now())
return lm.svc.ListComputations(ctx, token, meta)
}
func (lm *loggingMiddleware) UpdateComputation(ctx context.Context, token string, computation computations.Computation) (err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method update_computation for user %s took %s to complete", token, time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
}(time.Now())
return lm.svc.UpdateComputation(ctx, token, computation)
}
func (lm *loggingMiddleware) RemoveComputation(ctx context.Context, token, id string) (err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method remove_computation for user %s took %s to complete", token, time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
}(time.Now())
return lm.svc.RemoveComputation(ctx, token, id)
}
-68
View File
@@ -1,68 +0,0 @@
//go:build !test
package api
import (
"context"
"time"
"github.com/go-kit/kit/metrics"
"github.com/ultravioletrs/cocos/computations"
)
var _ computations.Service = (*metricsMiddleware)(nil)
type metricsMiddleware struct {
counter metrics.Counter
latency metrics.Histogram
svc computations.Service
}
// MetricsMiddleware instruments core service by tracking request count and latency.
func MetricsMiddleware(svc computations.Service, counter metrics.Counter, latency metrics.Histogram) computations.Service {
return &metricsMiddleware{
counter: counter,
latency: latency,
svc: svc,
}
}
func (ms *metricsMiddleware) CreateComputation(ctx context.Context, token string, computation computations.Computation) (string, error) {
defer func(begin time.Time) {
ms.counter.With("method", "create_computation").Add(1)
ms.latency.With("method", "create_computation").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.CreateComputation(ctx, token, computation)
}
func (ms *metricsMiddleware) ViewComputation(ctx context.Context, token, id string) (computations.Computation, error) {
defer func(begin time.Time) {
ms.counter.With("method", "view_computation").Add(1)
ms.latency.With("method", "view_computation").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.ViewComputation(ctx, token, id)
}
func (ms *metricsMiddleware) ListComputations(ctx context.Context, token string, meta computations.PageMetadata) (page computations.Page, err error) {
defer func(begin time.Time) {
ms.counter.With("method", "list_computations").Add(1)
ms.latency.With("method", "list_computations").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.ListComputations(ctx, token, meta)
}
func (ms *metricsMiddleware) UpdateComputation(ctx context.Context, token string, computation computations.Computation) error {
defer func(begin time.Time) {
ms.counter.With("method", "update_computations").Add(1)
ms.latency.With("method", "update_computations").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.UpdateComputation(ctx, token, computation)
}
func (ms *metricsMiddleware) RemoveComputation(ctx context.Context, token, id string) error {
defer func(begin time.Time) {
ms.counter.With("method", "remove_computation").Add(1)
ms.latency.With("method", "remove_computation").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.RemoveComputation(ctx, token, id)
}
-42
View File
@@ -1,42 +0,0 @@
package api
import "github.com/ultravioletrs/cocos/computations"
type createReq struct {
computation computations.Computation
token string
}
func (req createReq) validate() error {
return req.computation.Validate()
}
type viewReq struct {
token string
id string
}
func (req viewReq) validate() error {
return nil
}
type listReq struct {
token string
meta computations.PageMetadata
}
func (req listReq) validate() error {
return nil
}
type updateReq struct {
token string
id string
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
func (req updateReq) validate() error {
return nil
}
-85
View File
@@ -1,85 +0,0 @@
package api
import (
"fmt"
"net/http"
"github.com/ultravioletrs/cocos/computations"
)
type createRes struct {
ID string
created bool
}
func (res createRes) Code() int {
if res.created {
return http.StatusCreated
}
return http.StatusOK
}
func (res createRes) Headers() map[string]string {
if res.created {
return map[string]string{
"Location": fmt.Sprintf("/computations/%s", res.ID),
}
}
return map[string]string{}
}
func (res createRes) Empty() bool {
return true
}
type viewRes struct {
computations.Computation
}
func (res viewRes) Code() int {
return http.StatusOK
}
func (res viewRes) Headers() map[string]string {
return map[string]string{}
}
func (res viewRes) Empty() bool {
return false
}
type errorRes struct {
Err string `json:"error"`
}
type listRes struct {
computations.Page
}
func (res listRes) Code() int {
return http.StatusOK
}
func (res listRes) Headers() map[string]string {
return map[string]string{}
}
func (res listRes) Empty() bool {
return false
}
type removeRes struct{}
func (res removeRes) Code() int {
return http.StatusNoContent
}
func (res removeRes) Headers() map[string]string {
return map[string]string{}
}
func (res removeRes) Empty() bool {
return true
}
-201
View File
@@ -1,201 +0,0 @@
package api
import (
"context"
"encoding/json"
"net/http"
"strings"
kithttp "github.com/go-kit/kit/transport/http"
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
log "github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
opentracing "github.com/opentracing/opentracing-go"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/ultravioletrs/cocos/computations"
"github.com/ultravioletrs/cocos/internal/apiutil"
httputil "github.com/ultravioletrs/cocos/internal/http"
)
const (
contentType = "application/json"
offsetKey = "offset"
limitKey = "limit"
orderKey = "order"
dirKey = "dir"
metadataKey = "metadata"
defOffset = 0
defLimit = 10
bearerPrefix = "Bearer "
)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc computations.Service, tracer opentracing.Tracer, logger log.Logger) http.Handler {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
}
mux := bone.New()
mux.Post("/computations", kithttp.NewServer(
// kitot.TraceServer(tracer, "register")(createComputation(svc)),
create(svc),
decodeCreate,
encodeResponse,
opts...,
))
mux.Get("/computations", kithttp.NewServer(
// kitot.TraceServer(tracer, "register")(createComputation(svc)),
list(svc),
decodeList,
encodeResponse,
opts...,
))
mux.Get("/computations/:id", kithttp.NewServer(
view(svc),
decodeView,
encodeResponse,
opts...,
))
mux.Put("/computations/:id", kithttp.NewServer(
update(svc),
decodeUpdate,
encodeResponse,
opts...,
))
mux.Delete("/computations/:id", kithttp.NewServer(
remove(svc),
decodeView,
encodeResponse,
opts...,
))
mux.GetFunc("/health", httputil.Health("computations", "Computation management service"))
mux.Handle("/metrics", promhttp.Handler())
return mux
}
func decodeCreate(_ context.Context, r *http.Request) (interface{}, error) {
req := createReq{
token: extractBearerToken(r),
}
if err := json.NewDecoder(r.Body).Decode(&req.computation); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
return req, nil
}
func decodeList(_ context.Context, r *http.Request) (interface{}, error) {
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}
or, err := apiutil.ReadStringQuery(r, orderKey, "")
if err != nil {
return nil, err
}
d, err := apiutil.ReadStringQuery(r, dirKey, "")
if err != nil {
return nil, err
}
m, err := apiutil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}
req := listReq{
token: extractBearerToken(r),
meta: computations.PageMetadata{
Offset: o,
Limit: l,
Order: or,
Dir: d,
Metadata: m,
},
}
return req, nil
}
func decodeView(_ context.Context, r *http.Request) (interface{}, error) {
req := viewReq{
token: extractBearerToken(r),
id: bone.GetValue(r, "id"),
}
return req, nil
}
func decodeUpdate(_ context.Context, r *http.Request) (interface{}, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, errors.ErrUnsupportedContentType
}
req := updateReq{
token: extractBearerToken(r),
id: bone.GetValue(r, "id"),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
return req, nil
}
func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
if ar, ok := response.(mainflux.Response); ok {
for k, v := range ar.Headers() {
w.Header().Set(k, v)
}
w.Header().Set("Content-Type", contentType)
w.WriteHeader(ar.Code())
if ar.Empty() {
return nil
}
}
return json.NewEncoder(w).Encode(response)
}
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrInvalidQueryParams),
errors.Contains(err, errors.ErrMalformedEntity):
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errors.ErrCreateEntity),
errors.Contains(err, errors.ErrUpdateEntity),
errors.Contains(err, errors.ErrViewEntity),
errors.Contains(err, errors.ErrRemoveEntity):
w.WriteHeader(http.StatusInternalServerError)
default:
w.WriteHeader(http.StatusInternalServerError)
}
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(errorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
}
func extractBearerToken(r *http.Request) string {
token := r.Header.Get("Authorization")
if !strings.HasPrefix(token, bearerPrefix) {
return ""
}
return strings.TrimPrefix(token, bearerPrefix)
}
-51
View File
@@ -1,51 +0,0 @@
package computations
import (
"context"
"time"
)
type Computation struct {
ID string `json:"id,omitempty" db:"id"`
Name string `json:"name,omitempty" db:"name"`
Description string `json:"description,omitempty" db:"description"`
Status string `json:"status,omitempty" db:"status"`
Owner string `json:"owner,omitempty" db:"owner"`
StartTime time.Time `json:"start_time,omitempty" db:"start_time"`
EndTime time.Time `json:"end_time,omitempty" db:"end_time"`
Datasets []string `json:"datasets,omitempty" db:"datasets"`
Algorithms []string `json:"algorithms,omitempty" db:"algorithms"`
DatasetProviders []string `json:"dataset_providers,omitempty" db:"dataset_providers"`
AlgorithmProviders []string `json:"algorithm_providers,omitempty" db:"algorithm_providers"`
Ttl int `json:"ttl,omitempty" db:"ttl"`
Metadata Metadata `json:"metadata,omitempty" db:"metadata"`
}
type Metadata map[string]interface{}
type PageMetadata struct {
Total uint64 `json:"total,omitempty"`
Offset uint64 `json:"offset,omitempty"`
Limit uint64 `json:"limit,omitempty"`
Name string `json:"name,omitempty"`
Order string `json:"order,omitempty"`
Dir string `json:"dir,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
}
type Page struct {
PageMetadata
Computations []Computation `json:"computations,omitempty"`
}
func (c Computation) Validate() error {
return nil
}
type Repository interface {
Save(ctx context.Context, c Computation) (string, error)
View(ctx context.Context, id string) (Computation, error)
RetrieveAll(ctx context.Context, owner string, pm PageMetadata) (Page, error)
Update(ctx context.Context, c Computation) error
Delete(ctx context.Context, id string) error
}
-4
View File
@@ -1,4 +0,0 @@
// Package computations contains domain concept definitions
// needed to support Computations service functionality.
package computations
-355
View File
@@ -1,355 +0,0 @@
package postgres
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"strings"
"time"
"github.com/lib/pq"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/ultravioletrs/cocos/computations"
db "github.com/ultravioletrs/cocos/internal/db"
)
const (
errInvalid = "invalid_text_representation"
errTruncation = "string_data_right_truncation"
errDuplicate = "unique_violation"
)
var _ computations.Repository = (*computationRepo)(nil)
type computationRepo struct {
db db.Database
}
func NewRepository(db db.Database) computations.Repository {
return computationRepo{
db: db,
}
}
func (repo computationRepo) Save(ctx context.Context, c computations.Computation) (string, error) {
q := `INSERT INTO computations (id, name, description, status, owner, start_time, end_time, datasets, algorithms, dataset_providers, algorithm_providers, ttl, metadata)
VALUES (:id, :name, :description, :status, :owner, :start_time, :end_time, :datasets, :algorithms, :dataset_providers, :algorithm_providers, :ttl, :metadata) RETURNING id`
comp, err := fromComputation(c)
if err != nil {
return "", err
}
row, err := repo.db.NamedQueryContext(ctx, q, comp)
if err != nil {
pqErr, ok := err.(*pq.Error)
if ok {
switch pqErr.Code.Name() {
case errInvalid, errTruncation:
return "", errors.Wrap(errors.ErrMalformedEntity, err)
case errDuplicate:
return "", errors.Wrap(errors.ErrConflict, err)
}
}
return "", errors.Wrap(errors.ErrCreateEntity, err)
}
defer row.Close()
row.Next()
var id string
if err := row.Scan(&id); err != nil {
return "", err
}
return id, nil
}
func (repo computationRepo) View(ctx context.Context, id string) (computations.Computation, error) {
q := `SELECT id, name, description, status, owner, start_time, end_time, datasets,
algorithms, dataset_providers, algorithm_providers, ttl, metadata
FROM computations
WHERE id = $1`
c := dbComputation{
ID: id,
}
if err := repo.db.QueryRowxContext(ctx, q, id).StructScan(&c); err != nil {
if err == sql.ErrNoRows {
return computations.Computation{}, errors.Wrap(errors.ErrNotFound, err)
}
return computations.Computation{}, errors.Wrap(errors.ErrViewEntity, err)
}
return toComputation(c)
}
func (repo computationRepo) RetrieveAll(ctx context.Context, owner string, pm computations.PageMetadata) (computations.Page, error) {
nq, name := getNameQuery(pm.Name)
oq := getOrderQuery(pm.Order)
dq := getDirQuery(pm.Dir)
m, mq, err := getMetadataQuery(pm.Metadata)
if err != nil {
return computations.Page{}, errors.Wrap(errors.ErrViewEntity, err)
}
var query []string
if mq != "" {
query = append(query, mq)
}
if nq != "" {
query = append(query, nq)
}
var whereClause string
if len(query) > 0 {
whereClause = fmt.Sprintf(" WHERE %s", strings.Join(query, " AND "))
}
q := `SELECT id, name, description, status, owner, start_time, end_time, datasets,
algorithms, dataset_providers, algorithm_providers, ttl, metadata
FROM computations %s
ORDER BY %s %s LIMIT :limit OFFSET :offset`
q = fmt.Sprintf(q, whereClause, oq, dq)
params := map[string]interface{}{
"owner": owner,
"limit": pm.Limit,
"offset": pm.Offset,
"name": name,
"metadata": m,
}
rows, err := repo.db.NamedQueryContext(ctx, q, params)
if err != nil {
return computations.Page{}, errors.Wrap(errors.ErrViewEntity, err)
}
defer rows.Close()
var items []computations.Computation
for rows.Next() {
dbc := dbComputation{Owner: owner}
if err := rows.StructScan(&dbc); err != nil {
return computations.Page{}, errors.Wrap(errors.ErrViewEntity, err)
}
c, err := toComputation(dbc)
if err != nil {
return computations.Page{}, err
}
items = append(items, c)
}
cq := fmt.Sprintf(`SELECT COUNT(*) FROM computations %s;`, whereClause)
total, err := repo.total(ctx, cq, params)
if err != nil {
return computations.Page{}, errors.Wrap(errors.ErrViewEntity, err)
}
page := computations.Page{
Computations: items,
PageMetadata: computations.PageMetadata{
Total: total,
Offset: pm.Offset,
Limit: pm.Limit,
Order: pm.Order,
Dir: pm.Dir,
},
}
return page, nil
}
func (repo computationRepo) Update(ctx context.Context, c computations.Computation) error {
q := `UPDATE computations SET name = :name, metadata = :metadata, description = :description WHERE id = :id;`
dbcpt, err := toDBComputation(c)
if err != nil {
return errors.Wrap(errors.ErrUpdateEntity, err)
}
res, errdb := repo.db.NamedExecContext(ctx, q, dbcpt)
if errdb != nil {
pqErr, ok := errdb.(*pq.Error)
if ok {
switch pqErr.Code.Name() {
case errInvalid, errTruncation:
return errors.Wrap(errors.ErrMalformedEntity, errdb)
}
}
return errors.Wrap(errors.ErrUpdateEntity, errdb)
}
cnt, errdb := res.RowsAffected()
if errdb != nil {
return errors.Wrap(errors.ErrUpdateEntity, errdb)
}
if cnt == 0 {
return errors.ErrNotFound
}
return nil
}
func (repo computationRepo) Delete(ctx context.Context, id string) error {
q := `DELETE FROM computations WHERE id = :id`
c := dbComputation{
ID: id,
}
if _, err := repo.db.NamedExecContext(ctx, q, c); err != nil {
if err == sql.ErrNoRows {
return errors.Wrap(errors.ErrNotFound, err)
}
return errors.Wrap(errors.ErrViewEntity, err)
}
return nil
}
func (repo computationRepo) total(ctx context.Context, query string, params interface{}) (uint64, error) {
rows, err := repo.db.NamedQueryContext(ctx, query, params)
if err != nil {
return 0, err
}
defer rows.Close()
total := uint64(0)
if rows.Next() {
if err := rows.Scan(&total); err != nil {
return 0, err
}
}
return total, nil
}
type dbComputation struct {
ID string `db:"id"`
Name string `db:"name"`
Description string `db:"description"`
Status string `db:"status"`
Owner string `db:"owner"`
StartTime time.Time `db:"start_time"`
EndTime time.Time `db:"end_time"`
Datasets pq.StringArray `db:"datasets"`
Algorithms pq.StringArray `db:"algorithms"`
DatasetProviders pq.StringArray `db:"dataset_providers"`
AlgorithmProviders pq.StringArray `db:"algorithm_providers"`
Ttl int `db:"ttl"`
Metadata []byte `db:"metadata"`
}
func toComputation(c dbComputation) (computations.Computation, error) {
var metadata map[string]interface{}
if c.Metadata != nil {
if err := json.Unmarshal([]byte(c.Metadata), &metadata); err != nil {
return computations.Computation{}, errors.Wrap(errors.ErrMalformedEntity, err)
}
}
ret := computations.Computation{
ID: c.ID,
Name: c.Name,
Description: c.Description,
Status: c.Status,
Owner: c.Owner,
StartTime: c.StartTime,
EndTime: c.EndTime,
Datasets: c.Datasets,
Algorithms: c.Algorithms,
DatasetProviders: c.DatasetProviders,
AlgorithmProviders: c.AlgorithmProviders,
Ttl: c.Ttl,
Metadata: metadata,
}
return ret, nil
}
func fromComputation(c computations.Computation) (dbComputation, error) {
metadata := []byte("{}")
if len(c.Metadata) > 0 {
b, err := json.Marshal(c.Metadata)
if err != nil {
return dbComputation{}, errors.Wrap(errors.ErrMalformedEntity, err)
}
metadata = b
}
ret := dbComputation{
ID: c.ID,
Name: c.Name,
Description: c.Description,
Status: c.Status,
Owner: c.Owner,
StartTime: c.StartTime,
EndTime: c.EndTime,
Datasets: c.Datasets,
Algorithms: c.Algorithms,
DatasetProviders: c.DatasetProviders,
AlgorithmProviders: c.AlgorithmProviders,
Ttl: c.Ttl,
Metadata: metadata,
}
return ret, nil
}
func getNameQuery(name string) (string, string) {
if name == "" {
return "", ""
}
name = fmt.Sprintf(`%%%s%%`, strings.ToLower(name))
nq := `LOWER(name) LIKE :name`
return nq, name
}
func getOrderQuery(order string) string {
switch order {
case "name":
return "name"
default:
return "id"
}
}
func getDirQuery(dir string) string {
switch dir {
case "asc":
return "ASC"
default:
return "DESC"
}
}
func getMetadataQuery(m computations.Metadata) ([]byte, string, error) {
mq := ""
mb := []byte("{}")
if len(m) > 0 {
mq = `metadata @> :metadata`
b, err := json.Marshal(m)
if err != nil {
return nil, "", err
}
mb = b
}
return mb, mq, nil
}
func toDBComputation(cpt computations.Computation) (dbComputation, error) {
data := []byte("{}")
if len(cpt.Metadata) > 0 {
b, err := json.Marshal(cpt.Metadata)
if err != nil {
return dbComputation{}, errors.Wrap(errors.ErrMalformedEntity, err)
}
data = b
}
return dbComputation{
ID: cpt.ID,
Owner: cpt.Owner,
Name: cpt.Name,
Description: cpt.Description,
Metadata: data,
}, nil
}
-4
View File
@@ -1,4 +0,0 @@
// Package postgres contains repository implementations using
// PostgreSQL as the underlying database.
package postgres
-32
View File
@@ -1,32 +0,0 @@
package postgres
import migrate "github.com/rubenv/sql-migrate"
var Migrations = &migrate.MemoryMigrationSource{
Migrations: []*migrate.Migration{
{
Id: "computations_1",
Up: []string{
`CREATE TABLE IF NOT EXISTS computations (
id UUID,
owner VARCHAR(255),
name VARCHAR(1025),
description text,
status VARCHAR(255),
start_time timestamp NOT NULL,
end_time timestamp,
datasets text[],
algorithms text[],
dataset_providers text[],
algorithm_providers text[],
ttl integer,
metadata JSON,
PRIMARY KEY (id, owner)
)`,
},
Down: []string{
"DROP TABLE computations",
},
},
},
}
-84
View File
@@ -1,84 +0,0 @@
package computations
import (
"context"
"time"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/ultravioletrs/clients"
)
type Service interface {
CreateComputation(ctx context.Context, token string, computation Computation) (string, error)
ViewComputation(ctx context.Context, token, id string) (Computation, error)
ListComputations(ctx context.Context, token string, meta PageMetadata) (Page, error)
UpdateComputation(ctx context.Context, token string, computation Computation) error
RemoveComputation(ctx context.Context, token, id string) error
}
type service struct {
repo Repository
idp mainflux.IDProvider
auth clients.AuthServiceClient
}
func NewService(repo Repository, idp mainflux.IDProvider, auth clients.AuthServiceClient) Service {
return service{
repo: repo,
idp: idp,
auth: auth,
}
}
func (svc service) CreateComputation(ctx context.Context, token string, computation Computation) (string, error) {
id, err := svc.idp.ID()
if err != nil {
return "", err
}
computation.ID = id
computation.StartTime = time.Now()
return svc.repo.Save(ctx, computation)
}
func (svc service) ViewComputation(ctx context.Context, token string, id string) (Computation, error) {
// Use id as both subject and object as token is currently empty
// c_add policy is an example of acceptable policy from clients service.
if err := svc.authorize(ctx, id, id, "c_add"); err != nil {
return Computation{}, errors.Wrap(errors.ErrAuthentication, err)
}
return svc.repo.View(ctx, id)
}
func (svc service) ListComputations(ctx context.Context, token string, meta PageMetadata) (Page, error) {
return svc.repo.RetrieveAll(ctx, token, meta)
}
func (svc service) UpdateComputation(ctx context.Context, token string, computation Computation) error {
return svc.repo.Update(ctx, computation)
}
func (svc service) RemoveComputation(ctx context.Context, token string, id string) error {
// Use id as both subject and object as token is currently empty
// c_delete policy is an example of acceptable policy from clients service.
if err := svc.authorize(ctx, id, id, "c_delete"); err != nil {
return errors.Wrap(errors.ErrAuthentication, err)
}
return svc.repo.Delete(ctx, id)
}
func (svc service) authorize(ctx context.Context, subject, object, action string) error {
req := &clients.AuthorizeReq{
Sub: subject,
Obj: object,
Act: action,
}
res, err := svc.auth.Authorize(ctx, req)
if err != nil {
return errors.Wrap(errors.ErrAuthorization, err)
}
if !res.GetAuthorized() {
return errors.ErrAuthorization
}
return nil
}
View File
-4
View File
@@ -1,4 +0,0 @@
// Package api contains API-related concerns: endpoint
// definitions, middlewares, and all resource representations.
package api
-115
View File
@@ -1,115 +0,0 @@
package api
import (
"context"
"github.com/go-kit/kit/endpoint"
"github.com/ultravioletrs/cocos/datasets"
)
func createDatasetsEndpoint(svc datasets.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(createReq)
id, err := svc.CreateDataset(ctx, req.dataset)
if err != nil {
return createRes{}, err
}
res := createRes{
ID: id,
created: true,
}
return res, nil
}
}
func viewDatasetsEndpoint(svc datasets.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(viewRequest)
ds, err := svc.ViewDataset(ctx, req.owner, req.id)
if err != nil {
return nil, err
}
res := viewRes{
Dataset: ds,
}
return res, nil
}
}
func listDatasetsEndpoint(svc datasets.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(listResourcesReq)
page, err := svc.ListDatasets(ctx, req.owner, req.pageMetadata)
if err != nil {
return nil, err
}
res := datasetsPageRes{
pageRes: pageRes{
Total: page.Total,
Offset: page.Offset,
Limit: page.Limit,
Order: page.Order,
Dir: page.Dir,
},
Datasets: []datasets.Dataset{},
}
res.Datasets = append(res.Datasets, page.Datasets...)
return res, nil
}
}
func updateDatasetEndpoint(svc datasets.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(updateReq)
dataset := datasets.Dataset{
ID: req.id,
Name: req.Name,
Description: req.Description,
Metadata: req.Metadata,
}
if err := svc.UpdateDataset(ctx, dataset); err != nil {
return nil, err
}
res := createRes{ID: req.id, created: false}
return res, nil
}
}
func uploadDatasetEndpoint(svc datasets.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(uploadReq)
if err := req.validate(); err != nil {
return nil, err
}
if err := svc.UploadDataset(ctx, req.id, req.owner, req.Payload); err != nil {
return nil, err
}
res := createRes{ID: req.id, created: false}
return res, nil
}
}
func removeDatasetEndpoint(svc datasets.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(viewRequest)
if err := svc.RemoveDataset(ctx, req.id); err != nil {
return nil, err
}
return removeRes{}, nil
}
}
-95
View File
@@ -1,95 +0,0 @@
package api
import (
"context"
"fmt"
"time"
log "github.com/mainflux/mainflux/logger"
"github.com/ultravioletrs/cocos/datasets"
)
var _ datasets.Service = (*loggingMiddleware)(nil)
type loggingMiddleware struct {
logger log.Logger
svc datasets.Service
}
// LoggingMiddleware adds logging facilities to the core service.
func LoggingMiddleware(svc datasets.Service, logger log.Logger) datasets.Service {
return &loggingMiddleware{logger, svc}
}
func (lm *loggingMiddleware) CreateDataset(ctx context.Context, dts datasets.Dataset) (id string, err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method create_dataset took %s to complete", time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
}(time.Now())
return lm.svc.CreateDataset(ctx, dts)
}
func (lm *loggingMiddleware) ViewDataset(ctx context.Context, owner, id string) (d datasets.Dataset, err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method view_dataset took %s to complete", time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
}(time.Now())
return lm.svc.ViewDataset(ctx, owner, id)
}
func (lm *loggingMiddleware) ListDatasets(ctx context.Context, owner string, meta datasets.PageMetadata) (page datasets.Page, err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method list_datasets took %s to complete", time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
}(time.Now())
return lm.svc.ListDatasets(ctx, owner, meta)
}
func (lm *loggingMiddleware) UpdateDataset(ctx context.Context, dataset datasets.Dataset) (err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method update_dataset took %s to complete", time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
}(time.Now())
return lm.svc.UpdateDataset(ctx, dataset)
}
func (lm *loggingMiddleware) UploadDataset(ctx context.Context, id, owner string, payload []byte) (err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method upload_dataset took %s to complete", time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
}(time.Now())
return lm.svc.UploadDataset(ctx, id, owner, payload)
}
func (lm *loggingMiddleware) RemoveDataset(ctx context.Context, id string) (err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method remove_dataset took %s to complete", time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
}(time.Now())
return lm.svc.RemoveDataset(ctx, id)
}
-74
View File
@@ -1,74 +0,0 @@
package api
import (
"context"
"time"
"github.com/go-kit/kit/metrics"
"github.com/ultravioletrs/cocos/datasets"
)
var _ datasets.Service = (*metricsMiddleware)(nil)
type metricsMiddleware struct {
counter metrics.Counter
latency metrics.Histogram
svc datasets.Service
}
// MetricsMiddleware instruments core service by tracking request count and latency.
func MetricsMiddleware(svc datasets.Service, counter metrics.Counter, latency metrics.Histogram) datasets.Service {
return &metricsMiddleware{
counter: counter,
latency: latency,
svc: svc,
}
}
func (ms *metricsMiddleware) CreateDataset(ctx context.Context, dts datasets.Dataset) (id string, err error) {
defer func(begin time.Time) {
ms.counter.With("method", "create_dataset").Add(1)
ms.latency.With("method", "create_dataset").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.CreateDataset(ctx, dts)
}
func (ms *metricsMiddleware) ViewDataset(ctx context.Context, owner, id string) (datasets.Dataset, error) {
defer func(begin time.Time) {
ms.counter.With("method", "view_dataset").Add(1)
ms.latency.With("method", "view_dataset").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.ViewDataset(ctx, owner, id)
}
func (ms *metricsMiddleware) ListDatasets(ctx context.Context, owner string, meta datasets.PageMetadata) (page datasets.Page, err error) {
defer func(begin time.Time) {
ms.counter.With("method", "list_datasets").Add(1)
ms.latency.With("method", "list_datasets").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.ListDatasets(ctx, owner, meta)
}
func (ms *metricsMiddleware) UpdateDataset(ctx context.Context, dataset datasets.Dataset) error {
defer func(begin time.Time) {
ms.counter.With("method", "update_datasets").Add(1)
ms.latency.With("method", "update_datasets").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.UpdateDataset(ctx, dataset)
}
func (ms *metricsMiddleware) UploadDataset(ctx context.Context, id, owner string, payload []byte) error {
defer func(begin time.Time) {
ms.counter.With("method", "update_datasets").Add(1)
ms.latency.With("method", "update_datasets").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.UploadDataset(ctx, id, owner, payload)
}
func (ms *metricsMiddleware) RemoveDataset(ctx context.Context, id string) error {
defer func(begin time.Time) {
ms.counter.With("method", "remove_dataset").Add(1)
ms.latency.With("method", "remove_dataset").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.RemoveDataset(ctx, id)
}
-38
View File
@@ -1,38 +0,0 @@
package api
import (
"github.com/ultravioletrs/cocos/datasets"
)
type createReq struct {
dataset datasets.Dataset
token string
}
type listResourcesReq struct {
owner string
pageMetadata datasets.PageMetadata
}
type updateReq struct {
id string
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
type uploadReq struct {
owner string
token string
id string
Payload []byte
}
func (req uploadReq) validate() error {
return nil
}
type viewRequest struct {
id string
owner string
}
-93
View File
@@ -1,93 +0,0 @@
package api
import (
"fmt"
"net/http"
"github.com/ultravioletrs/cocos/datasets"
)
type createRes struct {
ID string
created bool
}
func (res createRes) Code() int {
if res.created {
return http.StatusCreated
}
return http.StatusOK
}
func (res createRes) Headers() map[string]string {
if res.created {
return map[string]string{
"Location": fmt.Sprintf("/datasets/%s", res.ID),
}
}
return map[string]string{}
}
func (res createRes) Empty() bool {
return true
}
type errorRes struct {
Err string `json:"error"`
}
type removeRes struct{}
func (res removeRes) Code() int {
return http.StatusNoContent
}
func (res removeRes) Headers() map[string]string {
return map[string]string{}
}
func (res removeRes) Empty() bool {
return true
}
type viewRes struct {
datasets.Dataset
}
func (res viewRes) Code() int {
return http.StatusOK
}
func (res viewRes) Headers() map[string]string {
return map[string]string{}
}
func (res viewRes) Empty() bool {
return false
}
type datasetsPageRes struct {
pageRes
Datasets []datasets.Dataset `json:"datasets"`
}
func (res datasetsPageRes) Code() int {
return http.StatusOK
}
func (res datasetsPageRes) Headers() map[string]string {
return map[string]string{}
}
func (res datasetsPageRes) Empty() bool {
return false
}
type pageRes struct {
Total uint64 `json:"total"`
Offset uint64 `json:"offset"`
Limit uint64 `json:"limit"`
Order string `json:"order"`
Dir string `json:"direction"`
}
-238
View File
@@ -1,238 +0,0 @@
package api
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
"strings"
kithttp "github.com/go-kit/kit/transport/http"
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/opentracing/opentracing-go"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/ultravioletrs/cocos/datasets"
"github.com/ultravioletrs/cocos/internal/apiutil"
httputil "github.com/ultravioletrs/cocos/internal/http"
)
const (
contentType = "application/json"
offsetKey = "offset"
nameKey = "name"
limitKey = "limit"
orderKey = "order"
dirKey = "dir"
metadataKey = "metadata"
sharedKey = "shared"
defOffset = 0
defLimit = 10
bearerPrefix = "Bearer "
)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc datasets.Service, tracer opentracing.Tracer, logger logger.Logger) http.Handler {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
}
mux := bone.New()
mux.Post("/datasets", kithttp.NewServer(
createDatasetsEndpoint(svc),
decodeCreateDatasets,
encodeResponse,
opts...,
))
mux.Get("/datasets", kithttp.NewServer(
listDatasetsEndpoint(svc),
decodeList,
encodeResponse,
opts...,
))
mux.Get("/datasets/:id", kithttp.NewServer(
viewDatasetsEndpoint(svc),
decodeView,
encodeResponse,
opts...,
))
mux.Put("/datasets/:id", kithttp.NewServer(
updateDatasetEndpoint(svc),
decodeUpdateDataset,
encodeResponse,
opts...,
))
mux.Patch("/datasets/payload/:id", kithttp.NewServer(
uploadDatasetEndpoint(svc),
decodeUploadDataset,
encodeResponse,
opts...,
))
mux.Delete("/datasets/:id", kithttp.NewServer(
removeDatasetEndpoint(svc),
decodeView,
encodeResponse,
opts...,
))
mux.GetFunc("/health", httputil.Health("datasets", "Datasets management service"))
mux.Handle("/metrics", promhttp.Handler())
return mux
}
func decodeCreateDatasets(_ context.Context, r *http.Request) (interface{}, error) {
req := createReq{
token: extractBearerToken(r),
}
if err := json.NewDecoder(r.Body).Decode(&req.dataset); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
return req, nil
}
func decodeList(_ context.Context, r *http.Request) (interface{}, error) {
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}
n, err := apiutil.ReadStringQuery(r, nameKey, "")
if err != nil {
return nil, err
}
or, err := apiutil.ReadStringQuery(r, orderKey, "")
if err != nil {
return nil, err
}
d, err := apiutil.ReadStringQuery(r, dirKey, "")
if err != nil {
return nil, err
}
m, err := apiutil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}
shared, err := apiutil.ReadBoolQuery(r, sharedKey, false)
if err != nil {
return nil, err
}
req := listResourcesReq{
pageMetadata: datasets.PageMetadata{
Offset: o,
Limit: l,
Name: n,
Order: or,
Dir: d,
Metadata: m,
FetchSharedDatasets: shared,
},
}
return req, nil
}
func decodeView(_ context.Context, r *http.Request) (interface{}, error) {
req := viewRequest{
id: bone.GetValue(r, "id"),
}
return req, nil
}
func decodeUpdateDataset(_ context.Context, r *http.Request) (interface{}, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, errors.ErrUnsupportedContentType
}
req := updateReq{
id: bone.GetValue(r, "id"),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
return req, nil
}
func decodeUploadDataset(_ context.Context, r *http.Request) (interface{}, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, errors.ErrUnsupportedContentType
}
payload, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, errors.ErrMalformedEntity
}
defer r.Body.Close()
req := uploadReq{
token: extractBearerToken(r),
id: bone.GetValue(r, "id"),
Payload: payload,
}
return req, nil
}
func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
if ar, ok := response.(mainflux.Response); ok {
for k, v := range ar.Headers() {
w.Header().Set(k, v)
}
w.Header().Set("Content-Type", contentType)
w.WriteHeader(ar.Code())
if ar.Empty() {
return nil
}
}
return json.NewEncoder(w).Encode(response)
}
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrInvalidQueryParams),
errors.Contains(err, errors.ErrMalformedEntity):
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errors.ErrCreateEntity),
errors.Contains(err, errors.ErrUpdateEntity),
errors.Contains(err, errors.ErrViewEntity),
errors.Contains(err, errors.ErrRemoveEntity):
w.WriteHeader(http.StatusInternalServerError)
default:
w.WriteHeader(http.StatusInternalServerError)
}
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(errorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
}
func extractBearerToken(r *http.Request) string {
token := r.Header.Get("Authorization")
if !strings.HasPrefix(token, bearerPrefix) {
return ""
}
return strings.TrimPrefix(token, bearerPrefix)
}
-65
View File
@@ -1,65 +0,0 @@
package datasets
import (
"context"
"time"
)
type Dataset struct {
ID string `json:"id,omitempty" db:"id"`
Token string `json:"token,omitempty" db:"token"`
Name string `json:"name,omitempty" db:"name"`
Description string `json:"description,omitempty" db:"description"`
Owner string `json:"owner,omitempty" db:"owner"`
Size uint64 `json:"size,omitempty" db:"size"`
CreatedAt time.Time `json:"created_at,omitempty" db:"created_at"`
UpdatedAt time.Time `json:"updated_at,omitempty" db:"updated_at"`
Location string `json:"location,omitempty" db:"location"`
Format string `json:"format,omitempty" db:"format"`
Metadata Metadata `json:"metadata,omitempty" db:"metadata"`
Path string `json:"Path,omitempty" db:"path"`
}
type Metadata map[string]interface{}
type PageMetadata struct {
Total uint64 `json:"total,omitempty"`
Offset uint64 `json:"offset,omitempty"`
Limit uint64 `json:"limit,omitempty"`
Name string `json:"name,omitempty"`
Order string `json:"order,omitempty"`
Dir string `json:"dir,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
FetchSharedDatasets bool
}
type Page struct {
PageMetadata
Datasets []Dataset `json:"datasets,omitempty"`
}
func (d Dataset) Validate() error {
return nil
}
// DatasetRepository specifies a dataset persistence API.
type DatasetRepository interface {
// Save persists multiple datasets. Datasets are saved using a transaction. If one dataset
// fails then none will be saved. Successful operation is indicated by non-nil
// error response.
Save(ctx context.Context, dts Dataset) (string, error)
// RetrieveAll retrieves the subset of datasets owned by the specified user
RetrieveByID(ctx context.Context, owner, id string) (Dataset, error)
// RetrieveAll retrieves the subset of datasets owned by the specified user
RetrieveAll(ctx context.Context, owner string, pm PageMetadata) (Page, error)
// Update performs an update to the existing dataset. A non-nil error is
// returned to indicate operation failure.
Update(ctx context.Context, d Dataset) error
// Remove removes the dataset having the provided identifier, that is owned
// by the specified user.
Delete(ctx context.Context, id string) error
}
-4
View File
@@ -1,4 +0,0 @@
// Package dataset contains domain concept definitions
// needed to support dataset service functionality.
package datasets
-360
View File
@@ -1,360 +0,0 @@
package postgres
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"strings"
"time"
"github.com/lib/pq"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/ultravioletrs/cocos/datasets"
db "github.com/ultravioletrs/cocos/internal/db"
)
const (
errDuplicate = "unique_violation"
errInvalid = "invalid_text_representation"
errTruncation = "string_data_right_truncation"
)
var _ datasets.DatasetRepository = (*datasetRepo)(nil)
type datasetRepo struct {
db db.Database
}
// NewRepository returns a new Datasets repository implementation.
func NewRepository(db db.Database) datasets.DatasetRepository {
return datasetRepo{
db: db,
}
}
func (repo datasetRepo) Save(ctx context.Context, dataset datasets.Dataset) (string, error) {
q := `INSERT INTO datasets (id, owner, name, metadata, description, format, location, created_at, updated_at)
VALUES (:id, :owner, :name, :metadata, :description, :format, :location, :created_at, :updated_at) RETURNING id;`
ds, err := fromDataset(dataset)
if err != nil {
return "", errors.Wrap(errors.ErrCreateEntity, err)
}
row, err := repo.db.NamedQueryContext(ctx, q, ds)
if err != nil {
pqErr, ok := err.(*pq.Error)
if ok {
switch pqErr.Code.Name() {
case errInvalid, errTruncation:
return "", errors.Wrap(errors.ErrMalformedEntity, err)
case errDuplicate:
return "", errors.Wrap(errors.ErrConflict, err)
}
}
return "", errors.Wrap(errors.ErrCreateEntity, err)
}
defer row.Close()
row.Next()
var id string
if err := row.Scan(&id); err != nil {
return "", err
}
return id, nil
}
func (repo datasetRepo) RetrieveByID(ctx context.Context, owner, id string) (datasets.Dataset, error) {
q := `SELECT id, name, owner, metadata, description, location, format, created_at, updated_at FROM datasets WHERE id = $1;`
dbds := dbDataset{ID: id}
if err := repo.db.QueryRowxContext(ctx, q, id).StructScan(&dbds); err != nil {
pqErr, ok := err.(*pq.Error)
if err == sql.ErrNoRows || ok && errInvalid == pqErr.Code.Name() {
return datasets.Dataset{}, errors.Wrap(errors.ErrNotFound, err)
}
return datasets.Dataset{}, errors.Wrap(errors.ErrViewEntity, err)
}
return toDataset(dbds)
}
func (repo datasetRepo) RetrieveAll(ctx context.Context, owner string, pm datasets.PageMetadata) (datasets.Page, error) {
nq, name := NameQuery(pm.Name)
oq := OrderQuery(pm.Order)
dq := DirQuery(pm.Dir)
m, mq, err := MetadataQuery(pm.Metadata)
if err != nil {
return datasets.Page{}, errors.Wrap(errors.ErrViewEntity, err)
}
var query []string
if mq != "" {
query = append(query, mq)
}
if nq != "" {
query = append(query, nq)
}
var whereClause string
if len(query) > 0 {
whereClause = fmt.Sprintf(" WHERE %s", strings.Join(query, " AND "))
}
q := `SELECT id, name, COALESCE(description, '') AS description, owner, created_at,
updated_at, location, format, metadata
FROM datasets %s
ORDER BY %s %s LIMIT :limit OFFSET :offset`
q = fmt.Sprintf(q, whereClause, oq, dq)
params := map[string]interface{}{
"owner": owner,
"limit": pm.Limit,
"offset": pm.Offset,
"name": name,
"metadata": m,
}
rows, err := repo.db.NamedQueryContext(ctx, q, params)
if err != nil {
return datasets.Page{}, errors.Wrap(errors.ErrViewEntity, err)
}
defer rows.Close()
var items []datasets.Dataset
for rows.Next() {
dbd := dbDataset{Owner: owner}
if err := rows.StructScan(&dbd); err != nil {
return datasets.Page{}, errors.Wrap(errors.ErrViewEntity, err)
}
ds, err := toDataset(dbd)
if err != nil {
return datasets.Page{}, err
}
items = append(items, ds)
}
cq := fmt.Sprintf(`SELECT COUNT(*) FROM datasets %s;`, whereClause)
total, err := repo.total(ctx, cq, params)
if err != nil {
return datasets.Page{}, errors.Wrap(errors.ErrViewEntity, err)
}
page := datasets.Page{
Datasets: items,
PageMetadata: datasets.PageMetadata{
Total: total,
Offset: pm.Offset,
Limit: pm.Limit,
Order: pm.Order,
Dir: pm.Dir,
},
}
return page, nil
}
func (repo datasetRepo) Update(ctx context.Context, d datasets.Dataset) error {
q := `UPDATE datasets SET name = :name, metadata = :metadata, description = :description WHERE id = :id;`
dbdts, err := toDBDataset(d)
if err != nil {
return errors.Wrap(errors.ErrUpdateEntity, err)
}
res, errdb := repo.db.NamedExecContext(ctx, q, dbdts)
if errdb != nil {
pqErr, ok := errdb.(*pq.Error)
if ok {
switch pqErr.Code.Name() {
case errInvalid, errTruncation:
return errors.Wrap(errors.ErrMalformedEntity, errdb)
}
}
return errors.Wrap(errors.ErrUpdateEntity, errdb)
}
cnt, errdb := res.RowsAffected()
if errdb != nil {
return errors.Wrap(errors.ErrUpdateEntity, errdb)
}
if cnt == 0 {
return errors.ErrNotFound
}
return nil
}
func (repo datasetRepo) Delete(ctx context.Context, id string) error {
q := `DELETE FROM datasets WHERE id = :id`
ds := dbDataset{
ID: id,
}
if _, err := repo.db.NamedExecContext(ctx, q, ds); err != nil {
if err == sql.ErrNoRows {
return errors.Wrap(errors.ErrNotFound, err)
}
return errors.Wrap(errors.ErrViewEntity, err)
}
return nil
}
func (repo datasetRepo) total(ctx context.Context, query string, params interface{}) (uint64, error) {
rows, err := repo.db.NamedQueryContext(ctx, query, params)
if err != nil {
return 0, err
}
defer rows.Close()
total := uint64(0)
if rows.Next() {
if err := rows.Scan(&total); err != nil {
return 0, err
}
}
return total, nil
}
type dbDataset struct {
ID string `db:"id"`
Token string `db:"token"`
Name string `db:"name"`
Description string `db:"description"`
Owner string `db:"owner"`
Size uint64 `db:"size"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
Location string `db:"location"`
Format string `db:"format"`
Metadata []byte `db:"metadata"`
Path string `db:"path"`
}
func toDataset(d dbDataset) (datasets.Dataset, error) {
var metadata map[string]interface{}
if d.Metadata != nil {
if err := json.Unmarshal([]byte(d.Metadata), &metadata); err != nil {
return datasets.Dataset{}, errors.Wrap(errors.ErrMalformedEntity, err)
}
}
ret := datasets.Dataset{
ID: d.ID,
Token: d.Token,
Name: d.Name,
Description: d.Description,
Owner: d.Owner,
Size: d.Size,
CreatedAt: d.CreatedAt,
UpdatedAt: d.UpdatedAt,
Location: d.Location,
Format: d.Format,
Metadata: metadata,
Path: d.Path,
}
return ret, nil
}
func fromDataset(d datasets.Dataset) (dbDataset, error) {
metadata := []byte("{}")
if len(d.Metadata) > 0 {
b, err := json.Marshal(d.Metadata)
if err != nil {
return dbDataset{}, errors.Wrap(errors.ErrMalformedEntity, err)
}
metadata = b
}
ret := dbDataset{
ID: d.ID,
Token: d.Token,
Name: d.Name,
Description: d.Description,
Owner: d.Owner,
Size: d.Size,
CreatedAt: d.CreatedAt,
UpdatedAt: d.UpdatedAt,
Location: d.Location,
Format: d.Format,
Metadata: metadata,
Path: d.Path,
}
return ret, nil
}
func NameQuery(name string) (string, string) {
if name == "" {
return "", ""
}
name = fmt.Sprintf(`%%%s%%`, strings.ToLower(name))
nq := `LOWER(name) LIKE :name`
return nq, name
}
func OrderQuery(order string) string {
switch order {
case "name":
return "name"
default:
return "id"
}
}
func DirQuery(dir string) string {
switch dir {
case "asc":
return "ASC"
default:
return "DESC"
}
}
func MetadataQuery(m datasets.Metadata) ([]byte, string, error) {
mq := ""
mb := []byte("{}")
if len(m) > 0 {
mq = `metadata @> :metadata`
b, err := json.Marshal(m)
if err != nil {
return nil, "", err
}
mb = b
}
return mb, mq, nil
}
func (repo datasetRepo) Remove(ctx context.Context, id string) error {
dbth := dbDataset{
ID: id,
}
q := `DELETE FROM datasets WHERE id = :id`
if _, err := repo.db.NamedExecContext(ctx, q, dbth); err != nil {
return errors.Wrap(errors.ErrRemoveEntity, err)
}
return nil
}
func toDBDataset(ds datasets.Dataset) (dbDataset, error) {
data := []byte("{}")
if len(ds.Metadata) > 0 {
b, err := json.Marshal(ds.Metadata)
if err != nil {
return dbDataset{}, errors.Wrap(errors.ErrMalformedEntity, err)
}
data = b
}
return dbDataset{
ID: ds.ID,
Owner: ds.Owner,
Name: ds.Name,
Description: ds.Description,
Metadata: data,
Size: ds.Size,
}, nil
}
-4
View File
@@ -1,4 +0,0 @@
// Package dataset contains domain concept definitions
// needed to support dataset service functionality.
package postgres
-33
View File
@@ -1,33 +0,0 @@
package postgres
import (
// used to register Postgres driver
_ "github.com/lib/pq"
migrate "github.com/rubenv/sql-migrate"
)
var Migrations = &migrate.MemoryMigrationSource{
Migrations: []*migrate.Migration{
{
Id: "datasets_01",
Up: []string{
`CREATE TABLE IF NOT EXISTS datasets (
id UUID,
name VARCHAR(1025),
owner VARCHAR(255),
description text,
created_at timestamp NOT NULL,
updated_at timestamp NOT NULL,
size INT,
location TEXT,
format VARCHAR(255),
metadata JSON,
PRIMARY KEY (id, owner)
)`,
},
Down: []string{
"DROP TABLE datasets",
},
},
},
}
-101
View File
@@ -1,101 +0,0 @@
package datasets
import (
"context"
"io/fs"
"os"
"path/filepath"
"time"
"github.com/mainflux/mainflux"
)
type datasetsService struct {
repo DatasetRepository
idp mainflux.IDProvider
}
func NewService(repo DatasetRepository, idp mainflux.IDProvider) Service {
return &datasetsService{
repo: repo,
idp: idp,
}
}
// Service specifies an API that must be fulfiled by the domain service
// implementation, and all of its decorators (e.g. logging & metrics).
type Service interface {
// CreateDatasets adds datasets to the user.
CreateDataset(ctx context.Context, dataset Dataset) (string, error)
// ViewDataset retrieves data about the dataset identified with the provided
// ID, that belongs to the user identified by the provided token.
ViewDataset(ctx context.Context, owner, id string) (Dataset, error)
// ListDatasets retrieves data about subset of datasets that belongs to the
// user identified by the provided token.
ListDatasets(ctx context.Context, owner string, meta PageMetadata) (Page, error)
// UpdateDataset updates the dataset identified by the provided ID, that
// belongs to the user identified by the provided token.
UpdateDataset(ctx context.Context, dataset Dataset) error
// UploadDataset uploads the actual dataset content to the dataset path.
UploadDataset(ctx context.Context, id, owner string, payload []byte) error
// RemoveDataset removes the dataset identified with the provided ID, that
// belongs to the user identified by the provided token.
RemoveDataset(ctx context.Context, id string) error
}
func (ds *datasetsService) CreateDataset(ctx context.Context, dataset Dataset) (string, error) {
id, err := ds.idp.ID()
if err != nil {
return "", err
}
dataset.ID = id
dataset.CreatedAt = time.Now()
return ds.repo.Save(ctx, dataset)
}
func (ds *datasetsService) ViewDataset(ctx context.Context, owner, id string) (Dataset, error) {
return ds.repo.RetrieveByID(ctx, owner, id)
}
func (ds *datasetsService) ListDatasets(ctx context.Context, owner string, pm PageMetadata) (Page, error) {
page, err := ds.repo.RetrieveAll(ctx, owner, pm)
if err != nil {
return Page{}, err
}
return page, nil
}
func (ds *datasetsService) UpdateDataset(ctx context.Context, dataset Dataset) error {
return ds.repo.Update(ctx, dataset)
}
func (ds *datasetsService) UploadDataset(ctx context.Context, id, owner string, payload []byte) error {
dataset, err := ds.repo.RetrieveByID(ctx, owner, id)
if err != nil {
return err
}
path := filepath.Join(dataset.Path, dataset.ID)
file, err := os.Create(id)
if err != nil {
return err
}
defer file.Close()
filename := path
err = os.WriteFile(filename, payload, fs.ModePerm)
if err != nil {
return err
}
return os.WriteFile(filename, payload, fs.ModePerm)
}
func (ds *datasetsService) RemoveDataset(ctx context.Context, id string) error {
if err := ds.repo.Delete(ctx, id); err != nil {
return err
}
return ds.repo.Delete(ctx, id)
}
-4
View File
@@ -1,4 +0,0 @@
// Package cocos acts as an umbrella package containing
// multiple microservices and defines shared domain concepts.
package cocos
-42
View File
@@ -1,42 +0,0 @@
# Docker: Environment variables in Compose
## COCOS services
### Computations service
COCOS_COMPUTATIONS_LOG_LEVEL=debug
COCOS_COMPUTATIONS_DB_PORT=5432
COCOS_COMPUTATIONS_DB_USER=cocos
COCOS_COMPUTATIONS_DB_PASS=cocos
COCOS_COMPUTATIONS_DB=computations
COCOS_COMPUTATIONS_HTTP_PORT=9000
### Datasets service
COCOS_DATASETS_LOG_LEVEL=debug
COCOS_DATASETS_DB_PORT=5432
COCOS_DATASETS_DB_USER=cocos
COCOS_DATASETS_DB_PASS=cocos
COCOS_DATASETS_DB=datasets
COCOS_DATASETS_HTTP_PORT=9001
### Clients service
UV_CLIENTS_LOG_LEVEL=debug
UV_CLIENTS_DB_HOST=clients-db
UV_CLIENTS_DB_PORT=5439
UV_CLIENTS_DB_USER=uv
UV_CLIENTS_DB_PASS=uv
UV_CLIENTS_DB=clients
UV_CLIENTS_DB_SSL_MODE=
UV_CLIENTS_DB_SSL_CERT=
UV_CLIENTS_DB_SSL_KEY=
UV_CLIENTS_DB_SSL_ROOT_CERT=
UV_CLIENTS_HTTP_PORT=9191
UV_CLIENTS_GRPC_PORT=9192
UV_CLIENTS_GRPC_TIMEOUT=1s
UV_CLIENTS_SERVER_CERT=
UV_CLIENTS_SERVER_KEY=
# Docker image tag
MF_RELEASE_TAG=latest
# Docker image tag
COCOS_RELEASE_TAG=latest
-19
View File
@@ -1,19 +0,0 @@
FROM golang:1.18-alpine AS builder
ARG SVC
ARG GOARCH
ARG GOARM
ARG VERSION
ARG COMMIT
ARG TIME
WORKDIR /go/src/github.com/ultravioletrs/cocos
COPY . .
RUN apk update \
&& apk add make\
&& make $SVC \
&& mv build/cocos-$SVC /exe
FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=builder /exe /
ENTRYPOINT ["/exe"]
-4
View File
@@ -1,4 +0,0 @@
FROM scratch
ARG SVC
COPY cocos-$SVC /exe
ENTRYPOINT ["/exe"]
-128
View File
@@ -1,128 +0,0 @@
version: "3.7"
networks:
cocos-base-net:
driver: bridge
volumes:
cocos-computations-db-volume:
cocos-datasets-db-volume:
cocos-clients-db-volume:
services:
# CoCoS services
computations-db:
image: postgres:13.3-alpine
container_name: cocos-computations-db
restart: on-failure
environment:
POSTGRES_USER: ${COCOS_COMPUTATIONS_DB_USER}
POSTGRES_PASSWORD: ${COCOS_COMPUTATIONS_DB_PASS}
POSTGRES_DB: ${COCOS_COMPUTATIONS_DB}
networks:
- cocos-base-net
volumes:
- cocos-computations-db-volume:/var/lib/postgresql/data
computations:
image: cocos/computations:${COCOS_RELEASE_TAG}
container_name: cocos-computations
depends_on:
- computations-db
- clients
restart: on-failure
environment:
COCOS_COMPUTATIONS_LOG_LEVEL: ${COCOS_COMPUTATIONS_LOG_LEVEL}
COCOS_COMPUTATIONS_DB_HOST: computations-db
COCOS_COMPUTATIONS_DB_PORT: ${COCOS_COMPUTATIONS_DB_PORT}
COCOS_COMPUTATIONS_DB_USER: ${COCOS_COMPUTATIONS_DB_USER}
COCOS_COMPUTATIONS_DB_PASS: ${COCOS_COMPUTATIONS_DB_PASS}
COCOS_COMPUTATIONS_DB: ${COCOS_COMPUTATIONS_DB}
COCOS_COMPUTATIONS_HTTP_PORT: ${COCOS_COMPUTATIONS_HTTP_PORT}
COCOS_COMPUTATIONS_AUTH_GRPC_URL: clients:${UV_CLIENTS_GRPC_PORT}
COCO_COMPUTATIONS_AUTH_GRPC_TIMEOUT: ${UV_CLIENTS_GRPC_TIMEOUT}
ports:
- ${COCOS_COMPUTATIONS_HTTP_PORT}:${COCOS_COMPUTATIONS_HTTP_PORT}
networks:
- cocos-base-net
datasets-db:
image: postgres:13.3-alpine
container_name: cocos-datasets-db
restart: on-failure
environment:
POSTGRES_USER: ${COCOS_DATASETS_DB_USER}
POSTGRES_PASSWORD: ${COCOS_DATASETS_DB_PASS}
POSTGRES_DB: ${COCOS_DATASETS_DB}
networks:
- cocos-base-net
volumes:
- cocos-datasets-db-volume:/var/lib/postgresql/data
datasets:
image: cocos/datasets:${COCOS_RELEASE_TAG}
container_name: cocos-datasets
depends_on:
- datasets-db
- clients
restart: on-failure
environment:
COCOS_DATASETS_LOG_LEVEL: ${COCOS_DATASETS_LOG_LEVEL}
COCOS_DATASETS_DB_HOST: datasets-db
COCOS_DATASETS_DB_PORT: ${COCOS_DATASETS_DB_PORT}
COCOS_DATASETS_DB_USER: ${COCOS_DATASETS_DB_USER}
COCOS_DATASETS_DB_PASS: ${COCOS_DATASETS_DB_PASS}
COCOS_DATASETS_DB: ${COCOS_DATASETS_DB}
COCOS_DATASETS_HTTP_PORT: ${COCOS_DATASETS_HTTP_PORT}
COCOS_DATASETS_AUTH_GRPC_URL: clients:${UV_CLIENTS_GRPC_PORT}
COCOS_DATASETS_AUTH_GRPC_TIMEOUT: ${UV_CLIENTS_GRPC_TIMEOUT}
ports:
- ${COCOS_DATASETS_HTTP_PORT}:${COCOS_DATASETS_HTTP_PORT}
networks:
- cocos-base-net
clients-db:
image: postgres:13.3-alpine
container_name: cocos-clients-db
restart: on-failure
expose:
- ${UV_CLIENTS_DB_PORT}
environment:
POSTGRES_USER: ${UV_CLIENTS_DB_USER}
POSTGRES_PASSWORD: ${UV_CLIENTS_DB_PASS}
POSTGRES_DB: ${UV_CLIENTS_DB}
networks:
- cocos-base-net
command: -p ${UV_CLIENTS_DB_PORT}
volumes:
- cocos-clients-db-volume:/var/lib/postgresql/data
clients:
image: ultraviolet/clients:${MF_RELEASE_TAG}
container_name: cocos-clients
depends_on:
- clients-db
restart: on-failure
expose:
- ${UV_CLIENTS_GRPC_PORT}
environment:
UV_CLIENTS_LOG_LEVEL: ${UV_CLIENTS_LOG_LEVEL}
UV_CLIENTS_DB_HOST: ${UV_CLIENTS_DB_HOST}
UV_CLIENTS_DB_PORT: ${UV_CLIENTS_DB_PORT}
UV_CLIENTS_DB_USER: ${UV_CLIENTS_DB_USER}
UV_CLIENTS_DB_PASS: ${UV_CLIENTS_DB_PASS}
UV_CLIENTS_DB: ${UV_CLIENTS_DB}
UV_CLIENTS_DB_SSL_MODE: ${UV_CLIENTS_DB_SSL_MODE}
UV_CLIENTS_DB_SSL_CERT: ${UV_CLIENTS_DB_SSL_CERT}
UV_CLIENTS_DB_SSL_KEY: ${UV_CLIENTS_DB_SSL_KEY}
UV_CLIENTS_DB_SSL_ROOT_CERT: ${UV_CLIENTS_DB_SSL_ROOT_CERT}
UV_CLIENTS_HTTP_PORT: ${UV_CLIENTS_HTTP_PORT}
UV_CLIENTS_GRPC_PORT: ${UV_CLIENTS_GRPC_PORT}
UV_CLIENTS_GRPC_TIMEOUT: ${UV_CLIENTS_GRPC_TIMEOUT}
UV_CLIENTS_SERVER_CERT: ${UV_CLIENTS_SERVER_CERT}
UV_CLIENTS_SERVER_KEY: ${UV_CLIENTS_SERVER_KEY}
ports:
- ${UV_CLIENTS_HTTP_PORT}:${UV_CLIENTS_HTTP_PORT}
- ${UV_CLIENTS_GRPC_PORT}:${UV_CLIENTS_GRPC_PORT}
networks:
- cocos-base-net
-16
View File
@@ -1,16 +0,0 @@
version: v0.6.0-alpha.3
log:
level: debug
namespaces:
- id: 0
name: members
serve:
read:
host: 0.0.0.0
port: 4466
write:
host: 0.0.0.0
port: 4467
-8
View File
@@ -1,8 +0,0 @@
To: {{range $index, $v := .To}}{{if $index}},{{end}}{{$v}}{{end}}
From: {{.From}}
Subject: {{.Subject}}
{{.Header}}
You have a new message:
{{.Content}}
{{.Footer}}
-9
View File
@@ -1,9 +0,0 @@
To: {{range $index, $v := .To}}{{if $index}},{{end}}{{$v}}{{end}}
From: {{.From}}
Subject: {{.Subject}}
{{.Header}}
You have initiated password reset.
Follow the link below to reset password.
{{.Content}}
{{.Footer}}
+48 -31
View File
@@ -1,41 +1,58 @@
module github.com/ultravioletrs/cocos
go 1.18
go 1.21.6
require (
github.com/go-kit/kit v0.12.0
github.com/go-zoo/bone v1.3.0
github.com/jmoiron/sqlx v1.3.5
github.com/lib/pq v1.10.6
github.com/mainflux/mainflux v0.0.0-20220624143112-931b48f3a7d6
github.com/opentracing/opentracing-go v1.2.0
github.com/prometheus/client_golang v1.12.2
github.com/rubenv/sql-migrate v1.1.2
github.com/uber/jaeger-client-go v2.30.0+incompatible
github.com/ultravioletrs/clients v0.0.0-20220812211530-116a1800cd38
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
google.golang.org/grpc v1.47.0
github.com/absmach/magistrala v0.0.0-20240119191055-d95283d31472
github.com/caarlos0/env/v7 v7.1.0
github.com/cenkalti/backoff/v4 v4.2.1
github.com/digitalocean/go-libvirt v0.0.0-20221205150000-2939327a8519
github.com/go-kit/kit v0.13.0
github.com/gofrs/uuid v4.4.0+incompatible
github.com/google/go-sev-guest v0.10.1
github.com/mdlayher/vsock v1.2.1
github.com/prometheus/client_golang v1.18.0
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1
go.opentelemetry.io/otel v1.21.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0
go.opentelemetry.io/otel/sdk v1.21.0
go.opentelemetry.io/otel/trace v1.21.0
golang.org/x/crypto v0.19.0
golang.org/x/sync v0.6.0
google.golang.org/grpc v1.60.1
google.golang.org/protobuf v1.32.0
)
require (
cloud.google.com/go/compute v1.23.3 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/go-gorp/gorp/v3 v3.0.2 // indirect
github.com/go-kit/log v0.2.0 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/gofrs/uuid v4.2.0+incompatible // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-configfs-tsm v0.2.2 // indirect
github.com/google/logger v1.1.1 // indirect
github.com/google/uuid v1.5.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/pborman/uuid v1.2.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.33.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac // indirect
google.golang.org/protobuf v1.28.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
go.opentelemetry.io/otel/metric v1.21.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 // indirect
)
+135 -749
View File
@@ -1,781 +1,167 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME=
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/absmach/magistrala v0.0.0-20240119191055-d95283d31472 h1:MdS3yTTJP/OSFkMJ4+cJ0LnRS9OyPtPxsR0mSFYglXw=
github.com/absmach/magistrala v0.0.0-20240119191055-d95283d31472/go.mod h1:02Ip3Ow7JlPT4nb2TdZcOuf7C3ac8tzyEVwB+H1G40g=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/caarlos0/env/v7 v7.1.0 h1:9lzTF5amyQeWHZzuZeKlCb5FWSUxpG1js43mhbY8ozg=
github.com/caarlos0/env/v7 v7.1.0/go.mod h1:LPPWniDUq4JaO6Q41vtlyikhMknqymCLBw0eX4dcH1E=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gorp/gorp/v3 v3.0.2 h1:ULqJXIekoqMx29FI5ekXXFoH1dT2Vc8UhnRzBg+Emz4=
github.com/go-gorp/gorp/v3 v3.0.2/go.mod h1:BJ3q1ejpV8cVALtcXvXaXyTOlMmJhWDxTmncaR6rwBY=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4=
github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw=
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-zoo/bone v1.3.0 h1:PY6sHq37FnQhj+4ZyqFIzJQHvrrGx0GEc3vTZZC/OsI=
github.com/go-zoo/bone v1.3.0/go.mod h1:HI3Lhb7G3UQcAwEhOJ2WyNcsFtQX1WYHa0Hl4OBbhW8=
github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU=
github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs=
github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0=
github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY=
github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY=
github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE=
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/digitalocean/go-libvirt v0.0.0-20221205150000-2939327a8519 h1:OpkN/n40cmKenDQS+IOAeW9DLhYy4DADSeZnouCEV/E=
github.com/digitalocean/go-libvirt v0.0.0-20221205150000-2939327a8519/go.mod h1:WyJJyfmJ0gWJvjV+ZH4DOgtOYZc1KOvYyBXWCLKxsUU=
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU=
github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg=
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kortschak/utter v1.0.1/go.mod h1:vSmSjbyrlKjjsL71193LmzBOKgwePk9DH6uFaWHIInc=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mainflux/mainflux v0.0.0-20220624143112-931b48f3a7d6 h1:um7t06LRWOhg7xkXDiqjE9nza0xYbCvpjMIJ4LpgX1U=
github.com/mainflux/mainflux v0.0.0-20220624143112-931b48f3a7d6/go.mod h1:jWkCsO75NjakH18Qmz6TPq7cKzSMtAfe0K+ZalpI8To=
github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI=
github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY=
github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI=
github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-configfs-tsm v0.2.2 h1:YnJ9rXIOj5BYD7/0DNnzs8AOp7UcvjfTvt215EWcs98=
github.com/google/go-configfs-tsm v0.2.2/go.mod h1:EL1GTDFMb5PZQWDviGfZV9n87WeGTR/JUg13RfwkgRo=
github.com/google/go-sev-guest v0.10.1 h1:kZIcGD513eqInbezqxchTtOLJlVXALyWlIXu5E0tNJE=
github.com/google/go-sev-guest v0.10.1/go.mod h1:/5hrgGWqG7+MPTXKhQz+v9ZE+Eh4MCBdItCNwgshlrk=
github.com/google/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ=
github.com/google/logger v1.1.1/go.mod h1:BkeJZ+1FhQ+/d087r4dzojEg1u2ZX+ZqG1jTUrLM+zQ=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=
github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=
github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw=
github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/poy/onpar v0.0.0-20190519213022-ee068f8ea4d1 h1:oL4IBbcqwhhNWh31bjOX8C/OCy0zs9906d/VUru+bqg=
github.com/poy/onpar v0.0.0-20190519213022-ee068f8ea4d1/go.mod h1:nSbFQvMj97ZyhFRSJYtut+msi4sOY6zJDGCdSc+/rZU=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.33.0 h1:rHgav/0a6+uYgGdNt3jwz8FNSesO/Hsang3O0T9A5SE=
github.com/prometheus/common v0.33.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rubenv/sql-migrate v1.1.2 h1:9M6oj4e//owVVHYrFISmY9LBRw6gzkCNmD9MV36tZeQ=
github.com/rubenv/sql-migrate v1.1.2/go.mod h1:/7TZymwxN8VWumcIxw1jjHEcR1djpdkMHQPT4FWdnbQ=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ultravioletrs/clients v0.0.0-20220812211530-116a1800cd38 h1:WrMG/LEFrJTGjodTVHxtWZMbxoyWUdFeWEFNkSHFc2M=
github.com/ultravioletrs/clients v0.0.0-20220812211530-116a1800cd38/go.mod h1:6GNy758K7HXn9dTLB6Ig/8APix0dW1a4kR/m7EuyopQ=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE=
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I=
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac h1:qSNTkEN+L2mvWcLgJOR+8bdHX9rN/IdU3A1Ghpfb1Rg=
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg=
google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0=
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 h1:OPXtXn7fNMaXwO3JvOmF1QyTc00jsSFFz1vXXBOdCDo=
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA=
google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+1
View File
@@ -0,0 +1 @@
source "$BR2_EXTERNAL_COCOS_PATH/package/agent/Config.in"
+14
View File
@@ -0,0 +1,14 @@
# Hardware Abstraction Layer (HAL) for Confidential Computing
Cocos HAL for Linux is framework for building custom in-enclave Linux distribution.
## Usage
HAL uses [Buildroot](https://buildroot.org/)'s [_External Tree_ mechanism](https://buildroot.org/downloads/manual/manual.html#outside-br-custom) for building custom distro:
```bash
git clone git@github.com:ultravioletrs/cocos.git
git clone git@github.com:buildroot/buildroot.git
cd buildroot
make BR2_EXTERNAL=../cocos/hal/linux cocos_defconfig
make menuconfig
make
```
+64
View File
@@ -0,0 +1,64 @@
CONFIG_SYSVIPC=y
CONFIG_CGROUPS=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_SMP=y
CONFIG_HYPERVISOR_GUEST=y
CONFIG_PARAVIRT=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
# CONFIG_WIRELESS is not set
CONFIG_PCI=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_VIRTIO_BLK=y
CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_VIRTIO=y
CONFIG_ATA=y
CONFIG_ATA_PIIX=y
CONFIG_NETDEVICES=y
CONFIG_VIRTIO_NET=y
CONFIG_NE2K_PCI=y
CONFIG_8139CP=y
# CONFIG_WLAN is not set
CONFIG_INPUT_EVDEV=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_HW_RANDOM_VIRTIO=m
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_INPUT=y
CONFIG_VIRTIO_MMIO=y
CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
CONFIG_EXT4_FS=y
CONFIG_AUTOFS4_FS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_UNWINDER_FRAME_POINTER=y
CONFIG_VSOCKETS=y
CONFIG_VIRTIO_VSOCKETS=y
###
# AMD SEV-SNP
###
CONFIG_EFI=y
CONFIG_EFI_STUB=y
CONFIG_VIRT_DRIVERS=y
CONFIG_LOCALVERSION_AUTO=n
CONFIG_AMD_MEM_ENCRYPT=y
CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT=n
CONFIG_CRYPTO_AES=y
CONFIG_SYSTEM_TRUSTED_KEYS=n
CONFIG_SYSTEM_REVOCATION_KEYS=n
CONFIG_MODULE_SIG_KEY=n
CONFIG_SEV_GUEST=y
CONFIG_IOMMU_DEFAULT_PASSTHROUGH=n
CONFIG_PREEMPT_COUNT=n
CONFIG_PREEMPT=n
CONFIG_PREEMPT_DYNAMIC=n
CONFIG_DEBUG_PREEMPT=n
CONFIG_CGROUP_MISC=y
CONFIG_X86_CPUID=y
+11
View File
@@ -0,0 +1,11 @@
#!/bin/sh
set -u
set -e
# Add a console on tty1
if [ -e ${TARGET_DIR}/etc/inittab ]; then
grep -qE '^tty1::' ${TARGET_DIR}/etc/inittab || \
sed -i '/GENERIC_SERIAL/a\
tty1::respawn:/sbin/getty -L tty1 0 vt100 # QEMU graphical window' ${TARGET_DIR}/etc/inittab
fi
+51
View File
@@ -0,0 +1,51 @@
#!/bin/bash
COCOS_BOARD_DIR="$(dirname "$0")"
DEFCONFIG_NAME="$(basename "$2")"
README_FILES="${COCOS_BOARD_DIR}/readme.txt"
START_QEMU_SCRIPT="${BINARIES_DIR}/start-qemu.sh"
if [[ "${DEFCONFIG_NAME}" =~ ^"cocos_*" ]]; then
# Not a Qemu defconfig, can't test.
exit 0
fi
# Search for "# qemu_*_defconfig" tag in all readme.txt files.
# Qemu command line on multilines using back slash are accepted.
# shellcheck disable=SC2086 # glob over each readme file
QEMU_CMD_LINE="$(sed -r ':a; /\\$/N; s/\\\n//; s/\t/ /; ta; /# '"${DEFCONFIG_NAME}"'$/!d; s/#.*//' ${README_FILES})"
if [ -z "${QEMU_CMD_LINE}" ]; then
# No Qemu cmd line found, can't test.
exit 0
fi
# Remove output/images path since the script will be in
# the same directory as the kernel and the rootfs images.
QEMU_CMD_LINE="${QEMU_CMD_LINE//output\/images\//}"
# Remove -serial stdio if present, keep it as default args
DEFAULT_ARGS="$(sed -r -e '/-serial stdio/!d; s/.*(-serial stdio).*/\1/' <<<"${QEMU_CMD_LINE}")"
QEMU_CMD_LINE="${QEMU_CMD_LINE//-serial stdio/}"
# Remove any string before qemu-system-*
QEMU_CMD_LINE="$(sed -r -e 's/^.*(qemu-system-)/\1/' <<<"${QEMU_CMD_LINE}")"
# Disable graphical output and redirect serial I/Os to console
case ${DEFCONFIG_NAME} in
(qemu_sh4eb_r2d_defconfig|qemu_sh4_r2d_defconfig)
# Special case for SH4
SERIAL_ARGS="-serial stdio -display none"
;;
(*)
SERIAL_ARGS="-nographic"
;;
esac
sed -e "s|@SERIAL_ARGS@|${SERIAL_ARGS}|g" \
-e "s|@DEFAULT_ARGS@|${DEFAULT_ARGS}|g" \
-e "s|@QEMU_CMD_LINE@|${QEMU_CMD_LINE}|g" \
-e "s|@HOST_DIR@|${HOST_DIR}|g" \
<"${COCOS_BOARD_DIR}/start-qemu.sh.in" \
>"${START_QEMU_SCRIPT}"
chmod +x "${START_QEMU_SCRIPT}"
+7
View File
@@ -0,0 +1,7 @@
Run the emulation with:
qemu-system-x86_64 -M pc -kernel output/images/bzImage -drive file=output/images/rootfs.ext2,if=virtio,format=raw -append "rootwait root=/dev/vda console=tty1 console=ttyS0" -serial stdio -net nic,model=virtio -net user # cocos_defconfig
Optionally add -smp N to emulate a SMP system with N CPUs.
The login prompt will appear in the graphical window.
+28
View File
@@ -0,0 +1,28 @@
#!/bin/sh
BINARIES_DIR="${0%/*}/"
# shellcheck disable=SC2164
cd "${BINARIES_DIR}"
mode_serial=false
mode_sys_qemu=false
while [ "$1" ]; do
case "$1" in
--serial-only|serial-only) mode_serial=true; shift;;
--use-system-qemu) mode_sys_qemu=true; shift;;
--) shift; break;;
*) echo "unknown option: $1" >&2; exit 1;;
esac
done
if ${mode_serial}; then
EXTRA_ARGS='@SERIAL_ARGS@'
else
EXTRA_ARGS='@DEFAULT_ARGS@'
fi
if ! ${mode_sys_qemu}; then
export PATH="@HOST_DIR@/bin:${PATH}"
fi
exec @QEMU_CMD_LINE@ ${EXTRA_ARGS} "$@"
+48
View File
@@ -0,0 +1,48 @@
# Architecture
BR2_x86_64=y
# System
BR2_TARGET_GENERIC_HOSTNAME="cocos"
BR2_TARGET_GENERIC_ISSUE="Welcome to Cocos"
BR2_PACKAGE_DHCP=y
BR2_PACKAGE_DHCP_CLIENT=y
BR2_INIT_SYSTEMD=y
# Filesystem
# BR2_TARGET_ROOTFS_TAR is not set
BR2_TARGET_ROOTFS_CPIO=y
BR2_TARGET_ROOTFS_CPIO_FULL=y
BR2_TARGET_ROOTFS_CPIO_GZIP=y
# Image
BR2_ROOTFS_POST_BUILD_SCRIPT="$(BR2_EXTERNAL_COCOS_PATH)/board/cocos/post-build.sh"
# Image
BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL_COCOS_PATH)/board/cocos/post-image.sh"
BR2_ROOTFS_POST_SCRIPT_ARGS="$(BR2_DEFCONFIG)"
# Linux headers same as kernel
BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_6_6=y
BR2_TOOLCHAIN_HEADERS_AT_LEAST_6_5=y
BR2_TOOLCHAIN_HEADERS_AT_LEAST_6_6=y
BR2_TOOLCHAIN_HEADERS_LATEST=y
BR2_TOOLCHAIN_HEADERS_AT_LEAST="6.6"
# Kernel
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_GIT=y
BR2_LINUX_KERNEL_CUSTOM_REPO_URL="https://github.com/torvalds/linux.git"
BR2_LINUX_KERNEL_CUSTOM_REPO_VERSION="v6.6"
BR2_LINUX_KERNEL_VERSION="v6.6"
BR2_LINUX_KERNEL_PATCH=""
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_COCOS_PATH)/board/cocos/linux.config"
BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
# host-qemu for gitlab testing
BR2_PACKAGE_HOST_QEMU=y
BR2_PACKAGE_HOST_QEMU_SYSTEM_MODE=y
# Python
BR2_PACKAGE_PYTHON3=y
BR2_PACKAGE_PYTHON_PIP=y

Some files were not shown because too many files have changed in this diff Show More