Skip to content

Commit

Permalink
Merge pull request #87 from Agomik/master
Browse files Browse the repository at this point in the history
Documentation, Docker files, Computes and SLT updated
  • Loading branch information
jsoldani committed Apr 17, 2024
2 parents c4c9f36 + 1f57480 commit 9f1ac7a
Show file tree
Hide file tree
Showing 11 changed files with 82 additions and 57 deletions.
63 changes: 36 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
# MicroFreshener

```
MicroFreshener is a web-based prototype that permits to identify
the architectural smells that possibly violate principles of microservices,
and to select suitable refactorings to resolve them.
```
MicroFreshener is a web-based prototype that enables to identify bad architectural smells that possibly violate principles of microservices, and to select suitable refactorings to resolve them.

![](./screenshot.png)

## Table of Contents
- [MicroFreshener](#microfreshener-architecture)
Expand All @@ -16,21 +13,23 @@ and to select suitable refactorings to resolve them.
<!-- * [Example of usage](#example-of-usage) -->
- [License](#license)

## MicroFreshener architecture

## Web-based interface
`MicroFreshener` has a web-based interface that permits to :
- draw and edit the architectures of microservices
- analyse the architecture and
- apply refactorings.
`MicroFreshener` has a web-based interface that allows to:
- Draw and edit the architectures of microservices
- Manage teams and their owned nodes
- Analyse the architecture to identify architectural smells
- Apply refactorings

Examples of the web-based interface is shown below.
`MicroFreshener` can be used either as `admin` or `team member`.
- You can login as administrator by typing `admin` in the login page
- You can login as a team member by typing the _exact_ name of your team in the login page

![](./docs/demo.gif)

<!--Examples of the web-based interface is shown below.
![](./docs/demo.gif)-->

## Quick Guide
In order to run the `MicroFreshener` you should run the server and the client (for local use only).
In order to run `MicroFreshener` you should run both the server and the client (for local use only).

## Installation
In order to use `MicroFreshener` you should first download the repository:
Expand All @@ -40,13 +39,13 @@ git clone https://github.com/di-unipi-socc/microFreshener.git
```

### Run the server
Enter in the server directotry
Enter the server directory.

```bash
cd /server
cd server
```

Create a virtual environment and install the python dependencies. Python3.8 is needed.
Create a virtual environment and install the Python dependencies. Python3.8+ is needed.

```bash
virtualenv -p="/usr/bin/python3.8" venv
Expand Down Expand Up @@ -84,33 +83,43 @@ python manage.py runserver 0.0.0.0:8000
The client is an Angular web application.

```bash
cd /client
cd client
```

Serve the client with a local server
Install the project dependencies.

```bash
npm install
```

Then, serve the client with a local server by typing

```bash
sudo ng serve
```
or
```bash
sudo npm start
```

[comment]: <> (// deploy on production host "neri.di.unipi.it")
[comment]: <> (ng serve --host neri.di.unipi.it -c production)

In case of `ERR_OSSL_EVP_UNSUPPORTED` error, type `export NODE_OPTIONS=--openssl-legacy-provider` before `ng serve`.

Open the bowser on http://127.0.0.1:4200/.
Open the bowser on http://localhost:4200/.


## with docker compose
## Install MicroFreshener using Docker compose

Make sure to install the following dependencies:

```bash
pip3 install websocket
pip3 install docopt
pip3 install texttable
pip3 install dockerpty
pip3 install websocket-client==0.32.0
pip install websocket
pip install docopt
pip install texttable
pip install dockerpty
pip install websocket-client
```

Create the docker network
Expand All @@ -127,4 +136,4 @@ docker-compose -f docker-compose.prod.yml build
docker-compose -f docker-compose.prod.yml up
```

Open the bowser on http://127.0.0.1.
Open the bowser on http://localhost:80.
6 changes: 3 additions & 3 deletions client/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
### Stage 1: build bundle angular
FROM node:11.4.0-alpine as builder
FROM node:16 as builder

RUN mkdir /app
WORKDIR /app
Expand All @@ -9,7 +9,7 @@ COPY package.json package-lock.json /app/
# Install app dependencies.
RUN npm install

COPY . /app
COPY . /app

# Default build configuration (production by default)
ARG configuration=production
Expand All @@ -18,7 +18,7 @@ ARG configuration=production
RUN npm run build -- --output-path=./dist/out --configuration $configuration

### Stage 2: delivery ###
FROM nginx:1.15.7-alpine
FROM nginx:alpine

# Remove default nginx website
RUN rm -rf /usr/share/nginx/html/*
Expand Down
6 changes: 3 additions & 3 deletions client/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# MicroFreshener

This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.1.2.
This project was generated with [Angular CLI](https://github.com/angular/angular-cli).

## Development server

Expand All @@ -16,7 +16,7 @@ Run `ng generate component component-name` to generate a new component. You can

Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use `ng build --configuration production` instead for a production build.

## Running unit tests
<!--## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
Expand All @@ -26,4 +26,4 @@ Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protrac
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).-->
5 changes: 2 additions & 3 deletions client/src/app/editor/graph-editor.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ export class GraphEditorComponent {
this.navigation.getPaper().on("element:pointerclick", (cellView, evt, x, y) => {
console.debug("clicked", cellView);
console.log("click on cell");
if(this.deployments.isCompute(cellView.model) || this.deployments.isDeploymentLink(cellView.model)) {
if(this.deployments.isDeploymentLink(cellView.model)) {
if(this.leftClickSelectedCell)
this.stopAddingLink();
return;
Expand Down Expand Up @@ -536,7 +536,7 @@ export class GraphEditorComponent {

bindTeamEmbedNodes() {
this.navigation.getPaper().on('cell:pointerdown', ((cellView, evt, x, y) => {
if(!this.addingLink && this.architecture.isNode(cellView.model) && !this.deployments.isCompute(cellView.model)) {
if(!this.addingLink && this.architecture.isNode(cellView.model)) {
let node = cellView.model;
this.draggingNode = true;
let team = this.teams.getTeamOfNode(node);
Expand Down Expand Up @@ -587,7 +587,6 @@ export class GraphEditorComponent {
if (
!cell.isLink() && // otherwise Error when cell.getBBox() is called.
!this.architecture.isEdgeGroup(cell) && // EdgeGroup node can't be in a squad
!this.deployments.isCompute(cell) && // Computes can't be in a squad
!this.teams.isTeamGroup(cell) &&
this.draggingNode)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Refactoring, RefactoringBuilder } from "./refactoring-command";
import { CompositeCommand } from "src/app/commands/icommand";
import { CompositeCommand, ElementCommand } from "src/app/commands/icommand";
import { AddComputeCommand, RemoveComputeCommand } from "src/app/deployment/computes/compute-commands";
import { ChangeDeploymentLinkTargetCommand } from "src/app/deployment/deployed-on-links/deployed-on-commands";
import { AddMemberToTeamGroupCommand } from "src/app/teams/team-commands";

export class SplitServiceInTwoPods implements Refactoring {

Expand Down Expand Up @@ -39,7 +40,12 @@ export class SplitServiceInTwoPods implements Refactoring {
links.forEach((link) => {
let sourceNode = <joint.shapes.microtosca.Node> link.getSourceElement();
let newComputeName = sourceNode.getName() + " container";
cmds.push(new AddComputeCommand(this.graph, newComputeName, this.graph.getPointCloseTo(sourceNode)));
let addComputeCommand: ElementCommand<joint.shapes.microtosca.Compute> = new AddComputeCommand(this.graph, newComputeName, this.graph.getPointCloseTo(sourceNode));
let sourceTeam = this.graph.getTeamOfNode(sourceNode);
if(sourceTeam) {
addComputeCommand = addComputeCommand.bind(new AddMemberToTeamGroupCommand(sourceTeam));
}
cmds.push(addComputeCommand);
cmds.push(new ChangeDeploymentLinkTargetCommand(this.graph, link, newComputeName));
});
// If the datastore won't be used after the application of the refactoring, remove it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,7 @@ export class SplitTeamsByMicroserviceRefactoring implements GroupRefactoring {
smell.getLinkBasedCauses().forEach(link => {
let service = <joint.shapes.microtosca.Service> link.getSourceElement();
let targetNode = <joint.shapes.microtosca.Node> link.getTargetElement();
if(graph.isCommunicationPattern(targetNode) || ((graph.isDatastore(targetNode) && !this.datastoreUsedInItsTeam(graph, <joint.shapes.microtosca.Datastore> targetNode)))) {
console.debug("SLT - Communication pattern found");
let targetTeam = <joint.shapes.microtosca.SquadGroup> graph.getTeamOfNode(targetNode);
let moveTarget = new RemoveMemberFromTeamGroupCommand(targetTeam, targetNode)
.bind(new AddMemberToTeamGroupCommand(sourceTeam));
cmds.push(moveTarget);
} else if(graph.isDatastore(targetNode)) {
if(graph.isDatastore(targetNode) && this.datastoreUsedInItsTeam(graph, <joint.shapes.microtosca.Datastore> targetNode)) {
// Service in one team -> Datastore in another team which is used internally
let databaseName = (<joint.shapes.microtosca.Service> link.getTargetElement()).getName();
let newDatabaseName = `${service.getName()}'s ${databaseName}`;
Expand All @@ -39,6 +33,12 @@ export class SplitTeamsByMicroserviceRefactoring implements GroupRefactoring {
.then(new AddRunTimeLinkCommand(graph, service.getName(), newDatabaseName));
// Add to global command and single nodes
cmds.push(splitDatastore);
} else {
console.debug("SLT - Communication pattern found");
let targetTeam = <joint.shapes.microtosca.SquadGroup> graph.getTeamOfNode(targetNode);
let moveTarget = new RemoveMemberFromTeamGroupCommand(targetTeam, targetNode)
.bind(new AddMemberToTeamGroupCommand(sourceTeam));
cmds.push(moveTarget);
}
});
this.command = CompositeCommand.of(cmds);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { EditorNavigationService } from 'src/app/navigation/navigation.service';
import { ToolSelectionService } from 'src/app/editor/tool-selection/tool-selection.service';
import { Invoker } from 'src/app/commands/invoker';
import { ArchitectureEditingService } from 'src/app/architecture/architecture-editing.service';
import { ComputeService } from 'src/app/deployment/computes/compute.service';

@Component({
selector: 'app-subtoolbar-teams-management',
Expand Down Expand Up @@ -40,6 +41,7 @@ export class SubtoolbarTeamsComponent {
constructor(
public tools: ToolSelectionService,
private architecture: ArchitectureEditingService,
private computes: ComputeService,
private teams: TeamsService,
private dialogService: DialogService,
private commands: Invoker,
Expand Down Expand Up @@ -118,7 +120,8 @@ export class SubtoolbarTeamsComponent {
let node = <joint.shapes.microtosca.Node> cell;
if((this.architecture.isService(node)
|| this.architecture.isCommunicationPattern(node)
|| this.architecture.isDatastore(node))
|| this.architecture.isDatastore(node)
|| this.computes.isCompute(node))
&& !this.selectedNodes.includes(node)) {
this.selectedNodes.push(node);
this.addTeam.hide();
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
version: "3"

services:
services:
server:
container_name: microfreshener-server
build: server
Expand All @@ -15,7 +15,7 @@ services:
- "traefik.frontend.rule=Host:api.microfreshener.localhost"
networks:
- web


client:
container_name: microfreshener-client
Expand Down
Binary file added screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 15 additions & 8 deletions server/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,23 @@ FROM python:3.8
# Set environment variables
ENV PYTHONUNBUFFERED 1

COPY requirements.txt /
# Set the working directory inside the container
WORKDIR /app

# Install dependencies.
RUN pip install -r /requirements.txt
# Copy the requirements file
COPY requirements.txt /app/

# Set work directory.
RUN mkdir /code
WORKDIR /code
# Install dependencies
RUN pip install -r requirements.txt

# Copy project code.
COPY . /code/
# Copy the project code into the container
COPY . /app/

# Add execute permission to the manage.py file
RUN chmod +x manage.py

# Expose port
EXPOSE 8000

# Run the server
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
3 changes: 2 additions & 1 deletion server/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ itypes==1.1.0
Jinja2==2.10.1
MarkupSafe==1.1.1
microfreshener-core==1.4.0
# microfreshener-core @ git+https://github.com/di-unipi-socc/microFreshener-core.git@master
#microfreshener-core @ git+https://github.com/di-unipi-socc/microFreshener-core.git@master
#../../microFreshener-core
nested-lookup==0.2.19
openapi-codec==1.3.2
pbr==5.4.2
Expand Down

0 comments on commit 9f1ac7a

Please sign in to comment.