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
9a621234
Commit
9a621234
authored
Aug 22, 2016
by
Jason Song
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add runtime config info audit
parent
75d2be0b
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
831 additions
and
20 deletions
+831
-20
Instance.java
.../java/com/ctrip/framework/apollo/biz/entity/Instance.java
+122
-0
InstanceConfig.java
...com/ctrip/framework/apollo/biz/entity/InstanceConfig.java
+127
-0
InstanceConfigRepository.java
...ework/apollo/biz/repository/InstanceConfigRepository.java
+9
-0
InstanceRepository.java
...p/framework/apollo/biz/repository/InstanceRepository.java
+9
-0
InstanceService.java
...m/ctrip/framework/apollo/biz/service/InstanceService.java
+62
-0
AllTests.java
...rc/test/java/com/ctrip/framework/apollo/biz/AllTests.java
+5
-1
InstanceServiceTest.java
...rip/framework/apollo/biz/service/InstanceServiceTest.java
+96
-0
ConfigController.java
...ork/apollo/configservice/controller/ConfigController.java
+46
-9
ConfigFileController.java
...apollo/configservice/controller/ConfigFileController.java
+7
-3
InstanceConfigAuditUtil.java
...rk/apollo/configservice/util/InstanceConfigAuditUtil.java
+235
-0
AllTests.java
...va/com/ctrip/framework/apollo/configservice/AllTests.java
+3
-1
ConfigControllerTest.java
...apollo/configservice/controller/ConfigControllerTest.java
+0
-0
ConfigFileControllerTest.java
...lo/configservice/controller/ConfigFileControllerTest.java
+9
-6
InstanceConfigAuditUtilTest.java
...pollo/configservice/util/InstanceConfigAuditUtilTest.java
+101
-0
No files found.
apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/Instance.java
0 → 100644
View file @
9a621234
package
com
.
ctrip
.
framework
.
apollo
.
biz
.
entity
;
import
com.google.common.base.MoreObjects
;
import
java.util.Date
;
import
javax.persistence.Column
;
import
javax.persistence.Entity
;
import
javax.persistence.GeneratedValue
;
import
javax.persistence.Id
;
import
javax.persistence.PrePersist
;
import
javax.persistence.Table
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Entity
@Table
(
name
=
"Instance"
)
public
class
Instance
{
@Id
@GeneratedValue
@Column
(
name
=
"Id"
)
private
long
id
;
@Column
(
name
=
"AppId"
,
nullable
=
false
)
private
String
appId
;
@Column
(
name
=
"ClusterName"
,
nullable
=
false
)
private
String
clusterName
;
@Column
(
name
=
"DataCenter"
,
nullable
=
false
)
private
String
dataCenter
;
@Column
(
name
=
"Ip"
,
nullable
=
false
)
private
String
ip
;
@Column
(
name
=
"DataChange_CreatedTime"
,
nullable
=
false
)
private
Date
dataChangeCreatedTime
;
@Column
(
name
=
"DataChange_LastTime"
)
private
Date
dataChangeLastModifiedTime
;
@PrePersist
protected
void
prePersist
()
{
if
(
this
.
dataChangeCreatedTime
==
null
)
{
dataChangeCreatedTime
=
new
Date
();
}
if
(
this
.
dataChangeLastModifiedTime
==
null
)
{
dataChangeLastModifiedTime
=
dataChangeCreatedTime
;
}
}
public
long
getId
()
{
return
id
;
}
public
void
setId
(
long
id
)
{
this
.
id
=
id
;
}
public
String
getAppId
()
{
return
appId
;
}
public
void
setAppId
(
String
appId
)
{
this
.
appId
=
appId
;
}
public
String
getClusterName
()
{
return
clusterName
;
}
public
void
setClusterName
(
String
clusterName
)
{
this
.
clusterName
=
clusterName
;
}
public
String
getDataCenter
()
{
return
dataCenter
;
}
public
void
setDataCenter
(
String
dataCenter
)
{
this
.
dataCenter
=
dataCenter
;
}
public
String
getIp
()
{
return
ip
;
}
public
void
setIp
(
String
ip
)
{
this
.
ip
=
ip
;
}
public
Date
getDataChangeCreatedTime
()
{
return
dataChangeCreatedTime
;
}
public
void
setDataChangeCreatedTime
(
Date
dataChangeCreatedTime
)
{
this
.
dataChangeCreatedTime
=
dataChangeCreatedTime
;
}
public
Date
getDataChangeLastModifiedTime
()
{
return
dataChangeLastModifiedTime
;
}
public
void
setDataChangeLastModifiedTime
(
Date
dataChangeLastModifiedTime
)
{
this
.
dataChangeLastModifiedTime
=
dataChangeLastModifiedTime
;
}
@Override
public
String
toString
()
{
return
MoreObjects
.
toStringHelper
(
this
)
.
omitNullValues
()
.
add
(
"id"
,
id
)
.
add
(
"appId"
,
appId
)
.
add
(
"clusterName"
,
clusterName
)
.
add
(
"dataCenter"
,
dataCenter
)
.
add
(
"ip"
,
ip
)
.
add
(
"dataChangeCreatedTime"
,
dataChangeCreatedTime
)
.
add
(
"dataChangeLastModifiedTime"
,
dataChangeLastModifiedTime
)
.
toString
();
}
}
apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/InstanceConfig.java
0 → 100644
View file @
9a621234
package
com
.
ctrip
.
framework
.
apollo
.
biz
.
entity
;
import
com.google.common.base.MoreObjects
;
import
java.util.Date
;
import
javax.persistence.Column
;
import
javax.persistence.Entity
;
import
javax.persistence.GeneratedValue
;
import
javax.persistence.Id
;
import
javax.persistence.PrePersist
;
import
javax.persistence.PreUpdate
;
import
javax.persistence.Table
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Entity
@Table
(
name
=
"InstanceConfig"
)
public
class
InstanceConfig
{
@Id
@GeneratedValue
@Column
(
name
=
"Id"
)
private
long
id
;
@Column
(
name
=
"InstanceId"
)
private
long
instanceId
;
@Column
(
name
=
"ConfigAppId"
,
nullable
=
false
)
private
String
configAppId
;
@Column
(
name
=
"ConfigNamespaceName"
,
nullable
=
false
)
private
String
configNamespaceName
;
@Column
(
name
=
"ReleaseKey"
,
nullable
=
false
)
private
String
releaseKey
;
@Column
(
name
=
"DataChange_CreatedTime"
,
nullable
=
false
)
private
Date
dataChangeCreatedTime
;
@Column
(
name
=
"DataChange_LastTime"
)
private
Date
dataChangeLastModifiedTime
;
@PrePersist
protected
void
prePersist
()
{
if
(
this
.
dataChangeCreatedTime
==
null
)
{
dataChangeCreatedTime
=
new
Date
();
}
if
(
this
.
dataChangeLastModifiedTime
==
null
)
{
dataChangeLastModifiedTime
=
dataChangeCreatedTime
;
}
}
@PreUpdate
protected
void
preUpdate
()
{
this
.
dataChangeLastModifiedTime
=
new
Date
();
}
public
long
getId
()
{
return
id
;
}
public
void
setId
(
long
id
)
{
this
.
id
=
id
;
}
public
long
getInstanceId
()
{
return
instanceId
;
}
public
void
setInstanceId
(
long
instanceId
)
{
this
.
instanceId
=
instanceId
;
}
public
String
getConfigAppId
()
{
return
configAppId
;
}
public
void
setConfigAppId
(
String
configAppId
)
{
this
.
configAppId
=
configAppId
;
}
public
String
getConfigNamespaceName
()
{
return
configNamespaceName
;
}
public
void
setConfigNamespaceName
(
String
configNamespaceName
)
{
this
.
configNamespaceName
=
configNamespaceName
;
}
public
String
getReleaseKey
()
{
return
releaseKey
;
}
public
void
setReleaseKey
(
String
releaseKey
)
{
this
.
releaseKey
=
releaseKey
;
}
public
Date
getDataChangeCreatedTime
()
{
return
dataChangeCreatedTime
;
}
public
void
setDataChangeCreatedTime
(
Date
dataChangeCreatedTime
)
{
this
.
dataChangeCreatedTime
=
dataChangeCreatedTime
;
}
public
Date
getDataChangeLastModifiedTime
()
{
return
dataChangeLastModifiedTime
;
}
public
void
setDataChangeLastModifiedTime
(
Date
dataChangeLastModifiedTime
)
{
this
.
dataChangeLastModifiedTime
=
dataChangeLastModifiedTime
;
}
@Override
public
String
toString
()
{
return
MoreObjects
.
toStringHelper
(
this
)
.
omitNullValues
()
.
add
(
"id"
,
id
)
.
add
(
"configAppId"
,
configAppId
)
.
add
(
"configNamespaceName"
,
configNamespaceName
)
.
add
(
"releaseKey"
,
releaseKey
)
.
add
(
"dataChangeCreatedTime"
,
dataChangeCreatedTime
)
.
add
(
"dataChangeLastModifiedTime"
,
dataChangeLastModifiedTime
)
.
toString
();
}
}
apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/InstanceConfigRepository.java
0 → 100644
View file @
9a621234
package
com
.
ctrip
.
framework
.
apollo
.
biz
.
repository
;
import
com.ctrip.framework.apollo.biz.entity.InstanceConfig
;
import
org.springframework.data.repository.PagingAndSortingRepository
;
public
interface
InstanceConfigRepository
extends
PagingAndSortingRepository
<
InstanceConfig
,
Long
>
{
InstanceConfig
findByInstanceIdAndConfigAppIdAndConfigNamespaceName
(
long
instanceId
,
String
configAppId
,
String
configNamespaceName
);
}
apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/InstanceRepository.java
0 → 100644
View file @
9a621234
package
com
.
ctrip
.
framework
.
apollo
.
biz
.
repository
;
import
com.ctrip.framework.apollo.biz.entity.Instance
;
import
org.springframework.data.repository.PagingAndSortingRepository
;
public
interface
InstanceRepository
extends
PagingAndSortingRepository
<
Instance
,
Long
>
{
Instance
findByAppIdAndClusterNameAndDataCenterAndIp
(
String
appId
,
String
clusterName
,
String
dataCenter
,
String
ip
);
}
apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/InstanceService.java
0 → 100644
View file @
9a621234
package
com
.
ctrip
.
framework
.
apollo
.
biz
.
service
;
import
com.google.common.base.Preconditions
;
import
com.ctrip.framework.apollo.biz.entity.Instance
;
import
com.ctrip.framework.apollo.biz.entity.InstanceConfig
;
import
com.ctrip.framework.apollo.biz.repository.InstanceConfigRepository
;
import
com.ctrip.framework.apollo.biz.repository.InstanceRepository
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Service
public
class
InstanceService
{
@Autowired
private
InstanceRepository
instanceRepository
;
@Autowired
private
InstanceConfigRepository
instanceConfigRepository
;
public
Instance
findInstance
(
String
appId
,
String
clusterName
,
String
dataCenter
,
String
ip
)
{
return
instanceRepository
.
findByAppIdAndClusterNameAndDataCenterAndIp
(
appId
,
clusterName
,
dataCenter
,
ip
);
}
@Transactional
public
Instance
createInstance
(
Instance
instance
)
{
instance
.
setId
(
0
);
//protection
return
instanceRepository
.
save
(
instance
);
}
public
InstanceConfig
findInstanceConfig
(
long
instanceId
,
String
configAppId
,
String
configNamespaceName
)
{
return
instanceConfigRepository
.
findByInstanceIdAndConfigAppIdAndConfigNamespaceName
(
instanceId
,
configAppId
,
configNamespaceName
);
}
@Transactional
public
InstanceConfig
createInstanceConfig
(
InstanceConfig
instanceConfig
)
{
instanceConfig
.
setId
(
0
);
//protection
return
instanceConfigRepository
.
save
(
instanceConfig
);
}
@Transactional
public
InstanceConfig
updateInstanceConfig
(
InstanceConfig
instanceConfig
)
{
InstanceConfig
existedInstanceConfig
=
instanceConfigRepository
.
findOne
(
instanceConfig
.
getId
());
Preconditions
.
checkArgument
(
existedInstanceConfig
!=
null
,
String
.
format
(
"Instance config %d doesn't exist"
,
instanceConfig
.
getId
()));
existedInstanceConfig
.
setReleaseKey
(
instanceConfig
.
getReleaseKey
());
existedInstanceConfig
.
setDataChangeLastModifiedTime
(
instanceConfig
.
getDataChangeLastModifiedTime
());
return
instanceConfigRepository
.
save
(
existedInstanceConfig
);
}
}
apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/AllTests.java
View file @
9a621234
...
...
@@ -8,7 +8,9 @@ import com.ctrip.framework.apollo.biz.repository.AppRepositoryTest;
import
com.ctrip.framework.apollo.biz.service.AdminServiceTest
;
import
com.ctrip.framework.apollo.biz.service.AdminServiceTransactionTest
;
import
com.ctrip.framework.apollo.biz.service.ClusterServiceTest
;
import
com.ctrip.framework.apollo.biz.service.InstanceServiceTest
;
import
com.ctrip.framework.apollo.biz.service.PrivilegeServiceTest
;
import
com.ctrip.framework.apollo.biz.service.ReleaseServiceTest
;
import
com.ctrip.framework.apollo.biz.service.ServerConfigServiceTest
;
import
com.ctrip.framework.apollo.biz.utils.ReleaseKeyGeneratorTest
;
...
...
@@ -26,9 +28,11 @@ import org.junit.runners.Suite.SuiteClasses;
DatabaseMessageSenderTest
.
class
,
ServerConfigServiceTest
.
class
,
ApolloEurekaClientConfigTest
.
class
,
ReleaseServiceTest
.
class
,
ReleaseMessageScannerTest
.
class
,
ClusterServiceTest
.
class
,
ReleaseKeyGeneratorTest
.
class
ReleaseKeyGeneratorTest
.
class
,
InstanceServiceTest
.
class
})
public
class
AllTests
{
...
...
apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/service/InstanceServiceTest.java
0 → 100644
View file @
9a621234
package
com
.
ctrip
.
framework
.
apollo
.
biz
.
service
;
import
com.ctrip.framework.apollo.biz.AbstractIntegrationTest
;
import
com.ctrip.framework.apollo.biz.entity.Instance
;
import
com.ctrip.framework.apollo.biz.entity.InstanceConfig
;
import
org.junit.Test
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.test.annotation.Rollback
;
import
static
org
.
junit
.
Assert
.*;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public
class
InstanceServiceTest
extends
AbstractIntegrationTest
{
@Autowired
private
InstanceService
instanceService
;
@Test
@Rollback
public
void
testInstance
()
throws
Exception
{
String
someAppId
=
"someAppId"
;
String
someClusterName
=
"someClusterName"
;
String
someDataCenter
=
"someDataCenter"
;
String
someIp
=
"someIp"
;
Instance
instance
=
instanceService
.
findInstance
(
someAppId
,
someClusterName
,
someDataCenter
,
someIp
);
assertNull
(
instance
);
instanceService
.
createInstance
(
assembleInstance
(
someAppId
,
someClusterName
,
someDataCenter
,
someIp
));
instance
=
instanceService
.
findInstance
(
someAppId
,
someClusterName
,
someDataCenter
,
someIp
);
assertNotEquals
(
0
,
instance
.
getId
());
}
@Test
@Rollback
public
void
testInstanceConfig
()
throws
Exception
{
long
someInstanceId
=
1
;
String
someConfigAppId
=
"someConfigAppId"
;
String
someConfigNamespaceName
=
"someConfigNamespaceName"
;
String
someReleaseKey
=
"someReleaseKey"
;
String
anotherReleaseKey
=
"anotherReleaseKey"
;
InstanceConfig
instanceConfig
=
instanceService
.
findInstanceConfig
(
someInstanceId
,
someConfigAppId
,
someConfigNamespaceName
);
assertNull
(
instanceConfig
);
instanceService
.
createInstanceConfig
(
assembleInstanceConfig
(
someInstanceId
,
someConfigAppId
,
someConfigNamespaceName
,
someReleaseKey
));
instanceConfig
=
instanceService
.
findInstanceConfig
(
someInstanceId
,
someConfigAppId
,
someConfigNamespaceName
);
assertNotEquals
(
0
,
instanceConfig
.
getId
());
assertEquals
(
someReleaseKey
,
instanceConfig
.
getReleaseKey
());
instanceConfig
.
setReleaseKey
(
anotherReleaseKey
);
instanceService
.
updateInstanceConfig
(
instanceConfig
);
InstanceConfig
updated
=
instanceService
.
findInstanceConfig
(
someInstanceId
,
someConfigAppId
,
someConfigNamespaceName
);
assertEquals
(
instanceConfig
.
getId
(),
updated
.
getId
());
assertEquals
(
anotherReleaseKey
,
updated
.
getReleaseKey
());
}
private
Instance
assembleInstance
(
String
appId
,
String
clusterName
,
String
dataCenter
,
String
ip
)
{
Instance
instance
=
new
Instance
();
instance
.
setAppId
(
appId
);
instance
.
setIp
(
ip
);
instance
.
setClusterName
(
clusterName
);
instance
.
setDataCenter
(
dataCenter
);
return
instance
;
}
private
InstanceConfig
assembleInstanceConfig
(
long
instanceId
,
String
configAppId
,
String
configNamespaceName
,
String
releaseKey
)
{
InstanceConfig
instanceConfig
=
new
InstanceConfig
();
instanceConfig
.
setInstanceId
(
instanceId
);
instanceConfig
.
setConfigAppId
(
configAppId
);
instanceConfig
.
setConfigNamespaceName
(
configNamespaceName
);
instanceConfig
.
setReleaseKey
(
releaseKey
);
return
instanceConfig
;
}
}
\ No newline at end of file
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/ConfigController.java
View file @
9a621234
...
...
@@ -8,10 +8,11 @@ import com.google.common.collect.Maps;
import
com.google.gson.Gson
;
import
com.google.gson.reflect.TypeToken
;
import
com.ctrip.framework.apollo.biz.service.ReleaseService
;
import
com.ctrip.framework.apollo.common.entity.AppNamespace
;
import
com.ctrip.framework.apollo.biz.entity.Release
;
import
com.ctrip.framework.apollo.biz.service.AppNamespaceService
;
import
com.ctrip.framework.apollo.biz.service.ReleaseService
;
import
com.ctrip.framework.apollo.common.entity.AppNamespace
;
import
com.ctrip.framework.apollo.configservice.util.InstanceConfigAuditUtil
;
import
com.ctrip.framework.apollo.configservice.util.NamespaceUtil
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
com.ctrip.framework.apollo.core.dto.ApolloConfig
;
...
...
@@ -30,6 +31,7 @@ import java.util.List;
import
java.util.Map
;
import
java.util.Objects
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
/**
...
...
@@ -44,6 +46,8 @@ public class ConfigController {
private
AppNamespaceService
appNamespaceService
;
@Autowired
private
NamespaceUtil
namespaceUtil
;
@Autowired
private
InstanceConfigAuditUtil
instanceConfigAuditUtil
;
private
static
final
Gson
gson
=
new
Gson
();
private
static
final
Type
configurationTypeReference
=
...
...
@@ -54,14 +58,21 @@ public class ConfigController {
@RequestMapping
(
value
=
"/{appId}/{clusterName}/{namespace:.+}"
,
method
=
RequestMethod
.
GET
)
public
ApolloConfig
queryConfig
(
@PathVariable
String
appId
,
@PathVariable
String
clusterName
,
@PathVariable
String
namespace
,
@RequestParam
(
value
=
"dataCenter"
,
required
=
false
)
String
dataCenter
,
@RequestParam
(
value
=
"releaseKey"
,
defaultValue
=
"-1"
)
String
clientSideReleaseKey
,
@RequestParam
(
value
=
"dataCenter"
,
required
=
false
)
String
dataCenter
,
@RequestParam
(
value
=
"releaseKey"
,
defaultValue
=
"-1"
)
String
clientSideReleaseKey
,
@RequestParam
(
value
=
"ip"
,
required
=
false
)
String
clientIp
,
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
IOException
{
String
originalNamespace
=
namespace
;
//strip out .properties suffix
namespace
=
namespaceUtil
.
filterNamespaceName
(
namespace
);
if
(
Strings
.
isNullOrEmpty
(
clientIp
))
{
clientIp
=
tryToGetClientIp
(
request
);
}
List
<
Release
>
releases
=
Lists
.
newLinkedList
();
String
appClusterNameLoaded
=
clusterName
;
...
...
@@ -93,8 +104,10 @@ public class ConfigController {
return
null
;
}
auditReleases
(
appId
,
clusterName
,
dataCenter
,
clientIp
,
releases
);
String
mergedReleaseKey
=
FluentIterable
.
from
(
releases
).
transform
(
input
->
String
.
valueOf
(
input
.
getReleaseKey
()
)).
join
(
STRING_JOINER
);
input
->
input
.
getReleaseKey
(
)).
join
(
STRING_JOINER
);
if
(
mergedReleaseKey
.
equals
(
clientSideReleaseKey
))
{
// Client side configuration is the same with server side, return 304
...
...
@@ -104,10 +117,12 @@ public class ConfigController {
return
null
;
}
ApolloConfig
apolloConfig
=
new
ApolloConfig
(
appId
,
appClusterNameLoaded
,
originalNamespace
,
mergedReleaseKey
);
ApolloConfig
apolloConfig
=
new
ApolloConfig
(
appId
,
appClusterNameLoaded
,
originalNamespace
,
mergedReleaseKey
);
apolloConfig
.
setConfigurations
(
mergeReleaseConfigurations
(
releases
));
Cat
.
logEvent
(
"Apollo.Config.Found"
,
assembleKey
(
appId
,
appClusterNameLoaded
,
originalNamespace
,
dataCenter
));
Cat
.
logEvent
(
"Apollo.Config.Found"
,
assembleKey
(
appId
,
appClusterNameLoaded
,
originalNamespace
,
dataCenter
));
return
apolloConfig
;
}
...
...
@@ -132,7 +147,8 @@ public class ConfigController {
* @param namespace the namespace
* @param dataCenter the datacenter
*/
private
Release
findPublicConfig
(
String
applicationId
,
String
clusterName
,
String
namespace
,
String
dataCenter
)
{
private
Release
findPublicConfig
(
String
applicationId
,
String
clusterName
,
String
namespace
,
String
dataCenter
)
{
AppNamespace
appNamespace
=
appNamespaceService
.
findPublicNamespaceByName
(
namespace
);
//check whether the namespace's appId equals to current one
...
...
@@ -145,7 +161,8 @@ public class ConfigController {
return
loadConfig
(
publicConfigAppId
,
clusterName
,
namespace
,
dataCenter
);
}
private
Release
loadConfig
(
String
appId
,
String
clusterName
,
String
namespace
,
String
dataCenter
)
{
private
Release
loadConfig
(
String
appId
,
String
clusterName
,
String
namespace
,
String
dataCenter
)
{
//load from specified cluster fist
if
(!
Objects
.
equals
(
ConfigConsts
.
CLUSTER_NAME_DEFAULT
,
clusterName
))
{
Release
clusterRelease
=
...
...
@@ -190,4 +207,24 @@ public class ConfigController {
return
STRING_JOINER
.
join
(
keyParts
);
}
private
void
auditReleases
(
String
appId
,
String
cluster
,
String
datacenter
,
String
clientIp
,
List
<
Release
>
releases
)
{
if
(
Strings
.
isNullOrEmpty
(
clientIp
))
{
//no need to audit instance config when there is no ip
return
;
}
for
(
Release
release
:
releases
)
{
instanceConfigAuditUtil
.
audit
(
appId
,
cluster
,
datacenter
,
clientIp
,
release
.
getAppId
(),
release
.
getNamespaceName
(),
release
.
getReleaseKey
());
}
}
private
String
tryToGetClientIp
(
HttpServletRequest
request
)
{
String
ipAddress
=
request
.
getHeader
(
"X-FORWARDED-FOR"
);
if
(
ipAddress
==
null
)
{
ipAddress
=
request
.
getRemoteAddr
();
}
return
ipAddress
;
}
}
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileController.java
View file @
9a621234
...
...
@@ -42,6 +42,7 @@ import java.util.Properties;
import
java.util.Set
;
import
java.util.concurrent.TimeUnit
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
/**
...
...
@@ -114,12 +115,13 @@ public class ConfigFileController implements ReleaseMessageListener {
@PathVariable
String
namespace
,
@RequestParam
(
value
=
"dataCenter"
,
required
=
false
)
String
dataCenter
,
@RequestParam
(
value
=
"ip"
,
required
=
false
)
String
clientIp
,
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
IOException
{
String
result
=
queryConfig
(
ConfigFileOutputFormat
.
PROPERTIES
,
appId
,
clusterName
,
namespace
,
dataCenter
,
clientIp
,
response
);
clientIp
,
re
quest
,
re
sponse
);
if
(
result
==
null
)
{
return
NOT_FOUND_RESPONSE
;
...
...
@@ -134,11 +136,12 @@ public class ConfigFileController implements ReleaseMessageListener {
@PathVariable
String
namespace
,
@RequestParam
(
value
=
"dataCenter"
,
required
=
false
)
String
dataCenter
,
@RequestParam
(
value
=
"ip"
,
required
=
false
)
String
clientIp
,
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
IOException
{
String
result
=
queryConfig
(
ConfigFileOutputFormat
.
JSON
,
appId
,
clusterName
,
namespace
,
dataCenter
,
clientIp
,
response
);
clientIp
,
re
quest
,
re
sponse
);
if
(
result
==
null
)
{
return
NOT_FOUND_RESPONSE
;
...
...
@@ -149,6 +152,7 @@ public class ConfigFileController implements ReleaseMessageListener {
String
queryConfig
(
ConfigFileOutputFormat
outputFormat
,
String
appId
,
String
clusterName
,
String
namespace
,
String
dataCenter
,
String
clientIp
,
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
IOException
{
//strip out .properties suffix
namespace
=
namespaceUtil
.
filterNamespaceName
(
namespace
);
...
...
@@ -162,7 +166,7 @@ public class ConfigFileController implements ReleaseMessageListener {
Cat
.
logEvent
(
"ConfigFile.Cache.Miss"
,
cacheKey
);
ApolloConfig
apolloConfig
=
configController
.
queryConfig
(
appId
,
clusterName
,
namespace
,
dataCenter
,
"-1"
,
clientIp
,
.
queryConfig
(
appId
,
clusterName
,
namespace
,
dataCenter
,
"-1"
,
clientIp
,
request
,
response
);
if
(
apolloConfig
==
null
||
apolloConfig
.
getConfigurations
()
==
null
)
{
...
...
apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/util/InstanceConfigAuditUtil.java
0 → 100644
View file @
9a621234
package
com
.
ctrip
.
framework
.
apollo
.
configservice
.
util
;
import
com.google.common.base.Joiner
;
import
com.google.common.base.Strings
;
import
com.google.common.cache.Cache
;
import
com.google.common.cache.CacheBuilder
;
import
com.google.common.collect.Lists
;
import
com.google.common.collect.Queues
;
import
com.ctrip.framework.apollo.biz.entity.Instance
;
import
com.ctrip.framework.apollo.biz.entity.InstanceConfig
;
import
com.ctrip.framework.apollo.biz.service.InstanceService
;
import
com.ctrip.framework.apollo.core.ConfigConsts
;
import
com.ctrip.framework.apollo.core.utils.ApolloThreadFactory
;
import
com.dianping.cat.Cat
;
import
org.springframework.beans.factory.InitializingBean
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.dao.DataIntegrityViolationException
;
import
org.springframework.stereotype.Service
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.concurrent.BlockingQueue
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicBoolean
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@Service
public
class
InstanceConfigAuditUtil
implements
InitializingBean
{
private
static
final
int
INSTANCE_CONFIG_AUDIT_MAX_SIZE
=
2000
;
private
static
final
int
INSTANCE_CACHE_MAX_SIZE
=
10000
;
private
static
final
int
INSTANCE_CONFIG_CACHE_MAX_SIZE
=
10000
;
private
static
final
Joiner
STRING_JOINER
=
Joiner
.
on
(
ConfigConsts
.
CLUSTER_NAMESPACE_SEPARATOR
);
private
final
ExecutorService
auditExecutorService
;
private
final
AtomicBoolean
auditStopped
;
private
BlockingQueue
<
InstanceConfigAuditModel
>
audits
=
Queues
.
newLinkedBlockingQueue
(
INSTANCE_CONFIG_AUDIT_MAX_SIZE
);
private
Cache
<
String
,
Long
>
instanceCache
;
private
Cache
<
String
,
String
>
instanceConfigReleaseKeyCache
;
@Autowired
private
InstanceService
instanceService
;
public
InstanceConfigAuditUtil
()
{
auditExecutorService
=
Executors
.
newSingleThreadExecutor
(
ApolloThreadFactory
.
create
(
"InstanceConfigAuditUtil"
,
true
));
auditStopped
=
new
AtomicBoolean
(
false
);
instanceCache
=
CacheBuilder
.
newBuilder
().
expireAfterAccess
(
1
,
TimeUnit
.
HOURS
)
.
maximumSize
(
INSTANCE_CACHE_MAX_SIZE
).
build
();
instanceConfigReleaseKeyCache
=
CacheBuilder
.
newBuilder
().
expireAfterWrite
(
1
,
TimeUnit
.
DAYS
)
.
maximumSize
(
INSTANCE_CONFIG_CACHE_MAX_SIZE
).
build
();
}
public
boolean
audit
(
String
appId
,
String
clusterName
,
String
dataCenter
,
String
ip
,
String
configAppId
,
String
configNamespace
,
String
releaseKey
)
{
return
this
.
audits
.
offer
(
new
InstanceConfigAuditModel
(
appId
,
clusterName
,
dataCenter
,
ip
,
configAppId
,
configNamespace
,
releaseKey
));
}
void
doAudit
(
InstanceConfigAuditModel
auditModel
)
{
String
instanceCacheKey
=
assembleInstanceKey
(
auditModel
.
getAppId
(),
auditModel
.
getClusterName
(),
auditModel
.
getIp
(),
auditModel
.
getDataCenter
());
Long
instanceId
=
instanceCache
.
getIfPresent
(
instanceCacheKey
);
if
(
instanceId
==
null
)
{
instanceId
=
prepareInstanceId
(
auditModel
);
instanceCache
.
put
(
instanceCacheKey
,
instanceId
);
}
//load instance config release key from cache, and check if release key is the same
String
instanceConfigCacheKey
=
assembleInstanceConfigKey
(
instanceId
,
auditModel
.
getConfigAppId
(),
auditModel
.
getConfigNamespace
());
String
cacheReleaseKey
=
instanceConfigReleaseKeyCache
.
getIfPresent
(
instanceConfigCacheKey
);
//if release key is the same, then skip audit
if
(
cacheReleaseKey
!=
null
&&
Objects
.
equals
(
cacheReleaseKey
,
auditModel
.
getReleaseKey
()))
{
return
;
}
instanceConfigReleaseKeyCache
.
put
(
instanceConfigCacheKey
,
auditModel
.
getReleaseKey
());
//if release key is not the same or cannot find in cache, then do audit
InstanceConfig
instanceConfig
=
instanceService
.
findInstanceConfig
(
instanceId
,
auditModel
.
getConfigAppId
(),
auditModel
.
getConfigNamespace
());
//we need to update no matter the release key is the same or not, to ensure the
//last modified time is updated each day
if
(
instanceConfig
!=
null
)
{
instanceConfig
.
setReleaseKey
(
auditModel
.
getReleaseKey
());
instanceConfig
.
setDataChangeLastModifiedTime
(
new
Date
());
instanceService
.
updateInstanceConfig
(
instanceConfig
);
return
;
}
instanceConfig
=
new
InstanceConfig
();
instanceConfig
.
setInstanceId
(
instanceId
);
instanceConfig
.
setConfigAppId
(
auditModel
.
getConfigAppId
());
instanceConfig
.
setConfigNamespaceName
(
auditModel
.
getConfigNamespace
());
instanceConfig
.
setReleaseKey
(
auditModel
.
getReleaseKey
());
try
{
instanceService
.
createInstanceConfig
(
instanceConfig
);
}
catch
(
DataIntegrityViolationException
ex
)
{
//concurrent insertion, safe to ignore
}
}
private
long
prepareInstanceId
(
InstanceConfigAuditModel
auditModel
)
{
Instance
instance
=
instanceService
.
findInstance
(
auditModel
.
getAppId
(),
auditModel
.
getClusterName
(),
auditModel
.
getDataCenter
(),
auditModel
.
getIp
());
if
(
instance
!=
null
)
{
return
instance
.
getId
();
}
instance
=
new
Instance
();
instance
.
setAppId
(
auditModel
.
getAppId
());
instance
.
setClusterName
(
auditModel
.
getClusterName
());
instance
.
setDataCenter
(
auditModel
.
getDataCenter
());
instance
.
setIp
(
auditModel
.
getIp
());
try
{
return
instanceService
.
createInstance
(
instance
).
getId
();
}
catch
(
DataIntegrityViolationException
ex
)
{
//return the one exists
return
instanceService
.
findInstance
(
instance
.
getAppId
(),
instance
.
getClusterName
(),
instance
.
getDataCenter
(),
instance
.
getIp
()).
getId
();
}
}
@Override
public
void
afterPropertiesSet
()
throws
Exception
{
auditExecutorService
.
submit
(()
->
{
while
(!
auditStopped
.
get
()
&&
!
Thread
.
currentThread
().
isInterrupted
())
{
try
{
InstanceConfigAuditModel
model
=
audits
.
poll
();
if
(
model
==
null
)
{
TimeUnit
.
SECONDS
.
sleep
(
1
);
continue
;
}
doAudit
(
model
);
}
catch
(
Throwable
ex
)
{
Cat
.
logError
(
ex
);
}
}
});
}
private
String
assembleInstanceKey
(
String
appId
,
String
cluster
,
String
ip
,
String
datacenter
)
{
List
<
String
>
keyParts
=
Lists
.
newArrayList
(
appId
,
cluster
,
ip
);
if
(!
Strings
.
isNullOrEmpty
(
datacenter
))
{
keyParts
.
add
(
datacenter
);
}
return
STRING_JOINER
.
join
(
keyParts
);
}
private
String
assembleInstanceConfigKey
(
long
instanceId
,
String
configAppId
,
String
configNamespace
)
{
return
STRING_JOINER
.
join
(
instanceId
,
configAppId
,
configNamespace
);
}
public
static
class
InstanceConfigAuditModel
{
private
String
appId
;
private
String
clusterName
;
private
String
dataCenter
;
private
String
ip
;
private
String
configAppId
;
private
String
configNamespace
;
private
String
releaseKey
;
public
InstanceConfigAuditModel
(
String
appId
,
String
clusterName
,
String
dataCenter
,
String
clientIp
,
String
configAppId
,
String
configNamespace
,
String
releaseKey
)
{
this
.
appId
=
appId
;
this
.
clusterName
=
clusterName
;
this
.
dataCenter
=
Strings
.
isNullOrEmpty
(
dataCenter
)
?
""
:
dataCenter
;
this
.
ip
=
clientIp
;
this
.
configAppId
=
configAppId
;
this
.
configNamespace
=
configNamespace
;
this
.
releaseKey
=
releaseKey
;
}
public
String
getAppId
()
{
return
appId
;
}
public
String
getClusterName
()
{
return
clusterName
;
}
public
String
getDataCenter
()
{
return
dataCenter
;
}
public
String
getIp
()
{
return
ip
;
}
public
String
getConfigAppId
()
{
return
configAppId
;
}
public
String
getConfigNamespace
()
{
return
configNamespace
;
}
public
String
getReleaseKey
()
{
return
releaseKey
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
InstanceConfigAuditModel
model
=
(
InstanceConfigAuditModel
)
o
;
return
Objects
.
equals
(
appId
,
model
.
appId
)
&&
Objects
.
equals
(
clusterName
,
model
.
clusterName
)
&&
Objects
.
equals
(
dataCenter
,
model
.
dataCenter
)
&&
Objects
.
equals
(
ip
,
model
.
ip
)
&&
Objects
.
equals
(
configAppId
,
model
.
configAppId
)
&&
Objects
.
equals
(
configNamespace
,
model
.
configNamespace
)
&&
Objects
.
equals
(
releaseKey
,
model
.
releaseKey
);
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
appId
,
clusterName
,
dataCenter
,
ip
,
configAppId
,
configNamespace
,
releaseKey
);
}
}
}
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/AllTests.java
View file @
9a621234
...
...
@@ -8,6 +8,7 @@ import com.ctrip.framework.apollo.configservice.integration.ConfigControllerInte
import
com.ctrip.framework.apollo.configservice.integration.ConfigFileControllerIntegrationTest
;
import
com.ctrip.framework.apollo.configservice.integration.NotificationControllerIntegrationTest
;
import
com.ctrip.framework.apollo.configservice.integration.NotificationControllerV2IntegrationTest
;
import
com.ctrip.framework.apollo.configservice.util.InstanceConfigAuditUtilTest
;
import
com.ctrip.framework.apollo.configservice.util.NamespaceUtilTest
;
import
com.ctrip.framework.apollo.configservice.util.WatchKeysUtilTest
;
...
...
@@ -20,7 +21,8 @@ import org.junit.runners.Suite.SuiteClasses;
ConfigControllerIntegrationTest
.
class
,
NotificationControllerIntegrationTest
.
class
,
NamespaceUtilTest
.
class
,
ConfigFileControllerTest
.
class
,
ConfigFileControllerIntegrationTest
.
class
,
WatchKeysUtilTest
.
class
,
NotificationControllerV2Test
.
class
,
NotificationControllerV2IntegrationTest
.
class
NotificationControllerV2Test
.
class
,
NotificationControllerV2IntegrationTest
.
class
,
InstanceConfigAuditUtilTest
.
class
})
public
class
AllTests
{
...
...
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/ConfigControllerTest.java
View file @
9a621234
This diff is collapsed.
Click to expand it.
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/controller/ConfigFileControllerTest.java
View file @
9a621234
...
...
@@ -27,6 +27,7 @@ import java.lang.reflect.Type;
import
java.util.Map
;
import
java.util.Set
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
...
...
@@ -56,6 +57,8 @@ public class ConfigFileControllerTest {
private
String
someClientIp
;
@Mock
private
HttpServletResponse
someResponse
;
@Mock
private
HttpServletRequest
someRequest
;
Multimap
<
String
,
String
>
watchedKeys2CacheKey
;
Multimap
<
String
,
String
>
cacheKey2WatchedKeys
;
...
...
@@ -103,7 +106,7 @@ public class ConfigFileControllerTest {
when
(
someApolloConfig
.
getConfigurations
()).
thenReturn
(
configurations
);
when
(
configController
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
someResponse
)).
thenReturn
(
someApolloConfig
);
someRe
quest
,
someRe
sponse
)).
thenReturn
(
someApolloConfig
);
when
(
watchKeysUtil
.
assembleAllWatchKeys
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
))
.
thenReturn
(
watchKeys
);
...
...
@@ -111,7 +114,7 @@ public class ConfigFileControllerTest {
ResponseEntity
<
String
>
response
=
configFileController
.
queryConfigAsProperties
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
someClientIp
,
someResponse
);
someClientIp
,
someRe
quest
,
someRe
sponse
);
assertEquals
(
2
,
watchedKeys2CacheKey
.
size
());
assertEquals
(
2
,
cacheKey2WatchedKeys
.
size
());
...
...
@@ -127,13 +130,13 @@ public class ConfigFileControllerTest {
ResponseEntity
<
String
>
anotherResponse
=
configFileController
.
queryConfigAsProperties
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
someClientIp
,
someResponse
);
someClientIp
,
someRe
quest
,
someRe
sponse
);
assertEquals
(
response
,
anotherResponse
);
verify
(
configController
,
times
(
1
))
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
someResponse
);
someRe
quest
,
someRe
sponse
);
}
@Test
...
...
@@ -151,7 +154,7 @@ public class ConfigFileControllerTest {
ApolloConfig
someApolloConfig
=
mock
(
ApolloConfig
.
class
);
when
(
configController
.
queryConfig
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
"-1"
,
someClientIp
,
someResponse
)).
thenReturn
(
someApolloConfig
);
someRe
quest
,
someRe
sponse
)).
thenReturn
(
someApolloConfig
);
when
(
someApolloConfig
.
getConfigurations
()).
thenReturn
(
configurations
);
when
(
watchKeysUtil
.
assembleAllWatchKeys
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
))
...
...
@@ -160,7 +163,7 @@ public class ConfigFileControllerTest {
ResponseEntity
<
String
>
response
=
configFileController
.
queryConfigAsJson
(
someAppId
,
someClusterName
,
someNamespace
,
someDataCenter
,
someClientIp
,
someResponse
);
someClientIp
,
someRe
quest
,
someRe
sponse
);
assertEquals
(
HttpStatus
.
OK
,
response
.
getStatusCode
());
assertEquals
(
configurations
,
gson
.
fromJson
(
response
.
getBody
(),
responseType
));
...
...
apollo-configservice/src/test/java/com/ctrip/framework/apollo/configservice/util/InstanceConfigAuditUtilTest.java
0 → 100644
View file @
9a621234
package
com
.
ctrip
.
framework
.
apollo
.
configservice
.
util
;
import
com.ctrip.framework.apollo.biz.entity.Instance
;
import
com.ctrip.framework.apollo.biz.entity.InstanceConfig
;
import
com.ctrip.framework.apollo.biz.service.InstanceService
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.mockito.Mock
;
import
org.mockito.runners.MockitoJUnitRunner
;
import
org.springframework.test.util.ReflectionTestUtils
;
import
java.util.Objects
;
import
java.util.concurrent.BlockingQueue
;
import
java.util.function.ObjDoubleConsumer
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
mockito
.
Matchers
.
any
;
import
static
org
.
mockito
.
Matchers
.
anyBoolean
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith
(
MockitoJUnitRunner
.
class
)
public
class
InstanceConfigAuditUtilTest
{
private
InstanceConfigAuditUtil
instanceConfigAuditUtil
;
@Mock
private
InstanceService
instanceService
;
private
BlockingQueue
<
InstanceConfigAuditUtil
.
InstanceConfigAuditModel
>
audits
;
private
String
someAppId
;
private
String
someClusterName
;
private
String
someDataCenter
;
private
String
someIp
;
private
String
someConfigAppId
;
private
String
someConfigNamespace
;
private
String
someReleaseKey
;
private
InstanceConfigAuditUtil
.
InstanceConfigAuditModel
someAuditModel
;
@Before
public
void
setUp
()
throws
Exception
{
instanceConfigAuditUtil
=
new
InstanceConfigAuditUtil
();
ReflectionTestUtils
.
setField
(
instanceConfigAuditUtil
,
"instanceService"
,
instanceService
);
audits
=
(
BlockingQueue
<
InstanceConfigAuditUtil
.
InstanceConfigAuditModel
>)
ReflectionTestUtils
.
getField
(
instanceConfigAuditUtil
,
"audits"
);
someAppId
=
"someAppId"
;
someClusterName
=
"someClusterName"
;
someDataCenter
=
"someDataCenter"
;
someIp
=
"someIp"
;
someConfigAppId
=
"someConfigAppId"
;
someConfigNamespace
=
"someConfigNamespace"
;
someReleaseKey
=
"someReleaseKey"
;
someAuditModel
=
new
InstanceConfigAuditUtil
.
InstanceConfigAuditModel
(
someAppId
,
someClusterName
,
someDataCenter
,
someIp
,
someConfigAppId
,
someConfigNamespace
,
someReleaseKey
);
}
@Test
public
void
testAudit
()
throws
Exception
{
boolean
result
=
instanceConfigAuditUtil
.
audit
(
someAppId
,
someClusterName
,
someDataCenter
,
someIp
,
someConfigAppId
,
someConfigNamespace
,
someReleaseKey
);
InstanceConfigAuditUtil
.
InstanceConfigAuditModel
audit
=
audits
.
poll
();
assertTrue
(
result
);
assertTrue
(
Objects
.
equals
(
someAuditModel
,
audit
));
}
@Test
public
void
testDoAudit
()
throws
Exception
{
long
someInstanceId
=
1
;
Instance
someInstance
=
mock
(
Instance
.
class
);
when
(
someInstance
.
getId
()).
thenReturn
(
someInstanceId
);
when
(
instanceService
.
createInstance
(
any
(
Instance
.
class
))).
thenReturn
(
someInstance
);
instanceConfigAuditUtil
.
doAudit
(
someAuditModel
);
verify
(
instanceService
,
times
(
1
)).
findInstance
(
someAppId
,
someClusterName
,
someDataCenter
,
someIp
);
verify
(
instanceService
,
times
(
1
)).
createInstance
(
any
(
Instance
.
class
));
verify
(
instanceService
,
times
(
1
)).
findInstanceConfig
(
someInstanceId
,
someConfigAppId
,
someConfigNamespace
);
verify
(
instanceService
,
times
(
1
)).
createInstanceConfig
(
any
(
InstanceConfig
.
class
));
}
}
\ No newline at end of file
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