Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
apollo
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
openSource
apollo
Commits
7a27efe2
Commit
7a27efe2
authored
May 04, 2016
by
Jason Song
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #167 from lepdou/lepdou_master
配置namespace之间同步
parents
47c4cd25
472f42bb
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
260 additions
and
149 deletions
+260
-149
data.sql
apollo-adminservice/src/test/resources/data.sql
+2
-1
pom.xml
apollo-portal/pom.xml
+1
-0
ConfigController.java
.../com/ctrip/apollo/portal/controller/ConfigController.java
+16
-1
NamespaceIdentifer.java
...va/com/ctrip/apollo/portal/entity/NamespaceIdentifer.java
+10
-0
ConfigService.java
...n/java/com/ctrip/apollo/portal/service/ConfigService.java
+90
-73
AppUtils.js
apollo-portal/src/main/resources/static/scripts/AppUtils.js
+1
-1
SyncConfigController.js
...ces/static/scripts/controller/app/SyncConfigController.js
+57
-17
ConfigService.js
...c/main/resources/static/scripts/services/ConfigService.js
+34
-0
app.html
apollo-portal/src/main/resources/static/views/app.html
+0
-8
sync.html
apollo-portal/src/main/resources/static/views/sync.html
+47
-46
ConfigServiceTest.java
.../test/java/com/ctrip/apollo/portal/ConfigServiceTest.java
+2
-2
No files found.
apollo-adminservice/src/test/resources/data.sql
View file @
7a27efe2
...
...
@@ -20,6 +20,7 @@ INSERT INTO AppNamespace (AppId, Name) VALUES ('100003173', 'fx.apollo.portal');
INSERT
INTO
AppNamespace
(
AppID
,
Name
)
VALUES
(
'fxhermesproducer'
,
'fx.hermes.producer'
);
INSERT
INTO
Namespace
(
Id
,
AppId
,
ClusterName
,
NamespaceName
)
VALUES
(
1
,
'100003171'
,
'default'
,
'application'
);
INSERT
INTO
Namespace
(
Id
,
AppId
,
ClusterName
,
NamespaceName
)
VALUES
(
5
,
'100003171'
,
'cluster1'
,
'application'
);
INSERT
INTO
Namespace
(
Id
,
AppId
,
ClusterName
,
NamespaceName
)
VALUES
(
2
,
'fxhermesproducer'
,
'default'
,
'fx.hermes.producer'
);
INSERT
INTO
Namespace
(
Id
,
AppId
,
ClusterName
,
NamespaceName
)
VALUES
(
3
,
'100003172'
,
'default'
,
'application'
);
INSERT
INTO
Namespace
(
Id
,
AppId
,
ClusterName
,
NamespaceName
)
VALUES
(
4
,
'100003173'
,
'default'
,
'application'
);
...
...
@@ -27,7 +28,7 @@ INSERT INTO Namespace (Id, AppId, ClusterName, NamespaceName) VALUES (4, '100003
INSERT
INTO
Item
(
NamespaceId
,
`Key`
,
Value
,
Comment
)
VALUES
(
1
,
'k1'
,
'v1'
,
'comment1'
);
INSERT
INTO
Item
(
NamespaceId
,
`Key`
,
Value
,
Comment
)
VALUES
(
1
,
'k2'
,
'v2'
,
'comment2'
);
INSERT
INTO
Item
(
NamespaceId
,
`Key`
,
Value
,
Comment
)
VALUES
(
2
,
'k3'
,
'v3'
,
'comment3'
);
INSERT
INTO
Item
(
NamespaceId
,
`Key`
,
Value
,
Comment
)
VALUES
(
5
,
'k3'
,
'v4'
,
'comment4'
);
INSERT
INTO
Item
(
NamespaceId
,
`Key`
,
Value
,
Comment
,
LineNum
)
VALUES
(
5
,
'k1'
,
'v4'
,
'comment4'
,
1
);
INSERT
INTO
RELEASE
(
ReleaseKey
,
Name
,
Comment
,
AppId
,
ClusterName
,
NamespaceName
,
Configurations
)
VALUES
(
'TEST-RELEASE-KEY'
,
'REV1'
,
'First Release'
,
'100003171'
,
'default'
,
'application'
,
'{"k1":"v1"}'
);
apollo-portal/pom.xml
View file @
7a27efe2
...
...
@@ -24,6 +24,7 @@
<scope>
test
</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
...
...
apollo-portal/src/main/java/com/ctrip/apollo/portal/controller/ConfigController.java
View file @
7a27efe2
...
...
@@ -14,6 +14,8 @@ import com.ctrip.apollo.portal.entity.form.NamespaceReleaseModel;
import
com.ctrip.apollo.portal.service.ConfigService
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestMapping
;
...
...
@@ -102,7 +104,20 @@ public class ConfigController {
throw
new
BadRequestException
(
"request model is invalid"
);
}
return
configService
.
compare
(
model
.
getSyncItems
(),
model
.
getSyncToNamespaces
());
return
configService
.
compare
(
model
.
getSyncToNamespaces
(),
model
.
getSyncItems
());
}
@RequestMapping
(
value
=
"/namespaces/{namespaceName}/items"
,
method
=
RequestMethod
.
PUT
,
consumes
=
{
"application/json"
})
public
ResponseEntity
<
Void
>
update
(
@RequestBody
NamespaceSyncModel
model
){
if
(
model
==
null
){
throw
new
BadRequestException
(
"request payload shoud not be null"
);
}
if
(
model
.
isInvalid
())
{
throw
new
BadRequestException
(
"request model is invalid"
);
}
configService
.
syncItems
(
model
.
getSyncToNamespaces
(),
model
.
getSyncItems
());
return
ResponseEntity
.
status
(
HttpStatus
.
OK
).
build
();
}
}
apollo-portal/src/main/java/com/ctrip/apollo/portal/entity/NamespaceIdentifer.java
View file @
7a27efe2
...
...
@@ -47,4 +47,14 @@ public class NamespaceIdentifer implements Verifiable{
public
boolean
isInvalid
()
{
return
StringUtils
.
isContainEmpty
(
env
,
clusterName
,
namespaceName
);
}
@Override
public
String
toString
()
{
return
"NamespaceIdentifer{"
+
"appId='"
+
appId
+
'\''
+
", env='"
+
env
+
'\''
+
", clusterName='"
+
clusterName
+
'\''
+
", namespaceName='"
+
namespaceName
+
'\''
+
'}'
;
}
}
apollo-portal/src/main/java/com/ctrip/apollo/portal/service/ConfigService.java
View file @
7a27efe2
...
...
@@ -54,11 +54,6 @@ public class ConfigService {
/**
* load cluster all namespace info with items
*
* @param appId
* @param env
* @param clusterName
* @return
*/
public
List
<
NamespaceVO
>
findNampspaces
(
String
appId
,
Env
env
,
String
clusterName
)
{
...
...
@@ -76,7 +71,7 @@ public class ConfigService {
namespaceVOs
.
add
(
namespaceVO
);
}
catch
(
Exception
e
)
{
logger
.
error
(
"parse namespace error. app id:{}, env:{}, clusterName:{}, namespace:{}"
,
appId
,
env
,
clusterName
,
namespace
.
getNamespaceName
(),
e
);
appId
,
env
,
clusterName
,
namespace
.
getNamespaceName
(),
e
);
throw
e
;
}
}
...
...
@@ -85,7 +80,7 @@ public class ConfigService {
}
@SuppressWarnings
(
"unchecked"
)
private
NamespaceVO
parseNamespace
(
String
appId
,
Env
env
,
String
clusterName
,
NamespaceDTO
namespace
)
{
private
NamespaceVO
parseNamespace
(
String
appId
,
Env
env
,
String
clusterName
,
NamespaceDTO
namespace
)
{
NamespaceVO
namespaceVO
=
new
NamespaceVO
();
namespaceVO
.
setNamespace
(
namespace
);
...
...
@@ -100,10 +95,10 @@ public class ConfigService {
try
{
release
=
releaseAPI
.
loadLatestRelease
(
appId
,
env
,
clusterName
,
namespaceName
);
releaseItems
=
gson
.
fromJson
(
release
.
getConfigurations
(),
Map
.
class
);
}
catch
(
HttpClientErrorException
e
)
{
if
(
e
.
getStatusCode
()
==
HttpStatus
.
NOT_FOUND
){
}
catch
(
HttpClientErrorException
e
)
{
if
(
e
.
getStatusCode
()
==
HttpStatus
.
NOT_FOUND
)
{
logger
.
warn
(
ExceptionUtils
.
toString
(
e
));
}
else
{
}
else
{
throw
e
;
}
}
...
...
@@ -142,7 +137,7 @@ public class ConfigService {
/**
* parse config text and update config items
*
*
* @return parse result
*/
public
void
updateConfigItemByText
(
NamespaceTextModel
model
)
{
...
...
@@ -154,8 +149,8 @@ public class ConfigService {
String
configText
=
model
.
getConfigText
();
ItemChangeSets
changeSets
=
resolver
.
resolve
(
namespaceId
,
configText
,
itemAPI
.
findItems
(
appId
,
env
,
clusterName
,
namespaceName
));
if
(
changeSets
.
isEmpty
()){
itemAPI
.
findItems
(
appId
,
env
,
clusterName
,
namespaceName
));
if
(
changeSets
.
isEmpty
())
{
return
;
}
try
{
...
...
@@ -171,85 +166,107 @@ public class ConfigService {
/**
* createRelease config items
*
* @return
*/
public
ReleaseDTO
createRelease
(
NamespaceReleaseModel
model
)
{
return
releaseAPI
.
release
(
model
.
getAppId
(),
model
.
getEnv
(),
model
.
getClusterName
(),
model
.
getNamespaceName
(),
model
.
getReleaseBy
(),
model
.
getReleaseComment
());
model
.
getNamespaceName
(),
model
.
getReleaseBy
(),
model
.
getReleaseComment
());
}
public
List
<
ItemDTO
>
findItems
(
String
appId
,
Env
env
,
String
clusterName
,
String
namespaceName
){
public
List
<
ItemDTO
>
findItems
(
String
appId
,
Env
env
,
String
clusterName
,
String
namespaceName
)
{
return
itemAPI
.
findItems
(
appId
,
env
,
clusterName
,
namespaceName
);
}
public
List
<
ItemDiffs
>
compare
(
List
<
ItemDTO
>
sourceItems
,
List
<
NamespaceIdentifer
>
comparedNamespaces
){
public
void
syncItems
(
List
<
NamespaceIdentifer
>
comparedNamespaces
,
List
<
ItemDTO
>
sourceItems
){
List
<
ItemDiffs
>
itemDiffs
=
compare
(
comparedNamespaces
,
sourceItems
);
for
(
ItemDiffs
itemDiff:
itemDiffs
){
NamespaceIdentifer
namespaceIdentifer
=
itemDiff
.
getNamespace
();
try
{
itemAPI
.
updateItems
(
namespaceIdentifer
.
getAppId
(),
namespaceIdentifer
.
getEnv
(),
namespaceIdentifer
.
getClusterName
(),
namespaceIdentifer
.
getNamespaceName
(),
itemDiff
.
getDiffs
());
}
catch
(
HttpClientErrorException
e
)
{
logger
.
error
(
"sync items error. namespace:{}"
,
namespaceIdentifer
);
throw
new
ServiceException
(
String
.
format
(
"sync item error. env:%s, clusterName:%s"
,
namespaceIdentifer
.
getEnv
(),
namespaceIdentifer
.
getClusterName
()),
e
);
}
}
}
public
List
<
ItemDiffs
>
compare
(
List
<
NamespaceIdentifer
>
comparedNamespaces
,
List
<
ItemDTO
>
sourceItems
)
{
List
<
ItemDiffs
>
result
=
new
LinkedList
<>();
String
appId
,
clusterName
,
namespaceName
;
Env
env
;
for
(
NamespaceIdentifer
namespace:
comparedNamespaces
){
appId
=
namespace
.
getAppId
();
clusterName
=
namespace
.
getClusterName
();
namespaceName
=
namespace
.
getNamespaceName
();
env
=
namespace
.
getEnv
();
NamespaceDTO
namespaceDTO
=
null
;
try
{
namespaceDTO
=
namespaceAPI
.
loadNamespace
(
appId
,
env
,
clusterName
,
namespaceName
);
}
catch
(
NotFoundException
e
){
logger
.
warn
(
"namespace not exist. appId:{}, env:{}, clusterName:{}, namespaceName:{}"
,
appId
,
env
,
clusterName
,
namespaceName
);
throw
new
BadRequestException
(
String
.
format
(
"namespace not exist. appId:%s, env:%s, clusterName:%s, namespaceName:%s"
,
appId
,
env
,
clusterName
,
namespaceName
));
}
for
(
NamespaceIdentifer
namespace
:
comparedNamespaces
)
{
ItemDiffs
itemDiffs
=
new
ItemDiffs
(
namespace
);
ItemChangeSets
changeSets
=
new
ItemChangeSets
();
itemDiffs
.
setDiffs
(
changeSets
);
List
<
ItemDTO
>
targetItems
=
itemAPI
.
findItems
(
namespace
.
getAppId
(),
namespace
.
getEnv
(),
namespace
.
getClusterName
(),
namespace
.
getNamespaceName
());
long
namespaceId
=
namespaceDTO
.
getId
();
if
(
CollectionUtils
.
isEmpty
(
targetItems
)){
//all source items is added
int
lineNum
=
1
;
for
(
ItemDTO
sourceItem:
sourceItems
){
changeSets
.
addCreateItem
(
buildItem
(
namespaceId
,
lineNum
++,
sourceItem
));
}
}
else
{
Map
<
String
,
ItemDTO
>
keyMapItem
=
BeanUtils
.
mapByKey
(
"key"
,
targetItems
);
String
key
,
sourceValue
,
sourceComment
;
ItemDTO
targetItem
=
null
;
int
maxLineNum
=
targetItems
.
size
();
//append to last
for
(
ItemDTO
sourceItem:
sourceItems
){
key
=
sourceItem
.
getKey
();
sourceValue
=
sourceItem
.
getValue
();
sourceComment
=
sourceItem
.
getComment
();
targetItem
=
keyMapItem
.
get
(
key
);
if
(
targetItem
==
null
)
{
//added items
changeSets
.
addCreateItem
(
buildItem
(
namespaceId
,
++
maxLineNum
,
sourceItem
));
}
else
if
(!
sourceValue
.
equals
(
targetItem
.
getValue
())
||
!
sourceComment
.
equals
(
targetItem
.
getComment
())){
//modified items
targetItem
.
setValue
(
sourceValue
);
targetItem
.
setComment
(
sourceComment
);
changeSets
.
addUpdateItem
(
targetItem
);
}
}
}
itemDiffs
.
setDiffs
(
parseChangeSets
(
namespace
,
sourceItems
));
result
.
add
(
itemDiffs
);
}
return
result
;
}
private
ItemDTO
buildItem
(
long
namespaceId
,
int
lineNum
,
ItemDTO
sourceItem
){
private
long
getNamespaceId
(
NamespaceIdentifer
namespaceIdentifer
)
{
String
appId
=
namespaceIdentifer
.
getAppId
();
String
clusterName
=
namespaceIdentifer
.
getClusterName
();
String
namespaceName
=
namespaceIdentifer
.
getNamespaceName
();
Env
env
=
namespaceIdentifer
.
getEnv
();
NamespaceDTO
namespaceDTO
=
null
;
try
{
namespaceDTO
=
namespaceAPI
.
loadNamespace
(
appId
,
env
,
clusterName
,
namespaceName
);
}
catch
(
NotFoundException
e
)
{
logger
.
warn
(
"namespace not exist. appId:{}, env:{}, clusterName:{}, namespaceName:{}"
,
appId
,
env
,
clusterName
,
namespaceName
);
throw
new
BadRequestException
(
String
.
format
(
"namespace not exist. appId:%s, env:%s, clusterName:%s, namespaceName:%s"
,
appId
,
env
,
clusterName
,
namespaceName
));
}
return
namespaceDTO
.
getId
();
}
private
ItemChangeSets
parseChangeSets
(
NamespaceIdentifer
namespace
,
List
<
ItemDTO
>
sourceItems
){
ItemChangeSets
changeSets
=
new
ItemChangeSets
();
List
<
ItemDTO
>
targetItems
=
itemAPI
.
findItems
(
namespace
.
getAppId
(),
namespace
.
getEnv
(),
namespace
.
getClusterName
(),
namespace
.
getNamespaceName
());
long
namespaceId
=
getNamespaceId
(
namespace
);
if
(
CollectionUtils
.
isEmpty
(
targetItems
))
{
//all source items is added
int
lineNum
=
1
;
for
(
ItemDTO
sourceItem
:
sourceItems
)
{
changeSets
.
addCreateItem
(
buildItem
(
namespaceId
,
lineNum
++,
sourceItem
));
}
}
else
{
Map
<
String
,
ItemDTO
>
keyMapItem
=
BeanUtils
.
mapByKey
(
"key"
,
targetItems
);
String
key
,
sourceValue
,
sourceComment
;
ItemDTO
targetItem
=
null
;
int
maxLineNum
=
targetItems
.
size
();
//append to last
for
(
ItemDTO
sourceItem
:
sourceItems
)
{
key
=
sourceItem
.
getKey
();
sourceValue
=
sourceItem
.
getValue
();
sourceComment
=
sourceItem
.
getComment
();
targetItem
=
keyMapItem
.
get
(
key
);
if
(
targetItem
==
null
)
{
//added items
changeSets
.
addCreateItem
(
buildItem
(
namespaceId
,
++
maxLineNum
,
sourceItem
));
}
else
if
(!
sourceValue
.
equals
(
targetItem
.
getValue
())
||
!
sourceComment
.
equals
(
targetItem
.
getComment
()))
{
//modified items
targetItem
.
setValue
(
sourceValue
);
targetItem
.
setComment
(
sourceComment
);
changeSets
.
addUpdateItem
(
targetItem
);
}
}
}
return
changeSets
;
}
private
ItemDTO
buildItem
(
long
namespaceId
,
int
lineNum
,
ItemDTO
sourceItem
)
{
ItemDTO
createdItem
=
new
ItemDTO
();
BeanUtils
.
copyEntityProperties
(
sourceItem
,
createdItem
);
createdItem
.
setLineNum
(
lineNum
++);
...
...
apollo-portal/src/main/resources/static/scripts/AppUtils.js
View file @
7a27efe2
...
...
@@ -12,7 +12,7 @@ appUtil.service('AppUtil', [function () {
if
(
!
path
)
{
return
{};
}
if
(
path
.
startsWith
(
"/"
)
)
{
if
(
path
.
indexOf
(
'/'
)
==
0
)
{
path
=
path
.
substring
(
1
,
path
.
length
);
}
var
params
=
path
.
split
(
"&"
);
...
...
apollo-portal/src/main/resources/static/scripts/controller/app/SyncConfigController.js
View file @
7a27efe2
sync_item_module
.
controller
(
"SyncItemController"
,
[
'$scope'
,
'$location'
,
'toastr'
,
'AppService'
,
'AppUtil'
,
'ConfigService'
,
function
(
$scope
,
$location
,
toastr
,
AppService
,
AppUtil
,
ConfigService
)
{
[
'$scope'
,
'$location'
,
'
$window'
,
'
toastr'
,
'AppService'
,
'AppUtil'
,
'ConfigService'
,
function
(
$scope
,
$location
,
$window
,
toastr
,
AppService
,
AppUtil
,
ConfigService
)
{
var
params
=
AppUtil
.
parseParams
(
$location
.
$$url
);
var
currentUser
=
'test_user'
;
...
...
@@ -13,15 +13,16 @@ sync_item_module.controller("SyncItemController",
////// load env //////
AppService
.
load_nav_tree
(
$scope
.
pageContext
.
appId
).
then
(
function
(
result
)
{
$scope
.
clusters
=
result
.
nodes
;
$scope
.
clusters
=
[];
$scope
.
namespaceIdentifers
=
[];
result
.
nodes
.
forEach
(
function
(
node
)
{
var
env
=
node
.
env
;
node
.
clusters
.
forEach
(
function
(
cluster
)
{
cluster
.
env
=
env
;
cluster
.
checked
=
false
;
$scope
.
clusters
.
push
(
cluster
);
})
if
(
env
!=
$scope
.
pageContext
.
env
||
cluster
.
name
!=
$scope
.
pageContext
.
clusterName
){
$scope
.
namespaceIdentifers
.
push
(
cluster
);
}
})
});
},
function
(
result
)
{
toastr
.
error
(
AppUtil
.
errorMsg
(
result
),
"加载环境出错"
);
...
...
@@ -30,8 +31,8 @@ sync_item_module.controller("SyncItemController",
var
envAllSelected
=
false
;
$scope
.
toggleEnvsCheckedStatus
=
function
()
{
envAllSelected
=
!
envAllSelected
;
$scope
.
clusters
.
forEach
(
function
(
clust
er
)
{
clust
er
.
checked
=
envAllSelected
;
$scope
.
namespaceIdentifers
.
forEach
(
function
(
namespaceIdentif
er
)
{
namespaceIdentif
er
.
checked
=
envAllSelected
;
})
};
...
...
@@ -39,9 +40,12 @@ sync_item_module.controller("SyncItemController",
ConfigService
.
find_items
(
$scope
.
pageContext
.
appId
,
$scope
.
pageContext
.
env
,
$scope
.
pageContext
.
clusterName
,
$scope
.
pageContext
.
namespaceName
).
then
(
function
(
result
)
{
$scope
.
sourceItems
=
result
;
$scope
.
sourceItems
.
forEach
(
function
(
item
)
{
item
.
checked
=
false
;
$scope
.
sourceItems
=
[];
result
.
forEach
(
function
(
item
)
{
if
(
item
.
key
){
item
.
checked
=
false
;
$scope
.
sourceItems
.
push
(
item
);
}
})
},
function
(
result
)
{
...
...
@@ -56,6 +60,44 @@ sync_item_module.controller("SyncItemController",
})
};
$scope
.
diff
=
function
()
{
ConfigService
.
diff
(
$scope
.
pageContext
.
namespaceName
,
parseSyncSourceData
()).
then
(
function
(
result
)
{
$scope
.
diffs
=
result
;
$scope
.
syncItemNextStep
(
1
);
},
function
(
result
)
{
toastr
.
error
(
AppUtil
.
errorMsg
(
result
));
});
};
$scope
.
syncItems
=
function
()
{
ConfigService
.
sync_items
(
$scope
.
pageContext
.
namespaceName
,
parseSyncSourceData
()).
then
(
function
(
result
)
{
$scope
.
syncItemStep
+=
1
;
},
function
(
result
)
{
toastr
.
error
(
AppUtil
.
errorMsg
(
result
));
});
};
function
parseSyncSourceData
()
{
var
sourceData
=
{
syncToNamespaces
:
[],
syncItems
:
[]
};
var
namespaceName
=
$scope
.
pageContext
.
namespaceName
;
$scope
.
namespaceIdentifers
.
forEach
(
function
(
namespaceIdentifer
)
{
if
(
namespaceIdentifer
.
checked
){
namespaceIdentifer
.
clusterName
=
namespaceIdentifer
.
name
;
namespaceIdentifer
.
namespaceName
=
namespaceName
;
sourceData
.
syncToNamespaces
.
push
(
namespaceIdentifer
);
}
});
$scope
.
sourceItems
.
forEach
(
function
(
item
)
{
if
(
item
.
checked
)
{
sourceData
.
syncItems
.
push
(
item
);
}
});
return
sourceData
;
}
////// flow control ///////
$scope
.
syncItemStep
=
1
;
...
...
@@ -63,14 +105,12 @@ sync_item_module.controller("SyncItemController",
$scope
.
syncItemStep
+=
offset
;
};
$scope
.
syncItems
=
function
()
{
$
scope
.
syncItemStep
+=
1
;
$scope
.
backToAppHomePage
=
function
()
{
$
window
.
location
.
href
=
'/views/app.html?#appid='
+
$scope
.
pageContext
.
appId
;
};
$scope
.
destorySync
=
function
(
)
{
$scope
.
syncItemStep
=
1
;
$scope
.
switchSelect
=
function
(
o
)
{
o
.
checked
=
!
o
.
checked
;
}
}]);
apollo-portal/src/main/resources/static/scripts/services/ConfigService.js
View file @
7a27efe2
...
...
@@ -17,6 +17,16 @@ appService.service("ConfigService", ['$resource', '$q', function ($resource, $q)
release
:
{
method
:
'POST'
,
url
:
'/apps/:appId/env/:env/clusters/:clusterName/namespaces/:namespaceName/release'
},
diff
:
{
method
:
'POST'
,
url
:
'/namespaces/:namespaceName/diff'
,
isArray
:
true
},
sync_item
:
{
method
:
'PUT'
,
url
:
'/namespaces/:namespaceName/items'
,
isArray
:
false
}
});
...
...
@@ -87,6 +97,30 @@ appService.service("ConfigService", ['$resource', '$q', function ($resource, $q)
d
.
reject
(
result
);
});
return
d
.
promise
;
},
diff
:
function
(
namespaceName
,
sourceData
)
{
var
d
=
$q
.
defer
();
config_source
.
diff
({
namespaceName
:
namespaceName
},
sourceData
,
function
(
result
)
{
d
.
resolve
(
result
);
},
function
(
result
)
{
d
.
reject
(
result
);
});
return
d
.
promise
;
},
sync_items
:
function
(
namespaceName
,
sourceData
)
{
var
d
=
$q
.
defer
();
config_source
.
sync_item
({
namespaceName
:
namespaceName
},
sourceData
,
function
(
result
)
{
d
.
resolve
(
result
);
},
function
(
result
)
{
d
.
reject
(
result
);
});
return
d
.
promise
;
}
}
...
...
apollo-portal/src/main/resources/static/views/app.html
View file @
7a27efe2
...
...
@@ -65,14 +65,6 @@
</div>
</section>
<a
class=
"list-group-item"
data-toggle=
"modal"
data-target=
"#syncItems"
>
<div
class=
"row"
>
<div
class=
"col-md-2"
><img
src=
"../img/sync.png"
class=
"i-20"
></div>
<div
class=
"col-md-7 hidden-xs"
>
<p
class=
"apps-description"
>
配置同步
</p>
</div>
</div>
</a>
<a
class=
"list-group-item"
data-toggle=
"modal"
data-target=
"#createEnvModal"
ng-show=
"missEnvs.length > 0"
>
<div
class=
"row"
>
...
...
apollo-portal/src/main/resources/static/views/sync.html
View file @
7a27efe2
...
...
@@ -29,12 +29,12 @@
ng-click=
"syncItemNextStep(-1)"
>
上一步
</button>
<button
type=
"button"
class=
"btn btn-primary"
ng-show=
"syncItemStep < 2"
ng-click=
"
syncItemNextStep(1
)"
>
下一步
ng-click=
"
diff(
)"
>
下一步
</button>
<button
type=
"button"
class=
"btn btn-success"
ng-show=
"syncItemStep == 2"
ng-click=
"syncItems()"
>
同步
</button>
<button
type=
"button"
class=
"btn btn-primary"
data-dismiss=
"modal"
ng-show=
"syncItemStep == 3"
ng-click=
"
destorySync
()"
>
返回
ng-click=
"
backToAppHomePage
()"
>
返回
</button>
</div>
</div>
...
...
@@ -55,10 +55,11 @@
</tr>
</thead>
<tbody>
<tr
ng-repeat=
"cluster in clusters"
>
<td
width=
"10%"
><input
type=
"checkbox"
ng-checked=
"cluster.checked"
></td>
<td
width=
"30%"
>
{{cluster.env}}
</td>
<td
width=
"60%"
>
{{cluster.name}}
</td>
<tr
ng-repeat=
"namespaceIdentifer in namespaceIdentifers"
>
<td
width=
"10%"
><input
type=
"checkbox"
ng-checked=
"namespaceIdentifer.checked"
ng-click=
"switchSelect(namespaceIdentifer)"
></td>
<td
width=
"30%"
>
{{namespaceIdentifer.env}}
</td>
<td
width=
"60%"
>
{{namespaceIdentifer.name}}
</td>
</tr>
</tbody>
</table>
...
...
@@ -85,10 +86,14 @@
</thead>
<tbody>
<tr
ng-repeat=
"item in sourceItems"
>
<td
width=
"10%"
><input
type=
"checkbox"
ng-checked=
"item.checked"
></td>
<td
width=
"10%"
><input
type=
"checkbox"
ng-checked=
"item.checked"
ng-click=
"switchSelect(item)"
></td>
<td
width=
"20%"
>
{{item.key}}
</td>
<td
width=
"50%"
>
{{item.value | limitTo: 36}} {{item.value.length > 36 ? '...' : ''}}
</td>
<td
width=
"20%"
>
{{item.comment | limitTo: 15}}{{item.comment.length > 15 ? '...' : ''}}
</td>
<td
width=
"50%"
>
{{item.value | limitTo: 36}} {{item.value.length > 36 ? '...' : ''}}
</td>
<td
width=
"20%"
>
{{item.comment | limitTo: 15}}{{item.comment.length > 15 ? '...' :
''}}
</td>
</tr>
</tbody>
</table>
...
...
@@ -99,28 +104,29 @@
</div>
<!--step 2-->
<div
class=
"row"
ng-show=
"syncItemStep == 2"
>
<h4
class=
"text-center"
>
环境:
fat 集群:default
</h4>
<div
class=
"row"
ng-show=
"syncItemStep == 2"
ng-repeat=
"diff in diffs"
>
<h4
class=
"text-center"
>
环境:
{{diff.namespace.env}} 集群:{{diff.namespace.clusterName}}
</h4>
<hr>
<div
class=
"row"
style=
"margin-top: 10px;"
>
<div
class=
"row text-center"
style=
"margin-top: 10px;"
ng-show=
"diff.diffs.createItems.length == 0 && diff.diffs.updateItems.length == 0"
>
<h5>
无更新的配置
</h5>
</div>
<div
class=
"row"
style=
"margin-top: 10px;"
ng-show=
"diff.diffs.createItems.length > 0"
>
<div
class=
"form-horizontal"
>
<label
class=
"col-sm-2 control-label"
>
新增的配置
</label>
<div
class=
"col-sm-9"
>
<table
class=
"table table-bordered table-hover"
>
<table
class=
"table table-bordered table-
striped table-
hover"
>
<thead>
<tr>
<td>
key
</td>
<td>
value
</td>
<td>
comment
</td>
</tr>
</thead>
<tbody>
<tr>
<td
width=
"30%"
>
k1
</td>
<td
width=
"60%"
>
v1
</td>
</tr>
<tr>
<td
width=
"30%"
>
k1
</td>
<td
width=
"60%"
>
v1
</td>
<tr
ng-repeat=
"createItem in diff.diffs.createItems"
>
<td
width=
"30%"
>
{{createItem.key}}
</td>
<td
width=
"40%"
>
{{createItem.value}}
</td>
<td
width=
"30%"
>
{{createItem.comment}}
</td>
</tr>
</tbody>
</table>
...
...
@@ -128,33 +134,28 @@
</div>
</div>
</div>
<div
class=
"row"
ng-show=
"syncItemStep == 2"
>
<div
class=
"row"
style=
"margin-top: 10px;"
>
<div
class=
"form-horizontal"
>
<label
class=
"col-sm-2 control-label"
>
更新的配置
</label>
<div
class=
"col-sm-9"
>
<table
class=
"table table-bordered table-striped table-hover"
>
<thead>
<tr>
<td>
key
</td>
<td>
value
</td>
</tr>
</thead>
<tbody>
<tr>
<td
width=
"30%"
>
k1
</td>
<td
width=
"60%"
>
v1
</td>
</tr>
<tr>
<td
width=
"30%"
>
k1
</td>
<td
width=
"60%"
>
v1
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div
class=
"row"
style=
"margin-top: 10px;"
ng-show=
"diff.diffs.updateItems.length > 0"
>
<div
class=
"form-horizontal"
>
<label
class=
"col-sm-2 control-label"
>
更新的配置
</label>
<div
class=
"col-sm-9"
>
<table
class=
"table table-bordered table-striped table-hover"
>
<thead>
<tr>
<td>
key
</td>
<td>
value
</td>
<td>
comment
</td>
</tr>
</thead>
<tbody>
<tr
ng-repeat=
"updateItem in diff.diffs.updateItems"
>
<td
width=
"30%"
>
{{updateItem.key}}
</td>
<td
width=
"40%"
>
{{updateItem.value}}
</td>
<td
width=
"30%"
>
{{updateItem.comment}}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
...
...
apollo-portal/src/test/java/com/ctrip/apollo/portal/ConfigServiceTest.java
View file @
7a27efe2
...
...
@@ -143,7 +143,7 @@ public class ConfigServiceTest {
when
(
namespaceAPI
.
loadNamespace
(
appId
,
Env
.
valueOf
(
env
),
clusterName
,
namespaceName
)).
thenReturn
(
namespaceDTO
);
when
(
itemAPI
.
findItems
(
appId
,
Env
.
valueOf
(
env
),
clusterName
,
namespaceName
)).
thenReturn
(
null
);
List
<
ItemDiffs
>
itemDiffses
=
configService
.
compare
(
sourceItems
,
namespaceIdentifer
s
);
List
<
ItemDiffs
>
itemDiffses
=
configService
.
compare
(
namespaceIdentifers
,
sourceItem
s
);
assertEquals
(
1
,
itemDiffses
.
size
());
ItemDiffs
itemDiffs
=
itemDiffses
.
get
(
0
);
...
...
@@ -180,7 +180,7 @@ public class ConfigServiceTest {
when
(
namespaceAPI
.
loadNamespace
(
appId
,
Env
.
valueOf
(
env
),
clusterName
,
namespaceName
)).
thenReturn
(
namespaceDTO
);
when
(
itemAPI
.
findItems
(
appId
,
Env
.
valueOf
(
env
),
clusterName
,
namespaceName
)).
thenReturn
(
targetItems
);
List
<
ItemDiffs
>
itemDiffses
=
configService
.
compare
(
sourceItems
,
namespaceIdentifer
s
);
List
<
ItemDiffs
>
itemDiffses
=
configService
.
compare
(
namespaceIdentifers
,
sourceItem
s
);
assertEquals
(
1
,
itemDiffses
.
size
());
ItemDiffs
itemDiffs
=
itemDiffses
.
get
(
0
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment