Skip to content
Snippets Groups Projects
Commit 3d5740fe authored by Loïc Ortola's avatar Loïc Ortola
Browse files

feat: added readmes and boilerplates

parent 437745d7
Branches
No related tags found
No related merge requests found
Showing
with 349 additions and 120 deletions
.idea
# Hackathon
Your end of training practice project
## Getting started
* Clone this repository to your local machine.
* Make sure you get your Temporal Cloud account credentials set up.
* Change the Client files in all subdirectories (workflow, starter, worker etc...)
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Add your files
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/topics/git/add_files/#add-files-to-a-git-repository) or push an existing Git repository with the following command:
```
cd existing_repo
git remote add origin https://gitlab.takima.io/school/temporal/Hackathon.git
git branch -M main
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](https://gitlab.takima.io/school/temporal/Hackathon/-/settings/integrations)
## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Set auto-merge](https://docs.gitlab.com/user/project/merge_requests/auto_merge/)
## Test and Deploy
Use the built-in continuous integration in GitLab.
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
***
# Editing this README
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
## Name
Choose a self-explaining name for your project.
## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
## Badges
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
## Visuals
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
## Installation
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
## Usage
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
## Support
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
## Roadmap
If you have ideas for releases in the future, it is a good idea to list them in the README.
## Contributing
State if you are open to contributions and what your requirements are for accepting them.
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
## Design Guidelines
1. Create a "server-side" state machine that represents your workflow
2. Map the state machine to Temporal primitives (Workflows, Activities, Signals, Queries, etc...)
3. Declare all "endpoints" you will use in the API Gateway for each activity / signal, etc...
4. Once you've presented your work to everyone, you can start the implementation!
## Authors and acknowledgment
Show your appreciation to those who have contributed to the project.
## Troubleshooting, FAQ, Guidelines
## License
For open source projects, say how it is licensed.
### I'd love a webhook, but I don't have access to your API Gateway...
Yes, our APIs are kind of old school, but you can poll every couple seconds and detect changes to "simulate" a webhook.
## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
### My workflows are "Running", but nothing is happening...
* Check that you have setup the Temporal Cloud credentials in ALL of your clients
* Check that you have the correct task queue names on both sides
* Make sure you have restarted the worker / apps to take into account your latest changes
# Datacenter Hosts Reset Workflow
Every now and then, to apply security patches or to reset hardware, we have a procedure to restart all of the Baremetal Hosts.
You will implemetnt this procedure with Temporal.
## Specs
### BASIC
→ We have over 500 Hosts, and we can’t reboot them all at the same time, to ensure the workloads continue running smoothly. To be safe, we cannot reboot more than 10 Hosts at a time.
→ Our system teams must know the progress of the restart procedure at all times
Boilerplate
### BONUS 1 - FAILING RESTART
→ Sometimes, a host can fail to restart, and therefore needs to be restarted again
→ If the host fails to restart after three attempts, you can skip it
### BONUS 2 - MAINTENANCE WINDOWS
→ The procedure can only be ongoing during maintenance windows (when maintenance status is set to allowed)
→ You can add a “onlySurvivors” flag when starting your workflow that only resets the hosts which haven’t restarted for 7 days or more.
## Architecture
The Datacenter has multiple APIs that you will need to interact with:
- A `Host` API that allows you to manage the hosts, including listing them, restarting them, and checking their status.
- A `VM` API that allows you to manage the virtual machines, including listing them, getting their load stats, resizing them, and checking their status.
- A `Maintenance` API that allows you to check if we are in a maintenance window, or not.
- A `SuperSlack` API, our internal support chat app, that allows you to send messages to specific channels and recipients.
## Boilerplate
We have provided you with a boilerplate code that contains the following:
- A http client to the remote Datacenter APIs, and the corresponding data structures
- Samples of query and signal "trigger" functions that you can use to interact with your future workflow
- A starter to launch your workflow (needs to be adapted to your needs)
- A worker that you will use to run your workflows and activities
\ No newline at end of file
microservice
============
This directory contains the Go code for a simple microservice,
accessible via HTTP, which accepts a name as an input parameter
and returns a greeting in Spanish customized for that name.
Run the service:
```
$ go run greeting-and-farewell-service.go
```
On a Mac, you might be prompted by the OS as to whether to allow incoming connections, so approve them if so.
Afterwards, test that it's working by visiting this URL in your browser:
[http://localhost:9999/get-spanish-greeting?name=Donna]
Once it is, you can write and run workflows that use this service.
package host
import (
"context"
"dc-hosts-reset/common/clients"
"encoding/json"
"fmt"
"strconv"
)
func GetAllHostStates(ctx context.Context) ([]HostApiHostDto, error) {
body, err := clients.Get("/hosts/state")
func GetAllHostStates() ([]HostApiHostDto, error) {
body, err := clients.Get("/hosts")
if err != nil {
return nil, err
}
......@@ -22,8 +21,8 @@ func GetAllHostStates(ctx context.Context) ([]HostApiHostDto, error) {
return hosts, nil
}
func GetAllHostStatesSurvivor(ctx context.Context, survivors bool) ([]HostApiHostDto, error) {
body, err := clients.Get("/hosts/state?survivors=" + strconv.FormatBool(survivors))
func GetAllHostStatesSurvivor(survivors bool) ([]HostApiHostDto, error) {
body, err := clients.Get("/hosts/survivors=" + strconv.FormatBool(survivors))
if err != nil {
return nil, err
}
......@@ -36,8 +35,8 @@ func GetAllHostStatesSurvivor(ctx context.Context, survivors bool) ([]HostApiHos
return hosts, nil
}
func GetHostState(ctx context.Context, hostId string) (HostApiHostDto, error) {
body, err := clients.Get("/hosts/" + hostId + "/state")
func GetHostState(hostId string) (HostApiHostDto, error) {
body, err := clients.Get("/hosts/" + hostId)
if err != nil {
return HostApiHostDto{}, err
}
......@@ -50,7 +49,7 @@ func GetHostState(ctx context.Context, hostId string) (HostApiHostDto, error) {
return host, nil
}
func RestartHost(ctx context.Context, hostId string) (HostApiHostDto, error) {
func RestartHost(hostId string) (HostApiHostDto, error) {
body, err := clients.Post("/hosts/"+hostId+"/restart", nil)
if err != nil {
return HostApiHostDto{}, err
......@@ -64,8 +63,8 @@ func RestartHost(ctx context.Context, hostId string) (HostApiHostDto, error) {
return host, nil
}
func GetUsersForHost(ctx context.Context, hostId string) ([]HostApiUserDto, error) {
body, err := clients.Post("/hosts/"+hostId+"/access", nil)
func GetUsersForHost(hostId string) ([]HostApiUserDto, error) {
body, err := clients.Post("/hosts/"+hostId+"/users", nil)
if err != nil {
return nil, err
}
......@@ -78,22 +77,22 @@ func GetUsersForHost(ctx context.Context, hostId string) ([]HostApiUserDto, erro
return users, nil
}
func SaveUserForHost(ctx context.Context, hostId string, user HostApiUserDto) error {
func SaveUserForHost(hostId string, user HostApiUserDto) error {
jsonData, err := json.Marshal(user)
if err != nil {
fmt.Printf("Erreur lors de la sérialisation: %v\n", err)
return err
}
_, err = clients.Post("/hosts/"+hostId+"/user", jsonData)
_, err = clients.Post("/hosts/"+hostId+"/users", jsonData)
if err != nil {
return err
}
return nil
}
func RevokeUserForHost(ctx context.Context, hostId string, userId string) error {
_, err := clients.Delete("/hosts/" + hostId + "/user/" + userId)
func RevokeUserForHost(hostId string, userId string) error {
_, err := clients.Delete("/hosts/" + hostId + "/users/" + userId)
if err != nil {
return err
}
......
package host
type HostStatusDto string
const (
OFF HostStatusDto = "OFF"
STARTING HostStatusDto = "STARTING"
RUNNING HostStatusDto = "RUNNING"
ERROR HostStatusDto = "ERROR"
)
type HostApiHostDto struct {
ID string `json:"id"`
Status HostStatusDto `json:"status"`
LastStatusChange string `json:"lastStatusChange"`
}
type HostApiRightDto struct {
......
package maintenance
import (
"dc-hosts-reset/common/clients"
"encoding/json"
"fmt"
)
func GetMaintenanceStatus() (bool, error) {
body, err := clients.Get("/maintenance")
if err != nil {
return false, err
}
var status MaintenanceStatusDto
if err := json.Unmarshal(body, &status); err != nil {
return false, fmt.Errorf("error when deserializing JSON: %w", err)
}
return status.Status, nil
}
func SetMaintenanceStatus(maintenanceEnabled bool) error {
dto := MaintenanceStatusDto{
Status: maintenanceEnabled,
}
body, err := json.Marshal(dto)
if err != nil {
return err
}
_, err = clients.Post("/maintenance", body)
if err != nil {
return err
}
return nil
}
package maintenance
type MaintenanceStatusDto struct {
Status bool `json:"status"`
}
package superslack
import (
"dc-hosts-reset/common/clients"
"encoding/json"
)
func PostMessage(dto SuperSlackMessageDto) error {
body, err := json.Marshal(dto)
if err != nil {
return err
}
_, err = clients.Post("/superslack/messages", body)
if err != nil {
return err
}
return nil
}
package superslack
type SuperSlackMessageDto struct {
Recipient string `json:"recipient"`
Message string `json:"message"`
}
package vm
import (
"dc-hosts-reset/common/clients"
"encoding/json"
"fmt"
)
func GetAllLiveVMs() ([]VMDto, error) {
body, err := clients.Get("/vms")
if err != nil {
return nil, err
}
var hosts []VMDto
if err := json.Unmarshal(body, &hosts); err != nil {
return nil, fmt.Errorf("error when deserializing JSON: %w", err)
}
return hosts, nil
}
func GetVMState(vmId string) (VMDto, error) {
body, err := clients.Get("/vms/" + vmId)
if err != nil {
return VMDto{}, err
}
var host VMDto
if err := json.Unmarshal(body, &host); err != nil {
return VMDto{}, fmt.Errorf("error when deserializing JSON: %w", err)
}
return host, nil
}
func ResizeVM(dto VMResizeRequestDto) (VMDto, error) {
reqBody, err := json.Marshal(dto)
if err != nil {
return VMDto{}, err
}
body, err := clients.Post("/vms/"+dto.ID+"/resize", reqBody)
if err != nil {
return VMDto{}, err
}
if err != nil {
return VMDto{}, err
}
var host VMDto
if err := json.Unmarshal(body, &host); err != nil {
return VMDto{}, fmt.Errorf("error when deserializing JSON: %w", err)
}
return host, nil
}
func StartVM(vmId string) (VMDto, error) {
body, err := clients.Post("/vms/"+vmId+"/start", nil)
if err != nil {
return VMDto{}, err
}
var vm VMDto
if err := json.Unmarshal(body, &vm); err != nil {
return VMDto{}, fmt.Errorf("error when deserializing JSON: %w", err)
}
return vm, nil
}
func StopVM(vmId string) error {
_, err := clients.Delete("/vms/" + vmId)
if err != nil {
return err
}
return nil
}
package vm
type VMStatusDto string
const (
OFF VMStatusDto = "OFF"
RUNNING VMStatusDto = "RUNNING"
)
type VMDto struct {
ID string `json:"id"`
Status VMStatusDto `json:"status"`
LastStatusChange string `json:"lastStatusChange"`
VCPU int `json:"vCPU"`
RamGB int `json:"ramGB"`
CPUAvgPercent int `json:"cpuAvgPercent"`
CPUPeakPercent int `json:"cpuPeakPercent"`
RamAvgPercent int `json:"ramAvgPercent"`
RamPeakPercent int `json:"ramPeakPercent"`
}
type VMResizeRequestDto struct {
ID string `json:"id"`
VCPU int `json:"vCPU"`
RamGB int `json:"ramGB"`
}
package utils
const REMOTE_API_GATEWAY_BASE_URL = "http://localhost:9999"
const REMOTE_API_GATEWAY_BASE_URL = "https://lhws.hcaupert.fr/api"
const QUEUE_NAME = "dc-host-reset-queue"
......
package main
import (
"dc-hosts-reset/common/clients/host"
"fmt"
"log"
)
func main() {
states, err := host.GetHostState("3f2eda06-36b5-4487-8b3e-8546999dff02")
if err != nil {
log.Fatalln("Error getting host states:", err)
}
fmt.Println(states)
}
# Elevated Request System
As we are just beginning our journey to becoming the greatest Cloud Provider on earth, we often find a need to patch things on our systems. Help us create an end-to-end elevated request workflow, which needs a manual approval process (through our internal support ticketing app), and provides (if granted) a temporary admin access to a specific host.
## Specs
### BASIC
→ A user can send a request to get an admin access for a limited time on a specific host
→ When the request is received, anyone could request (query) the current state and see if it has been approved, denied, or is still open
→ When the ticket has been closed (accepted or denied), grant access to the resource for 10 minutes (if accepted)
→ After 10 minutes, revoke host access
### BONUS 1 - GENTLE REMINDER
→ After some time (let’s say 5 minutes), if the ticket hasn’t been closed yet, notify the system team on their (mocked) slack so that they can start working on it.
### BONUS 2 - NEW REQUESTS: RESTART HOST & SET MAINTENANCE MODE
→ Add a feature to support a similar request to reset a host.
→ Add a feature to support a similar request to set or unset the maintenance mode.
## Architecture
The Datacenter has multiple APIs that you will need to interact with:
- A `Host` API that allows you to manage the hosts, including listing them, restarting them, and checking their status.
- A `VM` API that allows you to manage the virtual machines, including listing them, getting their load stats, resizing them, and checking their status.
- A `Maintenance` API that allows you to check if we are in a maintenance window, or not.
- A `SuperSlack` API, our internal support chat app, that allows you to send messages to specific channels and recipients.
## Boilerplate
We have provided you with a boilerplate code that contains the following:
- A http client to the remote Datacenter APIs, and the corresponding data structures
- Samples of query and signal "trigger" functions that you can use to interact with your future workflow
- A starter to launch your workflow (needs to be adapted to your needs)
- A worker that you will use to run your workflows and activities
\ No newline at end of file
# Reasonable Resource Management Watchdog
People have a tendency to ask for the moon. In our case, the moon looks like big vCPU / RAM VMs. Our problem? Most of them don’t really use those, which leads to waste. Create a workflow that scans VMs and takes progressive actions to optimize the use of resources
## Specs
### BASIC
→ When a watchdog runs, it fetches all VMs, and will check VM usage one by one (but will only watch one every 30 seconds not to create too much load)
→ If a VM has an average load below 5%, or a peak load below 50% (cpu or memory), the watchdog may suggest an optimized size
→ If the VM was created over 7 days ago, it should notify the owner (on SuperSlack) and suggest him to resize the VM
→ At any time, the user may want to signal and accept or deny the suggestion. If accepted, the VM gets resized and the user will be notified of this on SuperSlack
### BONUS 1 - GENTLE REMINDER
→ If the user doesn’t respond in the following 10 minutes, it should notify the owner that it will soon terminate the VM
→ At any time, the user may want to signal and either accept or deny the suggestion
→ If the user doesn’t respond after this second notification, terminate the VM and send a message to the user
### BONUS 2 - GENTLE RESURRECTION
→ When the user comes back from vacation and sees his workload was killed, he could at anytime signal his will to restart the VM exactly as it was in the beginning.
## Architecture
The Datacenter has multiple APIs that you will need to interact with:
- A `Host` API that allows you to manage the hosts, including listing them, restarting them, and checking their status.
- A `VM` API that allows you to manage the virtual machines, including listing them, getting their load stats, resizing them, and checking their status.
- A `Maintenance` API that allows you to check if we are in a maintenance window, or not.
- A `SuperSlack` API, our internal support chat app, that allows you to send messages to specific channels and recipients.
## Boilerplate
We have provided you with a boilerplate code that contains the following:
- A http client to the remote Datacenter APIs, and the corresponding data structures
- Samples of query and signal "trigger" functions that you can use to interact with your future workflow
- A starter to launch your workflow (needs to be adapted to your needs)
- A worker that you will use to run your workflows and activities
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment