-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Task] Support the new type App #266
Merged
Merged
Changes from 6 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
d4c8968
Copy from deployment to apps
cf6c512
The app interface prototype
73add4d
Support the creating function of app
deeb7e9
Insert the data into two db
004290e
Add the bats testging for apps
0d58c1f
Add unit testing
946f235
Change the name from entity.app to entity.application and use default…
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package entity | ||
|
||
// Deployment is the structure for deployment info | ||
type App struct { | ||
Deployment Deployment `bson:"deployment" json:"deployment" validate:"required"` | ||
Service Service `bson:"service" json:"service" validate:"required"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package server | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/linkernetworks/utils/timeutils" | ||
"github.com/linkernetworks/vortex/src/deployment" | ||
"github.com/linkernetworks/vortex/src/entity" | ||
response "github.com/linkernetworks/vortex/src/net/http" | ||
"github.com/linkernetworks/vortex/src/service" | ||
"github.com/linkernetworks/vortex/src/web" | ||
"k8s.io/apimachinery/pkg/api/errors" | ||
|
||
mgo "gopkg.in/mgo.v2" | ||
"gopkg.in/mgo.v2/bson" | ||
) | ||
|
||
func createAppHandler(ctx *web.Context) { | ||
sp, req, resp := ctx.ServiceProvider, ctx.Request, ctx.Response | ||
|
||
p := entity.App{} | ||
if err := req.ReadEntity(&p); err != nil { | ||
response.BadRequest(req.Request, resp.ResponseWriter, err) | ||
return | ||
} | ||
|
||
if err := sp.Validator.Struct(p); err != nil { | ||
response.BadRequest(req.Request, resp.ResponseWriter, err) | ||
return | ||
} | ||
|
||
session := sp.Mongo.NewSession() | ||
session.C(entity.DeploymentCollectionName).EnsureIndex(mgo.Index{ | ||
Key: []string{"name"}, | ||
Unique: true, | ||
}) | ||
session.C(entity.ServiceCollectionName).EnsureIndex(mgo.Index{ | ||
Key: []string{"name"}, | ||
Unique: true, | ||
}) | ||
defer session.Close() | ||
|
||
// Check whether this name has been used | ||
ID := bson.NewObjectId() | ||
p.Deployment.ID = ID | ||
p.Service.ID = ID | ||
|
||
time := timeutils.Now() | ||
p.Deployment.CreatedAt = time | ||
p.Service.CreatedAt = time | ||
if err := deployment.CheckDeploymentParameter(sp, &p.Deployment); err != nil { | ||
response.BadRequest(req.Request, resp.ResponseWriter, err) | ||
return | ||
} | ||
|
||
if err := deployment.CreateDeployment(sp, &p.Deployment); err != nil { | ||
if errors.IsAlreadyExists(err) { | ||
response.Conflict(req.Request, resp.ResponseWriter, fmt.Errorf("Deployment Name: %s already existed", p.Deployment.Name)) | ||
} else { | ||
response.InternalServerError(req.Request, resp.ResponseWriter, err) | ||
} | ||
return | ||
} | ||
|
||
p.Service.Selector["app"] = p.Deployment.Name | ||
p.Service.Namespace = p.Deployment.Namespace | ||
if err := service.CreateService(sp, &p.Service); err != nil { | ||
if errors.IsAlreadyExists(err) { | ||
response.Conflict(req.Request, resp.ResponseWriter, fmt.Errorf("Service Name: %s already existed", p.Service.Name)) | ||
} else { | ||
response.InternalServerError(req.Request, resp.ResponseWriter, err) | ||
} | ||
return | ||
} | ||
|
||
if err := session.Insert(entity.DeploymentCollectionName, &p.Deployment); err != nil { | ||
if mgo.IsDup(err) { | ||
response.Conflict(req.Request, resp.ResponseWriter, fmt.Errorf("Deployment Name: %s already existed", p.Deployment.Name)) | ||
} else { | ||
response.InternalServerError(req.Request, resp.ResponseWriter, err) | ||
} | ||
return | ||
} | ||
|
||
if err := session.Insert(entity.ServiceCollectionName, &p.Service); err != nil { | ||
if mgo.IsDup(err) { | ||
response.Conflict(req.Request, resp.ResponseWriter, fmt.Errorf("Deployment Name: %s already existed", p.Deployment.Name)) | ||
} else { | ||
response.InternalServerError(req.Request, resp.ResponseWriter, err) | ||
} | ||
return | ||
} | ||
resp.WriteHeaderAndEntity(http.StatusCreated, p) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package server | ||
|
||
import ( | ||
"encoding/json" | ||
"math/rand" | ||
"net/http" | ||
"net/http/httptest" | ||
"strings" | ||
"testing" | ||
"time" | ||
|
||
restful "github.com/emicklei/go-restful" | ||
"github.com/linkernetworks/mongo" | ||
"github.com/linkernetworks/vortex/src/config" | ||
"github.com/linkernetworks/vortex/src/entity" | ||
"github.com/linkernetworks/vortex/src/serviceprovider" | ||
"github.com/moby/moby/pkg/namesgenerator" | ||
"github.com/stretchr/testify/suite" | ||
"gopkg.in/mgo.v2/bson" | ||
) | ||
|
||
func init() { | ||
rand.Seed(time.Now().UnixNano()) | ||
} | ||
|
||
type AppTestSuite struct { | ||
suite.Suite | ||
sp *serviceprovider.Container | ||
wc *restful.Container | ||
session *mongo.Session | ||
} | ||
|
||
func (suite *AppTestSuite) SetupSuite() { | ||
cf := config.MustRead("../../config/testing.json") | ||
sp := serviceprovider.NewForTesting(cf) | ||
|
||
suite.sp = sp | ||
//init session | ||
suite.session = sp.Mongo.NewSession() | ||
//init restful container | ||
suite.wc = restful.NewContainer() | ||
service := newAppService(suite.sp) | ||
suite.wc.Add(service) | ||
} | ||
|
||
func (suite *AppTestSuite) TearDownSuite() {} | ||
|
||
func TestAppSuite(t *testing.T) { | ||
suite.Run(t, new(AppTestSuite)) | ||
} | ||
|
||
func (suite *AppTestSuite) TestCreateApp() { | ||
namespace := "default" | ||
containers := []entity.Container{ | ||
{ | ||
Name: namesgenerator.GetRandomName(0), | ||
Image: "busybox", | ||
Command: []string{"sleep", "3600"}, | ||
}, | ||
} | ||
tName := namesgenerator.GetRandomName(0) | ||
deploy := entity.Deployment{ | ||
Name: tName, | ||
Namespace: namespace, | ||
Labels: map[string]string{}, | ||
EnvVars: map[string]string{}, | ||
Containers: containers, | ||
Volumes: []entity.DeploymentVolume{}, | ||
Networks: []entity.DeploymentNetwork{}, | ||
Capability: true, | ||
NetworkType: entity.DeploymentHostNetwork, | ||
NodeAffinity: []string{}, | ||
Replicas: 1, | ||
} | ||
|
||
ports := []entity.ServicePort{ | ||
{ | ||
Name: namesgenerator.GetRandomName(0), | ||
Port: int32(80), | ||
TargetPort: 80, | ||
NodePort: int32(30000), | ||
}, | ||
} | ||
|
||
serviceName := namesgenerator.GetRandomName(0) | ||
service := entity.Service{ | ||
ID: bson.NewObjectId(), | ||
Name: serviceName, | ||
Namespace: "default", | ||
Type: "NodePort", | ||
Selector: map[string]string{}, | ||
Ports: ports, | ||
} | ||
|
||
app := entity.App{ | ||
Deployment: deploy, | ||
Service: service, | ||
} | ||
bodyBytes, err := json.MarshalIndent(app, "", " ") | ||
suite.NoError(err) | ||
|
||
bodyReader := strings.NewReader(string(bodyBytes)) | ||
httpRequest, err := http.NewRequest("POST", "http://localhost:7890/v1/apps", bodyReader) | ||
suite.NoError(err) | ||
|
||
httpRequest.Header.Add("Content-Type", "application/json") | ||
httpWriter := httptest.NewRecorder() | ||
suite.wc.Dispatch(httpWriter, httpRequest) | ||
assertResponseCode(suite.T(), http.StatusCreated, httpWriter) | ||
defer suite.session.Remove(entity.DeploymentCollectionName, "name", app.Deployment.Name) | ||
defer suite.session.Remove(entity.ServiceCollectionName, "name", app.Service.Name) | ||
|
||
//load data to check | ||
retDeployment := entity.Deployment{} | ||
err = suite.session.FindOne(entity.DeploymentCollectionName, bson.M{"name": deploy.Name}, &retDeployment) | ||
suite.NoError(err) | ||
suite.NotEqual("", retDeployment.ID) | ||
suite.Equal(deploy.Name, retDeployment.Name) | ||
suite.Equal(len(deploy.Containers), len(retDeployment.Containers)) | ||
|
||
//We use the new write but empty input which will cause the readEntity Error | ||
httpWriter = httptest.NewRecorder() | ||
suite.wc.Dispatch(httpWriter, httpRequest) | ||
assertResponseCode(suite.T(), http.StatusBadRequest, httpWriter) | ||
//Create again and it should fail since the name exist | ||
bodyReader = strings.NewReader(string(bodyBytes)) | ||
httpRequest, err = http.NewRequest("POST", "http://localhost:7890/v1/apps", bodyReader) | ||
suite.NoError(err) | ||
httpRequest.Header.Add("Content-Type", "application/json") | ||
httpWriter = httptest.NewRecorder() | ||
suite.wc.Dispatch(httpWriter, httpRequest) | ||
assertResponseCode(suite.T(), http.StatusConflict, httpWriter) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"deployment": { | ||
"name": "@APPNAME@", | ||
"labels":{}, | ||
"envVars":{ | ||
"myip":"1.2.3.4" | ||
}, | ||
"namespace":"default", | ||
"containers":[ | ||
{ | ||
"name":"first-container", | ||
"image":"busybox", | ||
"command":["sleep","3600"] | ||
} | ||
], | ||
"networks":[ | ||
], | ||
"volumes":[], | ||
"restartPolicy":"Always", | ||
"capability": true, | ||
"networkType": "host", | ||
"nodeAffinity": [], | ||
"replicas":2 | ||
}, | ||
"service":{ | ||
"name": "@APPNAME@", | ||
"namespace":"default", | ||
"type":"ClusterIP", | ||
"selector":{}, | ||
"ports":[ | ||
{ | ||
"protocol": "TCP", | ||
"port": 27017, | ||
"targetPort": 27017 | ||
} | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
if [ -z "$appName" ]; then | ||
export name=$(date | md5sum | cut -b 1-19) | ||
export appName="test-app-$name" | ||
|
||
rm -rf app.json | ||
cp app.info app.json | ||
sed -i "s/@APPNAME@/${appName}/" app.json | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"type":"system", | ||
"isDPDKPort":false, | ||
"name":"@NETWORKNAME@", | ||
"vlanTags":[], | ||
"bridgeName":"br0", | ||
"nodes":[ | ||
{ | ||
"name": "@NODENAME@", | ||
"physicalInterfaces": [{ | ||
"name":"@ETHNAME@" | ||
}] | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#!/usr/bin/env bats | ||
|
||
load init | ||
|
||
@test "Create App" { | ||
http -v --check-status 127.0.0.1:7890/v1/apps < app.json | ||
[ $? = 0 ] | ||
#Wait the Deployment | ||
#jsonpath="{.status.phase}" | ||
NEXT_WAIT_TIME=0 | ||
WAIT_LIMIT=40 | ||
until kubectl get deployment ${appName} -o jsonpath="{.status.readyReplicas}" | grep "2" || [ $NEXT_WAIT_TIME -eq $WAIT_LIMIT ]; do | ||
sleep 2 | ||
kubectl get deployment ${appName} | ||
NEXT_WAIT_TIME=$((NEXT_WAIT_TIME+ 1)) | ||
done | ||
[ $NEXT_WAIT_TIME != $WAIT_LIMIT ] | ||
} | ||
|
||
@test "List Service" { | ||
run bash -c "http http://127.0.0.1:7890/v1/services 2>/dev/null | jq -r '.[] | select(.name == \"${appName}\").name'" | ||
[ "$output" = "${appName}" ] | ||
[ $status = 0 ] | ||
} | ||
|
||
@test "List Deployment" { | ||
run bash -c "http http://127.0.0.1:7890/v1/deployments 2>/dev/null | jq -r '.[] | select(.name == \"${appName}\").name'" | ||
[ "$output" = "${appName}" ] | ||
[ $status = 0 ] | ||
} | ||
|
||
@test "Check Deployment Label" { | ||
run kubectl get deployment ${appName} -o jsonpath="{.spec.template.metadata.labels.app}" | ||
[ "$output" = "${appName}" ] | ||
[ $status = 0 ] | ||
} | ||
|
||
@test "Check Service Selector" { | ||
run kubectl get svc ${appName} -o jsonpath="{.spec.selector.app}" | ||
[ "$output" = "${appName}" ] | ||
[ $status = 0 ] | ||
} | ||
|
||
@test "Delete Deployment" { | ||
run bash -c "http http://127.0.0.1:7890/v1/deployments 2>/dev/null | jq -r '.[] | select(.name == \"${appName}\").id'" | ||
run http DELETE http://127.0.0.1:7890/v1/deployments/${output} 2>/dev/null | ||
[ $status = 0 ] | ||
} | ||
|
||
@test "Delete Services" { | ||
run bash -c "http http://127.0.0.1:7890/v1/services 2>/dev/null | jq -r '.[] | select(.name == \"${appName}\").id'" | ||
run http DELETE http://127.0.0.1:7890/v1/services/${output} 2>/dev/null | ||
[ $status = 0 ] | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.