mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-02 20:02:29 +01:00
CLOUDSTACK-2655: use ssvm public IP to construct extract url.
This commit is contained in:
parent
4611b515db
commit
8d08f9b74b
@ -24,6 +24,7 @@ import com.cloud.agent.api.Command;
|
|||||||
public interface EndPoint {
|
public interface EndPoint {
|
||||||
public long getId();
|
public long getId();
|
||||||
public String getHostAddr();
|
public String getHostAddr();
|
||||||
|
public String getPublicAddr();
|
||||||
public Answer sendMessage(Command cmd);
|
public Answer sendMessage(Command cmd);
|
||||||
public void sendMessageAsync(Command cmd, AsyncCompletionCallback<Answer> callback);
|
public void sendMessageAsync(Command cmd, AsyncCompletionCallback<Answer> callback);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -266,12 +266,12 @@ public class SnapshotTest extends CloudStackTestNGBase {
|
|||||||
hosts.add(this.host);
|
hosts.add(this.host);
|
||||||
Mockito.when(resourceMgr.listAllUpAndEnabledHosts((Type) Mockito.any(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong())).thenReturn(hosts);
|
Mockito.when(resourceMgr.listAllUpAndEnabledHosts((Type) Mockito.any(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong())).thenReturn(hosts);
|
||||||
|
|
||||||
remoteEp = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host.getId(), this.host.getPrivateIpAddress());
|
remoteEp = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host.getId(), this.host.getPrivateIpAddress(), this.host.getPublicIpAddress());
|
||||||
Mockito.when(epSelector.select(Mockito.any(DataObject.class), Mockito.any(DataObject.class))).thenReturn(remoteEp);
|
Mockito.when(epSelector.select(Mockito.any(DataObject.class), Mockito.any(DataObject.class))).thenReturn(remoteEp);
|
||||||
Mockito.when(epSelector.select(Mockito.any(DataObject.class))).thenReturn(remoteEp);
|
Mockito.when(epSelector.select(Mockito.any(DataObject.class))).thenReturn(remoteEp);
|
||||||
Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(remoteEp);
|
Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(remoteEp);
|
||||||
Mockito.when(hyGuruMgr.getGuruProcessedCommandTargetHost(Mockito.anyLong(), Mockito.any(Command.class))).thenReturn(this.host.getId());
|
Mockito.when(hyGuruMgr.getGuruProcessedCommandTargetHost(Mockito.anyLong(), Mockito.any(Command.class))).thenReturn(this.host.getId());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataStore createPrimaryDataStore() {
|
public DataStore createPrimaryDataStore() {
|
||||||
@ -333,7 +333,7 @@ public class SnapshotTest extends CloudStackTestNGBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private VolumeVO createVolume(Long templateId, long dataStoreId) {
|
private VolumeVO createVolume(Long templateId, long dataStoreId) {
|
||||||
|
|
||||||
VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000);
|
VolumeVO volume = new VolumeVO(Volume.Type.DATADISK, UUID.randomUUID().toString(), this.dcId, 1L, 1L, 1L, 1000);
|
||||||
volume.setDataCenterId(this.dcId);
|
volume.setDataCenterId(this.dcId);
|
||||||
volume.setPoolId(dataStoreId);
|
volume.setPoolId(dataStoreId);
|
||||||
@ -376,18 +376,18 @@ public class SnapshotTest extends CloudStackTestNGBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssertJUnit.assertNotNull(newSnapshot);
|
AssertJUnit.assertNotNull(newSnapshot);
|
||||||
|
|
||||||
LocalHostEndpoint ep = new MockLocalHostEndPoint();
|
LocalHostEndpoint ep = new MockLocalHostEndPoint();
|
||||||
ep.setResource(new MockLocalNfsSecondaryStorageResource());
|
ep.setResource(new MockLocalNfsSecondaryStorageResource());
|
||||||
Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(ep);
|
Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(ep);
|
||||||
|
|
||||||
//delete snapshot
|
//delete snapshot
|
||||||
for (SnapshotStrategy strategy : this.snapshotStrategies) {
|
for (SnapshotStrategy strategy : this.snapshotStrategies) {
|
||||||
if (strategy.canHandle(snapshot)) {
|
if (strategy.canHandle(snapshot)) {
|
||||||
strategy.deleteSnapshot(newSnapshot.getId());
|
strategy.deleteSnapshot(newSnapshot.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(remoteEp);
|
Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(remoteEp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,7 +412,7 @@ public class SnapshotTest extends CloudStackTestNGBase {
|
|||||||
image = imageDataDao.persist(image);
|
image = imageDataDao.persist(image);
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createVolumeFromSnapshot() {
|
public void createVolumeFromSnapshot() {
|
||||||
VolumeInfo vol = createCopyBaseImage();
|
VolumeInfo vol = createCopyBaseImage();
|
||||||
@ -432,7 +432,7 @@ public class SnapshotTest extends CloudStackTestNGBase {
|
|||||||
VolumeInfo newVol = this.volFactory.getVolume(volVO.getId());
|
VolumeInfo newVol = this.volFactory.getVolume(volVO.getId());
|
||||||
this.volumeService.createVolumeFromSnapshot(newVol, newVol.getDataStore(), snapshot);
|
this.volumeService.createVolumeFromSnapshot(newVol, newVol.getDataStore(), snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void deleteSnapshot() {
|
public void deleteSnapshot() {
|
||||||
VolumeInfo vol = createCopyBaseImage();
|
VolumeInfo vol = createCopyBaseImage();
|
||||||
@ -445,14 +445,14 @@ public class SnapshotTest extends CloudStackTestNGBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssertJUnit.assertNotNull(newSnapshot);
|
AssertJUnit.assertNotNull(newSnapshot);
|
||||||
|
|
||||||
//create another snapshot
|
//create another snapshot
|
||||||
for (SnapshotStrategy strategy : this.snapshotStrategies) {
|
for (SnapshotStrategy strategy : this.snapshotStrategies) {
|
||||||
if (strategy.canHandle(snapshot)) {
|
if (strategy.canHandle(snapshot)) {
|
||||||
strategy.deleteSnapshot(newSnapshot.getId());
|
strategy.deleteSnapshot(newSnapshot.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -477,6 +477,6 @@ public class SnapshotTest extends CloudStackTestNGBase {
|
|||||||
DataStore imageStore = this.dataStoreMgr.getImageStore(this.dcId);
|
DataStore imageStore = this.dataStoreMgr.getImageStore(this.dcId);
|
||||||
this.imageService.createTemplateFromSnapshotAsync(snapshot, tmpl, imageStore);
|
this.imageService.createTemplateFromSnapshotAsync(snapshot, tmpl, imageStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -247,7 +247,7 @@ public class VolumeTest extends CloudStackTestNGBase {
|
|||||||
hosts.add(this.host);
|
hosts.add(this.host);
|
||||||
Mockito.when(resourceMgr.listAllUpAndEnabledHosts((Type) Mockito.any(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong())).thenReturn(hosts);
|
Mockito.when(resourceMgr.listAllUpAndEnabledHosts((Type) Mockito.any(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong())).thenReturn(hosts);
|
||||||
|
|
||||||
RemoteHostEndPoint ep = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host.getId(), this.host.getPrivateIpAddress());
|
RemoteHostEndPoint ep = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host.getId(), this.host.getPrivateIpAddress(), this.host.getPublicIpAddress());
|
||||||
Mockito.when(epSelector.select(Mockito.any(DataObject.class), Mockito.any(DataObject.class))).thenReturn(ep);
|
Mockito.when(epSelector.select(Mockito.any(DataObject.class), Mockito.any(DataObject.class))).thenReturn(ep);
|
||||||
Mockito.when(epSelector.select(Mockito.any(DataObject.class))).thenReturn(ep);
|
Mockito.when(epSelector.select(Mockito.any(DataObject.class))).thenReturn(ep);
|
||||||
Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(ep);
|
Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(ep);
|
||||||
|
|||||||
@ -167,7 +167,7 @@ public class VolumeTestVmware extends CloudStackTestNGBase {
|
|||||||
cluster.setManagedState(ManagedState.Managed);
|
cluster.setManagedState(ManagedState.Managed);
|
||||||
cluster = clusterDao.persist(cluster);
|
cluster = clusterDao.persist(cluster);
|
||||||
clusterId = cluster.getId();
|
clusterId = cluster.getId();
|
||||||
|
|
||||||
//setup vcenter
|
//setup vcenter
|
||||||
ClusterDetailsVO clusterDetailVO = new ClusterDetailsVO(cluster.getId(), "url", null);
|
ClusterDetailsVO clusterDetailVO = new ClusterDetailsVO(cluster.getId(), "url", null);
|
||||||
this.clusterDetailsDao.persist(clusterDetailVO);
|
this.clusterDetailsDao.persist(clusterDetailVO);
|
||||||
@ -253,7 +253,7 @@ public class VolumeTestVmware extends CloudStackTestNGBase {
|
|||||||
hosts.add(this.host);
|
hosts.add(this.host);
|
||||||
Mockito.when(resourceMgr.listAllUpAndEnabledHosts((Type) Mockito.any(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong())).thenReturn(hosts);
|
Mockito.when(resourceMgr.listAllUpAndEnabledHosts((Type) Mockito.any(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong())).thenReturn(hosts);
|
||||||
|
|
||||||
RemoteHostEndPoint ep = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host.getId(), this.host.getPrivateIpAddress());
|
RemoteHostEndPoint ep = RemoteHostEndPoint.getHypervisorHostEndPoint(this.host.getId(), this.host.getPrivateIpAddress(), this.host.getPublicIpAddress());
|
||||||
Mockito.when(epSelector.select(Mockito.any(DataObject.class), Mockito.any(DataObject.class))).thenReturn(ep);
|
Mockito.when(epSelector.select(Mockito.any(DataObject.class), Mockito.any(DataObject.class))).thenReturn(ep);
|
||||||
Mockito.when(epSelector.select(Mockito.any(DataObject.class))).thenReturn(ep);
|
Mockito.when(epSelector.select(Mockito.any(DataObject.class))).thenReturn(ep);
|
||||||
Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(ep);
|
Mockito.when(epSelector.select(Mockito.any(DataStore.class))).thenReturn(ep);
|
||||||
|
|||||||
@ -128,7 +128,7 @@ public class volumeServiceTest extends CloudStackTestNGBase {
|
|||||||
@Test(priority = -1)
|
@Test(priority = -1)
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
ComponentContext.initComponentsLifeCycle();
|
ComponentContext.initComponentsLifeCycle();
|
||||||
|
|
||||||
host = hostDao.findByGuid(this.getHostGuid());
|
host = hostDao.findByGuid(this.getHostGuid());
|
||||||
if (host != null) {
|
if (host != null) {
|
||||||
dcId = host.getDataCenterId();
|
dcId = host.getDataCenterId();
|
||||||
@ -170,7 +170,7 @@ public class volumeServiceTest extends CloudStackTestNGBase {
|
|||||||
host.setClusterId(cluster.getId());
|
host.setClusterId(cluster.getId());
|
||||||
|
|
||||||
host = hostDao.persist(host);
|
host = hostDao.persist(host);
|
||||||
|
|
||||||
imageStore = new ImageStoreVO();
|
imageStore = new ImageStoreVO();
|
||||||
imageStore.setName("test");
|
imageStore.setName("test");
|
||||||
imageStore.setDataCenterId(dcId);
|
imageStore.setDataCenterId(dcId);
|
||||||
@ -194,7 +194,7 @@ public class volumeServiceTest extends CloudStackTestNGBase {
|
|||||||
Mockito.when(hostDao.findHypervisorHostInCluster(Mockito.anyLong())).thenReturn(results);
|
Mockito.when(hostDao.findHypervisorHostInCluster(Mockito.anyLong())).thenReturn(results);
|
||||||
List<EndPoint> eps = new ArrayList<EndPoint>();
|
List<EndPoint> eps = new ArrayList<EndPoint>();
|
||||||
eps.add(RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(),
|
eps.add(RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(),
|
||||||
host.getPrivateIpAddress()));
|
host.getPrivateIpAddress(), host.getPublicIpAddress()));
|
||||||
Mockito.when(selector.selectAll(Mockito.any(DataStore.class))).thenReturn(eps);
|
Mockito.when(selector.selectAll(Mockito.any(DataStore.class))).thenReturn(eps);
|
||||||
Mockito.when(selector.select(Mockito.any(DataObject.class))).thenReturn(eps.get(0));
|
Mockito.when(selector.select(Mockito.any(DataObject.class))).thenReturn(eps.get(0));
|
||||||
Mockito.when(selector.select(Mockito.any(DataObject.class), Mockito.any(DataObject.class))).thenReturn(eps.get(0));
|
Mockito.when(selector.select(Mockito.any(DataObject.class), Mockito.any(DataObject.class))).thenReturn(eps.get(0));
|
||||||
@ -219,10 +219,10 @@ public class volumeServiceTest extends CloudStackTestNGBase {
|
|||||||
image.setCrossZones(true);
|
image.setCrossZones(true);
|
||||||
image.setExtractable(true);
|
image.setExtractable(true);
|
||||||
|
|
||||||
|
|
||||||
//image.setImageDataStoreId(storeId);
|
//image.setImageDataStoreId(storeId);
|
||||||
image = imageDataDao.persist(image);
|
image = imageDataDao.persist(image);
|
||||||
|
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,7 @@ import com.cloud.agent.api.storage.DownloadAnswer;
|
|||||||
import com.cloud.resource.ServerResource;
|
import com.cloud.resource.ServerResource;
|
||||||
import com.cloud.storage.VMTemplateStorageResourceAssoc;
|
import com.cloud.storage.VMTemplateStorageResourceAssoc;
|
||||||
import com.cloud.storage.download.DownloadListener;
|
import com.cloud.storage.download.DownloadListener;
|
||||||
|
import com.cloud.utils.net.NetUtils;
|
||||||
|
|
||||||
public class LocalHostEndpoint implements EndPoint {
|
public class LocalHostEndpoint implements EndPoint {
|
||||||
private ScheduledExecutorService executor;
|
private ScheduledExecutorService executor;
|
||||||
@ -53,6 +54,12 @@ public class LocalHostEndpoint implements EndPoint {
|
|||||||
return "127.0.0.0";
|
return "127.0.0.0";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPublicAddr() {
|
||||||
|
return NetUtils.getDefaultHostIp();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Answer sendMessage(Command cmd) {
|
public Answer sendMessage(Command cmd) {
|
||||||
if ((cmd instanceof CopyCommand) || (cmd instanceof DownloadCommand)) {
|
if ((cmd instanceof CopyCommand) || (cmd instanceof DownloadCommand)) {
|
||||||
|
|||||||
@ -49,6 +49,7 @@ public class RemoteHostEndPoint implements EndPoint {
|
|||||||
private static final Logger s_logger = Logger.getLogger(RemoteHostEndPoint.class);
|
private static final Logger s_logger = Logger.getLogger(RemoteHostEndPoint.class);
|
||||||
private long hostId;
|
private long hostId;
|
||||||
private String hostAddress;
|
private String hostAddress;
|
||||||
|
private String publicAddress;
|
||||||
@Inject
|
@Inject
|
||||||
AgentManager agentMgr;
|
AgentManager agentMgr;
|
||||||
@Inject
|
@Inject
|
||||||
@ -61,14 +62,15 @@ public class RemoteHostEndPoint implements EndPoint {
|
|||||||
executor = Executors.newScheduledThreadPool(10);
|
executor = Executors.newScheduledThreadPool(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configure(long hostId, String hostAddress) {
|
private void configure(long hostId, String hostAddress, String publicAddress) {
|
||||||
this.hostId = hostId;
|
this.hostId = hostId;
|
||||||
this.hostAddress = hostAddress;
|
this.hostAddress = hostAddress;
|
||||||
|
this.publicAddress = publicAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RemoteHostEndPoint getHypervisorHostEndPoint(long hostId, String hostAddress) {
|
public static RemoteHostEndPoint getHypervisorHostEndPoint(long hostId, String hostAddress, String publicAddress) {
|
||||||
RemoteHostEndPoint ep = ComponentContext.inject(RemoteHostEndPoint.class);
|
RemoteHostEndPoint ep = ComponentContext.inject(RemoteHostEndPoint.class);
|
||||||
ep.configure(hostId, hostAddress);
|
ep.configure(hostId, hostAddress, publicAddress);
|
||||||
return ep;
|
return ep;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,6 +79,11 @@ public class RemoteHostEndPoint implements EndPoint {
|
|||||||
return this.hostAddress;
|
return this.hostAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getPublicAddr() {
|
||||||
|
return this.publicAddress;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getId() {
|
public long getId() {
|
||||||
return this.hostId;
|
return this.hostId;
|
||||||
|
|||||||
@ -144,7 +144,7 @@ public class DefaultEndPointSelector implements EndPointSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(),
|
return RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(),
|
||||||
host.getPrivateIpAddress());
|
host.getPrivateIpAddress(), host.getPublicIpAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected EndPoint findEndPointForImageMove(DataStore srcStore,
|
protected EndPoint findEndPointForImageMove(DataStore srcStore,
|
||||||
@ -204,7 +204,7 @@ public class DefaultEndPointSelector implements EndPointSelector {
|
|||||||
}
|
}
|
||||||
Collections.shuffle(ssAHosts);
|
Collections.shuffle(ssAHosts);
|
||||||
HostVO host = ssAHosts.get(0);
|
HostVO host = ssAHosts.get(0);
|
||||||
return RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(), host.getPrivateIpAddress());
|
return RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(), host.getPrivateIpAddress(), host.getPublicIpAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<HostVO> listUpAndConnectingSecondaryStorageVmHost(Long dcId) {
|
private List<HostVO> listUpAndConnectingSecondaryStorageVmHost(Long dcId) {
|
||||||
@ -243,7 +243,7 @@ public class DefaultEndPointSelector implements EndPointSelector {
|
|||||||
if (store.getScope().getScopeType() == ScopeType.HOST) {
|
if (store.getScope().getScopeType() == ScopeType.HOST) {
|
||||||
HostVO host = hostDao.findById(store.getScope().getScopeId());
|
HostVO host = hostDao.findById(store.getScope().getScopeId());
|
||||||
endPoints.add(RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(),
|
endPoints.add(RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(),
|
||||||
host.getPrivateIpAddress()));
|
host.getPrivateIpAddress(), host.getPublicIpAddress()));
|
||||||
} else if (store.getScope().getScopeType() == ScopeType.CLUSTER) {
|
} else if (store.getScope().getScopeType() == ScopeType.CLUSTER) {
|
||||||
SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2.create(HostVO.class);
|
SearchCriteriaService<HostVO, HostVO> sc = SearchCriteria2.create(HostVO.class);
|
||||||
sc.addAnd(sc.getEntity().getClusterId(), Op.EQ, store.getScope().getScopeId());
|
sc.addAnd(sc.getEntity().getClusterId(), Op.EQ, store.getScope().getScopeId());
|
||||||
@ -251,7 +251,7 @@ public class DefaultEndPointSelector implements EndPointSelector {
|
|||||||
List<HostVO> hosts = sc.find();
|
List<HostVO> hosts = sc.find();
|
||||||
for (HostVO host : hosts) {
|
for (HostVO host : hosts) {
|
||||||
endPoints.add(RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(),
|
endPoints.add(RemoteHostEndPoint.getHypervisorHostEndPoint(host.getId(),
|
||||||
host.getPrivateIpAddress()));
|
host.getPrivateIpAddress(), host.getPublicIpAddress()));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -239,7 +239,7 @@ public class UploadMonitorImpl extends ManagerBase implements UploadMonitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Construct actual URL locally now that the symlink exists at SSVM
|
//Construct actual URL locally now that the symlink exists at SSVM
|
||||||
String extractURL = generateCopyUrl(ep.getHostAddr(), uuid);
|
String extractURL = generateCopyUrl(ep.getPublicAddr(), uuid);
|
||||||
UploadVO vo = _uploadDao.createForUpdate();
|
UploadVO vo = _uploadDao.createForUpdate();
|
||||||
vo.setLastUpdated(new Date());
|
vo.setLastUpdated(new Date());
|
||||||
vo.setUploadUrl(extractURL);
|
vo.setUploadUrl(extractURL);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user