Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

5441 lines (4679 sloc) 172.12 kb
/*************************************************************************
* Copyright 2009-2012 Eucalyptus Systems, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
* Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
* CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
* additional information or have any questions.
*
* This file may incorporate work covered under the following copyright
* and permission notice:
*
* Software License Agreement (BSD License)
*
* Copyright (c) 2008, Regents of the University of California
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms,
* with or without modification, are permitted provided that the
* following conditions are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. USERS OF THIS SOFTWARE ACKNOWLEDGE
* THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE LICENSED MATERIAL,
* COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS SOFTWARE,
* AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
* IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA,
* SANTA BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY,
* WHICH IN THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION,
* REPLACEMENT OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO
* IDENTIFIED, OR WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT
* NEEDED TO COMPLY WITH ANY SUCH LICENSES OR RIGHTS.
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <math.h>
#include "axis2_skel_EucalyptusCC.h"
#include <server-marshal.h>
#include <handlers.h>
#include <vnetwork.h>
#include <misc.h>
#include <ipc.h>
#include <walrus.h>
#include <http.h>
#include <euca_axis.h>
#include "data.h"
#include "client-marshal.h"
#include <storage-windows.h>
#include <euca_auth.h>
#include <handlers-state.h>
#include "fault.h"
#include <eucalyptus.h>
#define SUPERUSER "eucalyptus"
#define MAX_SENSOR_RESOURCES MAXINSTANCES_PER_CC
// Globals
// local globals
int config_init=0;
int local_init=0;
int thread_init=0;
int sensor_initd=0;
int init=0;
// shared (between CC processes) globals
ccConfig *config=NULL;
ccInstanceCache *instanceCache=NULL;
vnetConfig *vnetconfig=NULL;
ccResourceCache *resourceCache=NULL;
ccResourceCache *resourceCacheStage=NULL;
sensorResourceCache *ccSensorResourceCache=NULL;
// shared (between CC processes) semaphores
sem_t *locks[ENDLOCK];
int mylocks[ENDLOCK];
#ifndef NO_COMP
const char * euca_this_component_name = "cc";
const char * euca_client_component_name = "clc";
#endif
void doInitCC(void) {
initialize(NULL);
}
int doBundleInstance(ncMetadata *ccMeta, char *instanceId, char *bucketName, char *filePrefix, char *walrusURL, char *userPublicKey, char *S3Policy, char *S3PolicySig) {
int i, j, rc, start = 0, stop = 0, ret=0, timeout, done;
char internalWalrusURL[MAX_PATH], theWalrusURL[MAX_PATH];
ccInstance *myInstance;
ncStub *ncs;
time_t op_start;
ccResourceCache resourceCacheLocal;
i = j = 0;
myInstance = NULL;
op_start = time(NULL);
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO, "invoked\n");
logprintfl(EUCADEBUG, "params: userId=%s, instanceId=%s, bucketName=%s, filePrefix=%s, walrusURL=%s, userPublicKey=%s, S3Policy=%s, S3PolicySig=%s\n", SP(ccMeta ? ccMeta->userId : "UNSET"), SP(instanceId), SP(bucketName), SP(filePrefix), SP(walrusURL), SP(userPublicKey), SP(S3Policy), SP(S3PolicySig));
if (!instanceId) {
logprintfl(EUCAERROR, "bad input params\n");
return(1);
}
// get internal walrus IP
done=0;
internalWalrusURL[0] = '\0';
for (i=0; i<16 && !done; i++) {
if (!strcmp(config->services[i].type, "walrus")) {
snprintf(internalWalrusURL, MAX_PATH, "%s", config->services[i].uris[0]);
done++;
}
}
if (done) {
snprintf(theWalrusURL, MAX_PATH, "%s", internalWalrusURL);
} else {
strncpy(theWalrusURL, walrusURL, strlen(walrusURL)+1);
}
sem_mywait(RESCACHE);
memcpy(&resourceCacheLocal, resourceCache, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
rc = find_instanceCacheId(instanceId, &myInstance);
if (!rc) {
// found the instance in the cache
if (myInstance) {
start = myInstance->ncHostIdx;
stop = start+1;
free(myInstance);
}
} else {
start = 0;
stop = resourceCacheLocal.numResources;
}
done=0;
for (j=start; j<stop && !done; j++) {
timeout = ncGetTimeout(op_start, OP_TIMEOUT, stop-start, j);
rc = ncClientCall(ccMeta, timeout, resourceCacheLocal.resources[j].lockidx, resourceCacheLocal.resources[j].ncURL, "ncBundleInstance", instanceId, bucketName, filePrefix, theWalrusURL, userPublicKey, S3Policy, S3PolicySig);
if (rc) {
ret = 1;
} else {
ret = 0;
done++;
}
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(ret);
}
int doBundleRestartInstance(ncMetadata *ccMeta, char *instanceId) {
int j = 0;
int rc = 0;
int start = 0;
int stop = 0;
int ret = 0;
int timeout = 0;
int done = 0;
ccInstance *myInstance = NULL;
time_t op_start = time(NULL);
ccResourceCache resourceCacheLocal;
rc = initialize(ccMeta);
if (rc || ccIsEnabled())
return(1);
logprintfl(EUCAINFO, "invoked\n");
logprintfl(EUCADEBUG, "params: userId=%s, instanceId=%s\n", SP(ccMeta ? ccMeta->userId : "UNSET"), SP(instanceId));
if (instanceId == NULL) {
logprintfl(EUCAERROR, "bad input params\n");
return(1);
}
sem_mywait(RESCACHE);
{
memcpy(&resourceCacheLocal, resourceCache, sizeof(ccResourceCache));
}
sem_mypost(RESCACHE);
if ((rc = find_instanceCacheId(instanceId, &myInstance)) == 0) {
// found the instance in the cache
if (myInstance) {
start = myInstance->ncHostIdx;
stop = start + 1;
free(myInstance);
myInstance = NULL;
}
}
else {
start = 0;
stop = resourceCacheLocal.numResources;
}
done = 0;
for (j = start; ((j < stop) && !done); j++) {
timeout = ncGetTimeout(op_start, OP_TIMEOUT, (stop - start), j);
rc = ncClientCall(ccMeta, timeout, resourceCacheLocal.resources[j].lockidx, resourceCacheLocal.resources[j].ncURL, "ncBundleRestartInstance", instanceId);
if (rc) {
ret = 1;
} else {
ret = 0;
done++;
}
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(ret);
}
int doCancelBundleTask(ncMetadata *ccMeta, char *instanceId) {
int i, rc, start = 0, stop = 0, ret=0, done, timeout;
ccInstance *myInstance;
ncStub *ncs;
time_t op_start;
ccResourceCache resourceCacheLocal;
i = 0;
myInstance = NULL;
op_start = time(NULL);
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO, "invoked\n");
logprintfl(EUCADEBUG, "params: userId=%s, instanceId=%s\n", SP(ccMeta ? ccMeta->userId : "UNSET"), SP(instanceId));
if (!instanceId) {
logprintfl(EUCAERROR, "bad input params\n");
return(1);
}
sem_mywait(RESCACHE);
memcpy(&resourceCacheLocal, resourceCache, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
rc = find_instanceCacheId(instanceId, &myInstance);
if (!rc) {
// found the instance in the cache
if (myInstance) {
start = myInstance->ncHostIdx;
stop = start+1;
free(myInstance);
}
} else {
start = 0;
stop = resourceCacheLocal.numResources;
}
done=0;
for (i=start; i<stop && !done; i++) {
timeout = ncGetTimeout(op_start, OP_TIMEOUT, stop-start, i);
rc = ncClientCall(ccMeta, timeout, resourceCacheLocal.resources[i].lockidx, resourceCacheLocal.resources[i].ncURL, "ncCancelBundleTask", instanceId);
if (rc) {
ret = 1;
} else {
ret = 0;
done++;
}
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(ret);
}
int ncClientCall(ncMetadata *meta, int timeout, int ncLock, char *ncURL, char *ncOp, ...) {
va_list al;
int pid, rc=0, ret=0, status=0, opFail=0, len, rbytes, i;
int filedes[2];
logprintfl(EUCADEBUG, "invoked ncOps=%s ncURL=%s timeout=%d\n", ncOp, ncURL, timeout);
rc = pipe(filedes);
if (rc) {
logprintfl(EUCAERROR, "cannot create pipe ncOps=%s\n", ncOp);
return(1);
}
va_start(al, ncOp);
// grab the lock
sem_mywait(ncLock);
pid = fork();
if (!pid) {
ncStub *ncs;
ncMetadata *localmeta=NULL;
localmeta = malloc(sizeof(ncMetadata));
if (!localmeta) {
logprintfl(EUCAFATAL, "out of memory! ncOps=%s\n", ncOp);
unlock_exit(1);
}
memcpy(localmeta, meta, sizeof(ncMetadata));
if (meta->correlationId) {
localmeta->correlationId = strdup(meta->correlationId);
} else {
localmeta->correlationId = strdup("unset");
}
if (meta->userId) {
localmeta->userId = strdup(meta->userId);
} else {
localmeta->userId = strdup("eucalyptus");
}
close(filedes[0]);
ncs = ncStubCreate(ncURL, NULL, NULL);
if (config->use_wssec) {
rc = InitWSSEC(ncs->env, ncs->stub, config->policyFile);
}
logprintfl(EUCADEBUG, "\tncOps=%s ppid=%d client calling '%s'\n", ncOp, getppid(), ncOp);
if (!strcmp(ncOp, "ncGetConsoleOutput")) {
// args: char *instId
char *instId = va_arg(al, char *);
char **consoleOutput=va_arg(al, char **);
rc = ncGetConsoleOutputStub(ncs, localmeta, instId, consoleOutput);
if (timeout && consoleOutput) {
if (!rc && *consoleOutput) {
len = strlen(*consoleOutput) + 1;
rc = write(filedes[1], &len, sizeof(int));
rc = write(filedes[1], *consoleOutput, sizeof(char) * len);
rc = 0;
} else {
len = 0;
rc = write(filedes[1], &len, sizeof(int));
rc = 1;
}
}
} else if (!strcmp(ncOp, "ncAttachVolume")) {
char *instanceId = va_arg(al, char *);
char *volumeId = va_arg(al, char *);
char *remoteDev = va_arg(al, char *);
char *localDev = va_arg(al, char *);
rc = ncAttachVolumeStub(ncs, localmeta, instanceId, volumeId, remoteDev, localDev);
} else if (!strcmp(ncOp, "ncDetachVolume")) {
char *instanceId = va_arg(al, char *);
char *volumeId = va_arg(al, char *);
char *remoteDev = va_arg(al, char *);
char *localDev = va_arg(al, char *);
int force = va_arg(al, int);
rc = ncDetachVolumeStub(ncs, localmeta, instanceId, volumeId, remoteDev, localDev, force);
} else if (!strcmp(ncOp, "ncCreateImage")) {
char *instanceId = va_arg(al, char *);
char *volumeId = va_arg(al, char *);
char *remoteDev = va_arg(al, char *);
rc = ncCreateImageStub(ncs, localmeta, instanceId, volumeId, remoteDev);
} else if (!strcmp(ncOp, "ncPowerDown")) {
rc = ncPowerDownStub(ncs, localmeta);
} else if (!strcmp(ncOp, "ncAssignAddress")) {
char *instanceId = va_arg(al, char *);
char *publicIp = va_arg(al, char *);
rc = ncAssignAddressStub(ncs, localmeta, instanceId, publicIp);
} else if (!strcmp(ncOp, "ncRebootInstance")) {
char *instId = va_arg(al, char *);
rc = ncRebootInstanceStub(ncs, localmeta, instId);
} else if (!strcmp(ncOp, "ncTerminateInstance")) {
char *instId = va_arg(al, char *);
int force = va_arg(al, int);
int *shutdownState = va_arg(al, int *);
int *previousState = va_arg(al, int *);
rc = ncTerminateInstanceStub(ncs, localmeta, instId, force, shutdownState, previousState);
if (timeout) {
if (!rc) {
len = 2;
rc = write(filedes[1], &len, sizeof(int));
rc = write(filedes[1], shutdownState, sizeof(int));
rc = write(filedes[1], previousState, sizeof(int));
rc = 0;
} else {
len = 0;
rc = write(filedes[1], &len, sizeof(int));
rc = 1;
}
}
} else if (!strcmp(ncOp, "ncStartNetwork")) {
char *uuid = va_arg(al, char *);
char **peers = va_arg(al, char **);
int peersLen = va_arg(al, int);
int port = va_arg(al, int);
int vlan = va_arg(al, int);
char **outStatus = va_arg(al, char **);
rc = ncStartNetworkStub(ncs, localmeta, uuid, peers, peersLen, port, vlan, outStatus);
if (timeout && outStatus) {
if (!rc && *outStatus) {
len = strlen(*outStatus) + 1;
rc = write(filedes[1], &len, sizeof(int));
rc = write(filedes[1], *outStatus, sizeof(char) * len);
rc = 0;
} else {
len = 0;
rc = write(filedes[1], &len, sizeof(int));
rc = 1;
}
}
} else if (!strcmp(ncOp, "ncRunInstance")) {
char *uuid = va_arg(al, char *);
char *instId = va_arg(al, char *);
char *reservationId = va_arg(al, char *);
virtualMachine *ncvm = va_arg(al, virtualMachine *);
char *imageId = va_arg(al, char *);
char *imageURL = va_arg(al, char *);
char *kernelId = va_arg(al, char *);
char *kernelURL = va_arg(al, char *);
char *ramdiskId = va_arg(al, char *);
char *ramdiskURL = va_arg(al, char *);
char *ownerId = va_arg(al, char *);
char *accountId = va_arg(al, char *);
char *keyName = va_arg(al, char *);
netConfig *ncnet = va_arg(al, netConfig *);
char *userData = va_arg(al, char *);
char *launchIndex = va_arg(al, char *);
char *platform = va_arg(al, char *);
int expiryTime = va_arg(al, int);
char **netNames = va_arg(al, char **);
int netNamesLen = va_arg(al, int);
ncInstance **outInst = va_arg(al, ncInstance **);
rc = ncRunInstanceStub(ncs, localmeta, uuid, instId, reservationId, ncvm, imageId, imageURL, kernelId, kernelURL, ramdiskId, ramdiskURL, ownerId, accountId, keyName, ncnet, userData, launchIndex, platform, expiryTime, netNames, netNamesLen, outInst);
if (timeout && outInst) {
if (!rc && *outInst) {
len = sizeof(ncInstance);
rc = write(filedes[1], &len, sizeof(int));
rc = write(filedes[1], *outInst, sizeof(ncInstance));
rc = 0;
} else {
len = 0;
rc = write(filedes[1], &len, sizeof(int));
rc = 1;
}
}
} else if (!strcmp(ncOp, "ncDescribeInstances")) {
char **instIds = va_arg(al, char **);
int instIdsLen = va_arg(al, int);
ncInstance ***ncOutInsts=va_arg(al, ncInstance ***);
int *ncOutInstsLen= va_arg(al, int *);
rc = ncDescribeInstancesStub(ncs, localmeta, instIds, instIdsLen, ncOutInsts, ncOutInstsLen);
if (timeout && ncOutInsts && ncOutInstsLen) {
if (!rc) {
len = *ncOutInstsLen;
rc = write(filedes[1], &len, sizeof(int));
for (i=0; i<len; i++) {
ncInstance *inst;
inst = (*ncOutInsts)[i];
rc = write(filedes[1], inst, sizeof(ncInstance));
}
rc = 0;
} else {
len = 0;
rc = write(filedes[1], &len, sizeof(int));
rc = 1;
}
}
} else if (!strcmp(ncOp, "ncDescribeResource")) {
char *resourceType = va_arg(al, char *);
ncResource **outRes=va_arg(al, ncResource **);
rc = ncDescribeResourceStub(ncs, localmeta, resourceType, outRes);
if (timeout && outRes) {
if (!rc && *outRes) {
len = sizeof(ncResource);
rc = write(filedes[1], &len, sizeof(int));
rc = write(filedes[1], *outRes, sizeof(ncResource));
rc = 0;
} else {
len = 0;
rc = write(filedes[1], &len, sizeof(int));
rc = 1;
}
}
} else if (!strcmp(ncOp, "ncDescribeSensors")) {
int history_size = va_arg(al, int);
long long collection_interval_time_ms = va_arg(al, long long);
char **instIds = va_arg(al, char **);
int instIdsLen = va_arg(al, int);
char **sensorIds = va_arg(al, char **);
int sensorIdsLen = va_arg(al, int);
sensorResource ***srs=va_arg(al, sensorResource ***);
int *srsLen= va_arg(al, int *);
rc = ncDescribeSensorsStub(ncs, localmeta, history_size, collection_interval_time_ms, instIds, instIdsLen, sensorIds, sensorIdsLen, srs, srsLen);
if (timeout && srs && srsLen) {
if (!rc) {
len = *srsLen;
rc = write(filedes[1], &len, sizeof(int));
for (i=0; i<len; i++) {
sensorResource *sr;
sr = (*srs)[i];
rc = write(filedes[1], sr, sizeof(sensorResource));
}
rc = 0;
} else {
len = 0;
rc = write(filedes[1], &len, sizeof(int));
rc = 1;
}
}
} else if (!strcmp(ncOp, "ncBundleInstance")) {
char *instanceId = va_arg(al, char *);
char *bucketName = va_arg(al, char *);
char *filePrefix = va_arg(al, char *);
char *walrusURL = va_arg(al, char *);
char *userPublicKey = va_arg(al, char *);
char *S3Policy = va_arg(al, char *);
char *S3PolicySig = va_arg(al, char *);
rc = ncBundleInstanceStub(ncs, localmeta, instanceId, bucketName, filePrefix, walrusURL, userPublicKey, S3Policy, S3PolicySig);
} else if (!strcmp(ncOp, "ncBundleRestartInstance")) {
char *instanceId = va_arg(al, char *);
rc = ncBundleRestartInstanceStub(ncs, localmeta, instanceId);
} else if (!strcmp(ncOp, "ncCancelBundleTask")) {
char *instanceId = va_arg(al, char *);
rc = ncCancelBundleTaskStub(ncs, localmeta, instanceId);
} else {
logprintfl(EUCAWARN, "\tncOps=%s ppid=%d operation '%s' not found\n", ncOp, getppid(), ncOp);
rc = 1;
}
logprintfl(EUCADEBUG, "\tncOps=%s ppid=%d done calling '%s' with exit code '%d'\n", ncOp, getppid(), ncOp, rc);
if (rc) {
ret = 1;
} else {
ret = 0;
}
close(filedes[1]);
if (localmeta) free(localmeta);
exit(ret);
} else {
// returns for each client call
close(filedes[1]);
if (!strcmp(ncOp, "ncGetConsoleOutput")) {
char *instId = va_arg(al, char *);
char **outConsoleOutput = va_arg(al, char **);
if (outConsoleOutput) {
*outConsoleOutput = NULL;
}
if (timeout && outConsoleOutput) {
rbytes = timeread(filedes[0], &len, sizeof(int), timeout);
if (rbytes <= 0) {
kill(pid, SIGKILL);
opFail=1;
} else {
*outConsoleOutput = malloc(sizeof(char) * len);
if (!*outConsoleOutput) {
logprintfl(EUCAFATAL, "out of memory! ncOps=%s\n", ncOp);
unlock_exit(1);
}
rbytes = timeread(filedes[0], *outConsoleOutput, len, timeout);
if (rbytes <= 0) {
kill(pid, SIGKILL);
opFail=1;
}
}
}
} else if (!strcmp(ncOp, "ncTerminateInstance")) {
char *instId = va_arg(al, char *);
int force = va_arg(al, int);
int *shutdownState = va_arg(al, int *);
int *previousState = va_arg(al, int *);
if (shutdownState && previousState) {
*shutdownState = *previousState = 0;
}
if (timeout && shutdownState && previousState) {
rbytes = timeread(filedes[0], &len, sizeof(int), timeout);
if (rbytes <= 0) {
kill(pid, SIGKILL);
opFail=1;
} else {
rbytes = timeread(filedes[0], shutdownState, sizeof(int), timeout);
if (rbytes <= 0) {
kill(pid, SIGKILL);
opFail=1;
}
rbytes = timeread(filedes[0], previousState, sizeof(int), timeout);
if (rbytes <= 0) {
kill(pid, SIGKILL);
opFail=1;
}
}
}
} else if (!strcmp(ncOp, "ncStartNetwork")) {
char *uuid = va_arg(al, char *);
char **peers = va_arg(al, char **);
int peersLen = va_arg(al, int);
int port = va_arg(al, int);
int vlan = va_arg(al, int);
char **outStatus = va_arg(al, char **);
if (outStatus) {
*outStatus = NULL;
}
if (timeout && outStatus) {
*outStatus = NULL;
rbytes = timeread(filedes[0], &len, sizeof(int), timeout);
if (rbytes <= 0) {
kill(pid, SIGKILL);
opFail=1;
} else {
*outStatus = malloc(sizeof(char) * len);
if (!*outStatus) {
logprintfl(EUCAFATAL, "out of memory! ncOps=%s\n", ncOp);
unlock_exit(1);
}
rbytes = timeread(filedes[0], *outStatus, len, timeout);
if (rbytes <= 0) {
kill(pid, SIGKILL);
opFail=1;
}
}
}
} else if (!strcmp(ncOp, "ncRunInstance")) {
char *uuid = va_arg(al, char *);
char *instId = va_arg(al, char *);
char *reservationId = va_arg(al, char *);
virtualMachine *ncvm = va_arg(al, virtualMachine *);
char *imageId = va_arg(al, char *);
char *imageURL = va_arg(al, char *);
char *kernelId = va_arg(al, char *);
char *kernelURL = va_arg(al, char *);
char *ramdiskId = va_arg(al, char *);
char *ramdiskURL = va_arg(al, char *);
char *ownerId = va_arg(al, char *);
char *accountId = va_arg(al, char *);
char *keyName = va_arg(al, char *);
netConfig *ncnet = va_arg(al, netConfig *);
char *userData = va_arg(al, char *);
char *launchIndex = va_arg(al, char *);
char *platform = va_arg(al, char *);
int expiryTime = va_arg(al, int);
char **netNames = va_arg(al, char **);
int netNamesLen = va_arg(al, int);
ncInstance **outInst = va_arg(al, ncInstance **);
if (outInst) {
*outInst = NULL;
}
if (timeout && outInst) {
rbytes = timeread(filedes[0], &len, sizeof(int), timeout);
if (rbytes <= 0) {
kill(pid, SIGKILL);
opFail=1;
} else {
*outInst = malloc(sizeof(ncInstance));
if (!*outInst) {
logprintfl(EUCAFATAL, "out of memory! ncOps=%s\n", ncOp);
unlock_exit(1);
}
rbytes = timeread(filedes[0], *outInst, sizeof(ncInstance), timeout);
if (rbytes <= 0) {
kill(pid, SIGKILL);
opFail=1;
}
}
}
} else if (!strcmp(ncOp, "ncDescribeInstances")) {
char **instIds = va_arg(al, char **);
int instIdsLen = va_arg(al, int);
ncInstance ***ncOutInsts=va_arg(al, ncInstance ***);
int *ncOutInstsLen=va_arg(al, int *);
if (ncOutInstsLen && ncOutInsts) {
*ncOutInstsLen = 0;
*ncOutInsts = NULL;
}
if (timeout && ncOutInsts && ncOutInstsLen) {
rbytes = timeread(filedes[0], &len, sizeof(int), timeout);
if (rbytes <= 0) {
kill(pid, SIGKILL);
opFail=1;
} else {
*ncOutInsts = malloc(sizeof(ncInstance *) * len);
if (!*ncOutInsts) {
logprintfl(EUCAFATAL, "out of memory! ncOps=%s\n", ncOp);
unlock_exit(1);
}
*ncOutInstsLen = len;
for (i=0; i<len; i++) {
ncInstance *inst;
inst = malloc(sizeof(ncInstance));
if (!inst) {
logprintfl(EUCAFATAL, "out of memory! ncOps=%s\n", ncOp);
unlock_exit(1);
}
rbytes = timeread(filedes[0], inst, sizeof(ncInstance), timeout);
(*ncOutInsts)[i] = inst;
}
}
}
} else if (!strcmp(ncOp, "ncDescribeResource")) {
char *resourceType = va_arg(al, char *);
ncResource **outRes=va_arg(al, ncResource **);
if (outRes) {
*outRes = NULL;
}
if (timeout && outRes) {
rbytes = timeread(filedes[0], &len, sizeof(int), timeout);
if (rbytes <= 0) {
kill(pid, SIGKILL);
opFail=1;
} else {
*outRes = malloc(sizeof(ncResource));
if (*outRes == NULL) {
logprintfl(EUCAFATAL, "out of memory! ncOps=%s\n", ncOp);
unlock_exit(1);
}
rbytes = timeread(filedes[0], *outRes, sizeof(ncResource), timeout);
if (rbytes <= 0) {
kill(pid, SIGKILL);
opFail=1;
}
}
}
} else if (!strcmp(ncOp, "ncDescribeSensors")) {
int history_size = va_arg(al, int);
long long collection_interval_time_ms = va_arg(al, long long);
char **instIds = va_arg(al, char **);
int instIdsLen = va_arg(al, int);
char **sensorIds = va_arg(al, char **);
int sensorIdsLen = va_arg(al, int);
sensorResource ***srs=va_arg(al, sensorResource ***);
int *srsLen= va_arg(al, int *);
if (srs && srsLen) {
* srs = NULL;
* srsLen = 0;
}
if (timeout && srs && srsLen) {
rbytes = timeread(filedes[0], &len, sizeof(int), timeout);
if (rbytes <= 0) {
kill (pid, SIGKILL);
opFail = 1;
} else {
* srs = malloc(sizeof(sensorResource *) * len);
if (* srs == NULL) {
logprintfl(EUCAFATAL, "out of memory! ncOps=%s\n", ncOp);
unlock_exit(1);
}
* srsLen = len;
for (i=0; i<len; i++) {
sensorResource * sr;
sr = malloc (sizeof (sensorResource));
if (sr == NULL) {
logprintfl(EUCAFATAL, "out of memory! ncOps=%s\n", ncOp);
unlock_exit(1);
}
rbytes = timeread(filedes[0], sr, sizeof (sensorResource), timeout);
(* srs)[i] = sr;
}
}
}
} else {
// nothing to do in default case (succ/fail encoded in exit code)
}
close(filedes[0]);
if (timeout) {
rc = timewait(pid, &status, timeout);
rc = WEXITSTATUS(status);
} else {
rc = 0;
}
}
logprintfl(EUCADEBUG, "done ncOps=%s clientrc=%d opFail=%d\n", ncOp, rc, opFail);
if (rc || opFail) {
ret = 1;
} else {
ret = 0;
}
// release the lock
sem_mypost(ncLock);
va_end(al);
return(ret);
}
// calculate nc call timeout, based on when operation was started (op_start), the total number of calls to make (numCalls), and the current progress (idx)
int ncGetTimeout(time_t op_start, time_t op_max, int numCalls, int idx) {
time_t op_timer, op_pernode;
int numLeft;
numLeft = numCalls - idx;
if ( numLeft <= 0 ) {
numLeft = 1;
}
op_timer = op_max - (time(NULL) - op_start);
op_pernode = op_timer / numLeft;
return(maxint(minint(op_pernode, OP_TIMEOUT_PERNODE), OP_TIMEOUT_MIN));
}
int doAttachVolume(ncMetadata *ccMeta, char *volumeId, char *instanceId, char *remoteDev, char *localDev) {
int i, rc, start = 0, stop = 0, ret=0, done=0, timeout;
ccInstance *myInstance;
ncStub *ncs;
time_t op_start;
ccResourceCache resourceCacheLocal;
i = 0;
myInstance = NULL;
op_start = time(NULL);
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO, "invoked\n");
logprintfl(EUCADEBUG, "params: userId=%s, volumeId=%s, instanceId=%s, remoteDev=%s, localDev=%s\n", SP(ccMeta ? ccMeta->userId : "UNSET"), SP(volumeId), SP(instanceId), SP(remoteDev), SP(localDev));
if (!volumeId || !instanceId || !remoteDev || !localDev) {
logprintfl(EUCAERROR, "bad input params\n");
return(1);
}
sem_mywait(RESCACHE);
memcpy(&resourceCacheLocal, resourceCache, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
rc = find_instanceCacheId(instanceId, &myInstance);
if (!rc) {
// found the instance in the cache
if (myInstance) {
start = myInstance->ncHostIdx;
stop = start+1;
free(myInstance);
}
} else {
start = 0;
stop = resourceCacheLocal.numResources;
}
done=0;
for (i=start; i<stop && !done; i++) {
timeout = ncGetTimeout(op_start, OP_TIMEOUT, stop-start, i);
rc = ncClientCall(ccMeta, timeout, resourceCacheLocal.resources[i].lockidx, resourceCacheLocal.resources[i].ncURL, "ncAttachVolume", instanceId, volumeId, remoteDev, localDev);
if (rc) {
ret = 1;
} else {
ret = 0;
done++;
}
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(ret);
}
int doDetachVolume(ncMetadata *ccMeta, char *volumeId, char *instanceId, char *remoteDev, char *localDev, int force) {
int i, rc, start = 0, stop = 0, ret=0, done=0, timeout;
ccInstance *myInstance;
ncStub *ncs;
time_t op_start;
ccResourceCache resourceCacheLocal;
i = 0;
myInstance = NULL;
op_start = time(NULL);
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO, "invoked\n");
logprintfl(EUCADEBUG, "params: userId=%s, volumeId=%s, instanceId=%s, remoteDev=%s, localDev=%s, force=%d\n", SP(ccMeta ? ccMeta->userId : "UNSET"), SP(volumeId), SP(instanceId), SP(remoteDev), SP(localDev), force);
if (!volumeId || !instanceId || !remoteDev || !localDev) {
logprintfl(EUCAERROR, "bad input params\n");
return(1);
}
sem_mywait(RESCACHE);
memcpy(&resourceCacheLocal, resourceCache, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
rc = find_instanceCacheId(instanceId, &myInstance);
if (!rc) {
// found the instance in the cache
if (myInstance) {
start = myInstance->ncHostIdx;
stop = start+1;
free(myInstance);
}
} else {
start = 0;
stop = resourceCacheLocal.numResources;
}
for (i=start; i<stop; i++) {
timeout = ncGetTimeout(op_start, OP_TIMEOUT, stop-start, i);
rc = ncClientCall(ccMeta, timeout, resourceCacheLocal.resources[i].lockidx, resourceCacheLocal.resources[i].ncURL, "ncDetachVolume", instanceId, volumeId, remoteDev, localDev, force);
if (rc) {
ret = 1;
} else {
ret = 0;
done++;
}
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(ret);
}
int doConfigureNetwork(ncMetadata *ccMeta, char *accountId, char *type, int namedLen, char **sourceNames, char **userNames, int netLen, char **sourceNets, char *destName, char *destUserName, char *protocol, int minPort, int maxPort) {
int rc, i, fail;
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO, "invoked\n");
logprintfl(EUCADEBUG, "params: userId=%s, accountId=%s, type=%s, namedLen=%d, netLen=%d, destName=%s, destUserName=%s, protocol=%s, minPort=%d, maxPort=%d\n", ccMeta ? SP(ccMeta->userId) : "UNSET", SP(accountId), SP(type), namedLen, netLen, SP(destName), SP(destUserName), SP(protocol), minPort, maxPort);
if (!strcmp(vnetconfig->mode, "SYSTEM") || !strcmp(vnetconfig->mode, "STATIC") || !strcmp(vnetconfig->mode, "STATIC-DYNMAC")) {
fail = 0;
} else {
if ( destUserName == NULL ) {
if ( accountId ) {
destUserName = accountId;
} else {
// destUserName is not set, return fail
logprintfl(EUCAERROR, "cannot set destUserName from ccMeta or input\n");
return(1);
}
}
sem_mywait(VNET);
fail=0;
for (i=0; i<namedLen; i++) {
if (sourceNames && userNames) {
rc = vnetTableRule(vnetconfig, type, destUserName, destName, userNames[i], NULL, sourceNames[i], protocol, minPort, maxPort);
}
if (rc) {
logprintfl(EUCAERROR,"vnetTableRule() returned error rc=%d\n", rc);
fail=1;
}
}
for (i=0; i<netLen; i++) {
if (sourceNets) {
rc = vnetTableRule(vnetconfig, type, destUserName, destName, NULL, sourceNets[i], NULL, protocol, minPort, maxPort);
}
if (rc) {
logprintfl(EUCAERROR,"vnetTableRule() returned error rc=%d\n", rc);
fail=1;
}
}
sem_mypost(VNET);
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
if (fail) {
return(1);
}
return(0);
}
int doFlushNetwork(ncMetadata *ccMeta, char *accountId, char *destName) {
int rc;
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
if (!strcmp(vnetconfig->mode, "SYSTEM") || !strcmp(vnetconfig->mode, "STATIC") || !strcmp(vnetconfig->mode, "STATIC-DYNMAC") ) {
return(0);
}
sem_mywait(VNET);
rc = vnetFlushTable(vnetconfig, accountId, destName);
sem_mypost(VNET);
return(rc);
}
int doAssignAddress(ncMetadata *ccMeta, char *uuid, char *src, char *dst) {
int rc, allocated, addrdevno, ret, i;
char cmd[MAX_PATH];
ccInstance *myInstance=NULL;
ccResourceCache resourceCacheLocal;
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO,"invoked\n");
logprintfl(EUCADEBUG,"params: src=%s, dst=%s\n", SP(src), SP(dst));
if (!src || !dst || !strcmp(src, "0.0.0.0")) {
logprintfl(EUCADEBUG, "bad input params\n");
return(1);
}
set_dirty_instanceCache();
sem_mywait(RESCACHE);
memcpy(&resourceCacheLocal, resourceCache, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
ret = 1;
if (!strcmp(vnetconfig->mode, "SYSTEM") || !strcmp(vnetconfig->mode, "STATIC") || !strcmp(vnetconfig->mode, "STATIC-DYNMAC") ) {
ret = 0;
} else {
rc = find_instanceCacheIP(dst, &myInstance);
if (!rc) {
if (myInstance) {
logprintfl(EUCADEBUG, "found local instance, applying %s->%s mapping\n", src, dst);
sem_mywait(VNET);
rc = vnetReassignAddress(vnetconfig, uuid, src, dst);
if (rc) {
logprintfl(EUCAERROR, "vnetReassignAddress() failed rc=%d\n", rc);
ret = 1;
} else {
ret = 0;
}
sem_mypost(VNET);
if (myInstance) free(myInstance);
}
} else {
logprintfl(EUCADEBUG, "skipping %s->%s mapping, as this clusters does not own the instance (%s)\n", src, dst, dst);
}
}
if (!ret && strcmp(dst, "0.0.0.0")) {
// everything worked, update instance cache
rc = map_instanceCache(privIpCmp, dst, pubIpSet, src);
if (rc) {
logprintfl(EUCAERROR, "map_instanceCache() failed to assign %s->%s\n", dst, src);
} else {
rc = find_instanceCacheIP(src, &myInstance);
if (!rc) {
logprintfl(EUCADEBUG, "found instance (%s) in cache with IP (%s)\n", myInstance->instanceId, myInstance->ccnet.publicIp);
// found the instance in the cache
if (myInstance) {
//timeout = ncGetTimeout(op_start, OP_TIMEOUT, 1, myInstance->ncHostIdx);
rc = ncClientCall(ccMeta, OP_TIMEOUT, resourceCacheLocal.resources[myInstance->ncHostIdx].lockidx, resourceCacheLocal.resources[myInstance->ncHostIdx].ncURL, "ncAssignAddress", myInstance->instanceId, myInstance->ccnet.publicIp);
if (rc) {
logprintfl(EUCAERROR, "could not sync public IP %s with NC\n", src);
ret = 1;
} else {
ret = 0;
}
if (myInstance) free(myInstance);
}
}
}
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(ret);
}
int doDescribePublicAddresses(ncMetadata *ccMeta, publicip **outAddresses, int *outAddressesLen) {
int rc, ret;
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO, "invoked\n");
logprintfl(EUCADEBUG, "params: userId=%s\n", SP(ccMeta ? ccMeta->userId : "UNSET"));
ret=0;
if (!strcmp(vnetconfig->mode, "MANAGED") || !strcmp(vnetconfig->mode, "MANAGED-NOVLAN")) {
sem_mywait(VNET);
*outAddresses = vnetconfig->publicips;
*outAddressesLen = NUMBER_OF_PUBLIC_IPS;
sem_mypost(VNET);
} else {
*outAddresses = NULL;
*outAddressesLen = 0;
ret=0;
}
logprintfl(EUCADEBUG, "done.\n");
shawn();
return(ret);
}
int doUnassignAddress(ncMetadata *ccMeta, char *src, char *dst) {
int rc, allocated, addrdevno, ret;
char cmd[MAX_PATH];
ccInstance *myInstance=NULL;
ccResourceCache resourceCacheLocal;
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO,"invoked\n");
logprintfl(EUCADEBUG,"params: userId=%s, src=%s, dst=%s\n", SP(ccMeta ? ccMeta->userId : "UNSET"), SP(src), SP(dst));
if (!src || !dst || !strcmp(src, "0.0.0.0")) {
logprintfl(EUCADEBUG, "bad input params\n");
return(1);
}
set_dirty_instanceCache();
sem_mywait(RESCACHE);
memcpy(&resourceCacheLocal, resourceCache, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
ret=0;
if (!strcmp(vnetconfig->mode, "SYSTEM") || !strcmp(vnetconfig->mode, "STATIC") || !strcmp(vnetconfig->mode, "STATIC-DYNMAC") ) {
ret = 0;
} else {
sem_mywait(VNET);
ret = vnetReassignAddress(vnetconfig, "UNSET", src, "0.0.0.0");
if (ret) {
logprintfl(EUCAERROR, "vnetReassignAddress() failed ret=%d\n", ret);
ret = 1;
}
sem_mypost(VNET);
}
if (!ret) {
rc = find_instanceCacheIP(src, &myInstance);
if (!rc) {
logprintfl(EUCADEBUG, "found instance %s in cache with IP %s\n", myInstance->instanceId, myInstance->ccnet.publicIp);
// found the instance in the cache
if (myInstance) {
//timeout = ncGetTimeout(op_start, OP_TIMEOUT, 1, myInstance->ncHostIdx);
rc = ncClientCall(ccMeta, OP_TIMEOUT, resourceCacheLocal.resources[myInstance->ncHostIdx].lockidx, resourceCacheLocal.resources[myInstance->ncHostIdx].ncURL, "ncAssignAddress", myInstance->instanceId, "0.0.0.0");
if (rc) {
logprintfl(EUCAERROR, "could not sync IP with NC\n");
ret = 1;
} else {
ret = 0;
}
if (myInstance) free(myInstance);
}
}
// refresh instance cache
rc = map_instanceCache(pubIpCmp, src, pubIpSet, "0.0.0.0");
if (rc) {
logprintfl(EUCAERROR, "map_instanceCache() failed to assign %s->%s\n", dst, src);
}
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(ret);
}
int doStopNetwork(ncMetadata *ccMeta, char *accountId, char *netName, int vlan) {
int rc, ret;
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO, "invoked\n");
logprintfl(EUCADEBUG, "params: userId=%s, accountId=%s, netName=%s, vlan=%d\n", SP(ccMeta ? ccMeta->userId : "UNSET"), SP(accountId), SP(netName), vlan);
if (!ccMeta || !netName || vlan < 0) {
logprintfl(EUCAERROR, "bad input params\n");
}
if (!strcmp(vnetconfig->mode, "SYSTEM") || !strcmp(vnetconfig->mode, "STATIC") || !strcmp(vnetconfig->mode, "STATIC-DYNMAC") ) {
ret = 0;
} else {
sem_mywait(VNET);
if(ccMeta != NULL) {
rc = vnetStopNetwork(vnetconfig, vlan, accountId, netName);
}
ret = rc;
sem_mypost(VNET);
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(ret);
}
int doDescribeNetworks(ncMetadata *ccMeta, char *nameserver, char **ccs, int ccsLen, vnetConfig *outvnetConfig) {
int rc, i, j;
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO, "invoked\n");
logprintfl(EUCADEBUG, "params: userId=%s, nameserver=%s, ccsLen=%d\n", SP(ccMeta ? ccMeta->userId : "UNSET"), SP(nameserver), ccsLen);
// ensure that we have the latest network state from the CC (based on instance cache) before responding to CLC
rc = checkActiveNetworks();
if (rc) {
logprintfl(EUCAWARN, "checkActiveNetworks() failed, will attempt to re-sync\n");
}
sem_mywait(VNET);
if (nameserver) {
vnetconfig->euca_ns = dot2hex(nameserver);
}
if (!strcmp(vnetconfig->mode, "MANAGED") || !strcmp(vnetconfig->mode, "MANAGED-NOVLAN")) {
rc = vnetSetCCS(vnetconfig, ccs, ccsLen);
rc = vnetSetupTunnels(vnetconfig);
}
memcpy(outvnetConfig, vnetconfig, sizeof(vnetConfig));
sem_mypost(VNET);
logprintfl(EUCADEBUG, "done.\n");
shawn();
return(0);
}
int doStartNetwork(ncMetadata *ccMeta, char *accountId, char *uuid, char *netName, int vlan, char *nameserver, char **ccs, int ccsLen) {
int rc, ret;
char *brname;
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO, "invoked\n");
logprintfl(EUCADEBUG, "params: userId=%s, accountId=%s, netName=%s, vlan=%d, nameserver=%s, ccsLen=%d\n", SP(ccMeta ? ccMeta->userId : "UNSET"), SP(accountId), SP(netName), vlan, SP(nameserver), ccsLen);
if (!strcmp(vnetconfig->mode, "SYSTEM") || !strcmp(vnetconfig->mode, "STATIC") || !strcmp(vnetconfig->mode, "STATIC-DYNMAC") ) {
ret = 0;
} else {
sem_mywait(VNET);
if (nameserver) {
vnetconfig->euca_ns = dot2hex(nameserver);
}
rc = vnetSetCCS(vnetconfig, ccs, ccsLen);
rc = vnetSetupTunnels(vnetconfig);
brname = NULL;
rc = vnetStartNetwork(vnetconfig, vlan, uuid, accountId, netName, &brname);
if (brname) free(brname);
sem_mypost(VNET);
if (rc) {
logprintfl(EUCAERROR,"vnetStartNetwork() failed (%d)\n", rc);
ret = 1;
} else {
ret = 0;
}
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(ret);
}
int doDescribeResources(ncMetadata *ccMeta, virtualMachine **ccvms, int vmLen, int **outTypesMax, int **outTypesAvail, int *outTypesLen, ccResource **outNodes, int *outNodesLen) {
int i;
int rc, diskpool, mempool, corepool;
int j;
ccResource *res;
ccResourceCache resourceCacheLocal;
char strbuf[4096];
logprintfl(EUCAINFO,"invoked\n");
logprintfl(EUCADEBUG,"params: userId=%s, vmLen=%d\n", SP(ccMeta ? ccMeta->userId : "UNSET"), vmLen);
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
if (outTypesMax == NULL || outTypesAvail == NULL || outTypesLen == NULL || outNodes == NULL || outNodesLen == NULL) {
// input error
return(1);
}
*outTypesMax = NULL;
*outTypesAvail = NULL;
*outTypesMax = malloc(sizeof(int) * vmLen);
*outTypesAvail = malloc(sizeof(int) * vmLen);
if (*outTypesMax == NULL || *outTypesAvail == NULL) {
logprintfl(EUCAERROR,"out of memory\n");
unlock_exit(1);
}
bzero(*outTypesMax, sizeof(int) * vmLen);
bzero(*outTypesAvail, sizeof(int) * vmLen);
*outTypesLen = vmLen;
for (i=0; i<vmLen; i++) {
if ((*ccvms)[i].mem <= 0 || (*ccvms)[i].cores <= 0 || (*ccvms)[i].disk <= 0) {
logprintfl(EUCAERROR,"input error\n");
if (*outTypesAvail) free(*outTypesAvail);
if (*outTypesMax) free(*outTypesMax);
*outTypesLen = 0;
return(1);
}
}
sem_mywait(RESCACHE);
memcpy(&resourceCacheLocal, resourceCache, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
{
*outNodes = malloc(sizeof(ccResource) * resourceCacheLocal.numResources);
if (*outNodes == NULL) {
logprintfl(EUCAFATAL,"out of memory!\n");
unlock_exit(1);
} else {
bzero(*outNodes, sizeof(ccResource) * resourceCacheLocal.numResources);
memcpy(*outNodes, resourceCacheLocal.resources, sizeof(ccResource) * resourceCacheLocal.numResources);
*outNodesLen = resourceCacheLocal.numResources;
}
for (i=0; i<resourceCacheLocal.numResources; i++) {
res = &(resourceCacheLocal.resources[i]);
for (j=0; j<vmLen; j++) {
mempool = res->availMemory;
diskpool = res->availDisk;
corepool = res->availCores;
mempool -= (*ccvms)[j].mem;
diskpool -= (*ccvms)[j].disk;
corepool -= (*ccvms)[j].cores;
while (mempool >= 0 && diskpool >= 0 && corepool >= 0) {
(*outTypesAvail)[j]++;
mempool -= (*ccvms)[j].mem;
diskpool -= (*ccvms)[j].disk;
corepool -= (*ccvms)[j].cores;
}
mempool = res->maxMemory;
diskpool = res->maxDisk;
corepool = res->maxCores;
mempool -= (*ccvms)[j].mem;
diskpool -= (*ccvms)[j].disk;
corepool -= (*ccvms)[j].cores;
while (mempool >= 0 && diskpool >= 0 && corepool >= 0) {
(*outTypesMax)[j]++;
mempool -= (*ccvms)[j].mem;
diskpool -= (*ccvms)[j].disk;
corepool -= (*ccvms)[j].cores;
}
}
}
}
if (vmLen >= 5) {
logprintfl(EUCAINFO,"resource response summary (name{avail/max}): %s{%d/%d} %s{%d/%d} %s{%d/%d} %s{%d/%d} %s{%d/%d}\n", (*ccvms)[0].name, (*outTypesAvail)[0], (*outTypesMax)[0], (*ccvms)[1].name, (*outTypesAvail)[1], (*outTypesMax)[1], (*ccvms)[2].name, (*outTypesAvail)[2], (*outTypesMax)[2], (*ccvms)[3].name, (*outTypesAvail)[3], (*outTypesMax)[3], (*ccvms)[4].name, (*outTypesAvail)[4], (*outTypesMax)[4]);
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(0);
}
int changeState(ccResource *in, int newstate) {
if (in == NULL) return(1);
if (in->state == newstate) return(0);
in->lastState = in->state;
in->state = newstate;
in->stateChange = time(NULL);
in->idleStart = 0;
return(0);
}
int refresh_resources(ncMetadata *ccMeta, int timeout, int dolock) {
int i, rc, nctimeout, pid, *pids=NULL;
int status, ret=0;
time_t op_start;
ncStub *ncs;
ncResource *ncResDst=NULL;
if (timeout <= 0) timeout = 1;
op_start = time(NULL);
logprintfl(EUCAINFO,"invoked\n");
// critical NC call section
sem_mywait(RESCACHE);
memcpy(resourceCacheStage, resourceCache, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
sem_close(locks[REFRESHLOCK]);
locks[REFRESHLOCK] = sem_open("/eucalyptusCCrefreshLock", O_CREAT, 0644, config->ncFanout);
pids = malloc(sizeof(int) * resourceCacheStage->numResources);
if (!pids) {
logprintfl(EUCAFATAL, "out of memory!\n");
unlock_exit(1);
}
for (i=0; i<resourceCacheStage->numResources; i++) {
sem_mywait(REFRESHLOCK);
pid = fork();
if (!pid) {
ncResDst=NULL;
if (resourceCacheStage->resources[i].state != RESASLEEP && resourceCacheStage->resources[i].running == 0) {
// nctimeout = ncGetTimeout(op_start, timeout, resourceCacheStage->numResources, i);
nctimeout = ncGetTimeout(op_start, timeout, 1, 1);
rc = ncClientCall(ccMeta, nctimeout, resourceCacheStage->resources[i].lockidx, resourceCacheStage->resources[i].ncURL, "ncDescribeResource", NULL, &ncResDst);
if (rc != 0) {
powerUp(&(resourceCacheStage->resources[i]));
if (resourceCacheStage->resources[i].state == RESWAKING && ((time(NULL) - resourceCacheStage->resources[i].stateChange) < config->wakeThresh)) {
logprintfl(EUCADEBUG, "resource still waking up (%d more seconds until marked as down)\n", config->wakeThresh - (time(NULL) - resourceCacheStage->resources[i].stateChange));
} else{
logprintfl(EUCAERROR,"bad return from ncDescribeResource(%s) (%d)\n", resourceCacheStage->resources[i].hostname, rc);
resourceCacheStage->resources[i].maxMemory = 0;
resourceCacheStage->resources[i].availMemory = 0;
resourceCacheStage->resources[i].maxDisk = 0;
resourceCacheStage->resources[i].availDisk = 0;
resourceCacheStage->resources[i].maxCores = 0;
resourceCacheStage->resources[i].availCores = 0;
changeState(&(resourceCacheStage->resources[i]), RESDOWN);
}
} else {
logprintfl(EUCADEBUG,"received data from node=%s mem=%d/%d disk=%d/%d cores=%d/%d\n",
resourceCacheStage->resources[i].hostname,
ncResDst->memorySizeAvailable,
ncResDst->memorySizeMax,
ncResDst->diskSizeAvailable,
ncResDst->diskSizeMax,
ncResDst->numberOfCoresAvailable,
ncResDst->numberOfCoresMax);
resourceCacheStage->resources[i].maxMemory = ncResDst->memorySizeMax;
resourceCacheStage->resources[i].availMemory = ncResDst->memorySizeAvailable;
resourceCacheStage->resources[i].maxDisk = ncResDst->diskSizeMax;
resourceCacheStage->resources[i].availDisk = ncResDst->diskSizeAvailable;
resourceCacheStage->resources[i].maxCores = ncResDst->numberOfCoresMax;
resourceCacheStage->resources[i].availCores = ncResDst->numberOfCoresAvailable;
// set iqn, if set
if (strlen(ncResDst->iqn)) {
snprintf(resourceCacheStage->resources[i].iqn, 128, "%s", ncResDst->iqn);
}
changeState(&(resourceCacheStage->resources[i]), RESUP);
}
} else {
logprintfl(EUCADEBUG, "resource asleep/running instances (%d), skipping resource update\n", resourceCacheStage->resources[i].running);
}
// try to discover the mac address of the resource
if (resourceCacheStage->resources[i].mac[0] == '\0' && resourceCacheStage->resources[i].ip[0] != '\0') {
char *mac;
rc = ip2mac(vnetconfig, resourceCacheStage->resources[i].ip, &mac);
if (!rc) {
safe_strncpy(resourceCacheStage->resources[i].mac, mac, 24);
free(mac);
logprintfl(EUCADEBUG, "discovered MAC '%s' for host %s(%s)\n", resourceCacheStage->resources[i].mac, resourceCacheStage->resources[i].hostname, resourceCacheStage->resources[i].ip);
}
}
if (ncResDst) free(ncResDst);
sem_mypost(REFRESHLOCK);
exit(0);
} else {
pids[i] = pid;
}
}
for (i=0; i<resourceCacheStage->numResources; i++) {
rc = timewait(pids[i], &status, 120);
if (!rc) {
// timed out, really bad failure (reset REFRESHLOCK semaphore)
sem_close(locks[REFRESHLOCK]);
locks[REFRESHLOCK] = sem_open("/eucalyptusCCrefreshLock", O_CREAT, 0644, config->ncFanout);
rc = 1;
} else if (rc > 0) {
// process exited, and wait picked it up.
if (WIFEXITED(status)) {
rc = WEXITSTATUS(status);
} else {
rc = 1;
}
} else {
// process no longer exists, and someone else reaped it
rc = 0;
}
if (rc) {
logprintfl(EUCAWARN, "error waiting for child pid '%d', exit code '%d'\n", pids[i], rc);
}
}
sem_mywait(RESCACHE);
memcpy(resourceCache, resourceCacheStage, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
if (pids) free(pids);
logprintfl(EUCADEBUG,"done.\n");
return(0);
}
int refresh_instances(ncMetadata *ccMeta, int timeout, int dolock) {
ccInstance *myInstance=NULL;
int i, k, numInsts = 0, found, ncOutInstsLen, rc, pid, nctimeout, *pids=NULL, status;
time_t op_start;
ncInstance **ncOutInsts=NULL;
ncStub *ncs;
netConfig origNetConfig;
op_start = time(NULL);
logprintfl(EUCAINFO,"invoked\n");
set_clean_instanceCache();
// critical NC call section
sem_mywait(RESCACHE);
memcpy(resourceCacheStage, resourceCache, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
sem_close(locks[REFRESHLOCK]);
locks[REFRESHLOCK] = sem_open("/eucalyptusCCrefreshLock", O_CREAT, 0644, config->ncFanout);
pids = malloc(sizeof(int) * resourceCacheStage->numResources);
if (!pids) {
logprintfl(EUCAFATAL, "out of memory!\n");
unlock_exit(1);
}
invalidate_instanceCache();
for (i=0; i<resourceCacheStage->numResources; i++) {
sem_mywait(REFRESHLOCK);
pid = fork();
if (!pid) {
if (resourceCacheStage->resources[i].state == RESUP) {
int j;
nctimeout = ncGetTimeout(op_start, timeout, 1, 1);
rc = ncClientCall(ccMeta, nctimeout, resourceCacheStage->resources[i].lockidx, resourceCacheStage->resources[i].ncURL, "ncDescribeInstances", NULL, 0, &ncOutInsts, &ncOutInstsLen);
if (!rc) {
// if idle, power down
if (ncOutInstsLen == 0) {
logprintfl(EUCADEBUG, "node %s idle since %d: (%d/%d) seconds\n", resourceCacheStage->resources[i].hostname, resourceCacheStage->resources[i].idleStart, time(NULL) - resourceCacheStage->resources[i].idleStart, config->idleThresh);
if (!resourceCacheStage->resources[i].idleStart) {
resourceCacheStage->resources[i].idleStart = time(NULL);
} else if ((time(NULL) - resourceCacheStage->resources[i].idleStart) > config->idleThresh) {
// call powerdown
if (powerDown(ccMeta, &(resourceCacheStage->resources[i]))) {
logprintfl(EUCAWARN, "powerDown for %s failed\n", resourceCacheStage->resources[i].hostname);
}
}
} else {
resourceCacheStage->resources[i].idleStart = 0;
}
// populate instanceCache
for (j=0; j<ncOutInstsLen; j++) {
found=1;
if (found) {
myInstance = NULL;
// add it
logprintfl(EUCADEBUG,"describing instance %s, %s, %d\n", ncOutInsts[j]->instanceId, ncOutInsts[j]->stateName, j);
numInsts++;
// grab instance from cache, if available. otherwise, start from scratch
rc = find_instanceCacheId(ncOutInsts[j]->instanceId, &myInstance);
if (rc || !myInstance) {
myInstance = malloc(sizeof(ccInstance));
if (!myInstance) {
logprintfl(EUCAFATAL, "out of memory!\n");
unlock_exit(1);
}
bzero(myInstance, sizeof(ccInstance));
}
// update CC instance with instance state from NC
rc = ccInstance_to_ncInstance(myInstance, ncOutInsts[j]);
// instance info that the CC maintains
myInstance->ncHostIdx = i;
safe_strncpy(myInstance->serviceTag, resourceCacheStage->resources[i].ncURL, 64);
{
char *ip=NULL;
if (!strcmp(myInstance->ccnet.publicIp, "0.0.0.0")) {
if (!strcmp(vnetconfig->mode, "SYSTEM") || !strcmp(vnetconfig->mode, "STATIC") || !strcmp(vnetconfig->mode, "STATIC-DYNMAC") ) {
rc = mac2ip(vnetconfig, myInstance->ccnet.privateMac, &ip);
if (!rc) {
safe_strncpy(myInstance->ccnet.publicIp, ip, 24);
}
}
}
if (ip) free(ip);
ip=NULL;
if (!strcmp(myInstance->ccnet.privateIp, "0.0.0.0")) {
rc = mac2ip(vnetconfig, myInstance->ccnet.privateMac, &ip);
if (!rc) {
safe_strncpy(myInstance->ccnet.privateIp, ip, 24);
}
}
if (ip) free(ip);
}
//#if 0
if ((myInstance->ccnet.publicIp[0] != '\0' && strcmp(myInstance->ccnet.publicIp, "0.0.0.0")) && (myInstance->ncnet.publicIp[0] == '\0' || !strcmp(myInstance->ncnet.publicIp, "0.0.0.0"))) {
// CC has network info, NC does not
logprintfl(EUCADEBUG, "sending ncAssignAddress to sync NC\n");
rc = ncClientCall(ccMeta, nctimeout, resourceCacheStage->resources[i].lockidx, resourceCacheStage->resources[i].ncURL, "ncAssignAddress", myInstance->instanceId, myInstance->ccnet.publicIp);
if (rc) {
// problem, but will retry next time
logprintfl(EUCAWARN, "could not send AssignAddress to NC\n");
}
}
//#endif
refresh_instanceCache(myInstance->instanceId, myInstance);
if (!strcmp(myInstance->state, "Extant")) {
if (myInstance->ccnet.vlan < 0) {
vnetEnableHost(vnetconfig, myInstance->ccnet.privateMac, myInstance->ccnet.privateIp, 0);
} else {
vnetEnableHost(vnetconfig, myInstance->ccnet.privateMac, myInstance->ccnet.privateIp, myInstance->ccnet.vlan);
}
}
logprintfl(EUCADEBUG, "storing instance state: %s/%s/%s/%s\n", myInstance->instanceId, myInstance->state, myInstance->ccnet.publicIp, myInstance->ccnet.privateIp);
print_ccInstance("refresh_instances(): ", myInstance);
if (myInstance) free(myInstance);
}
}
}
if (ncOutInsts) {
for (j=0; j<ncOutInstsLen; j++) {
free_instance(&(ncOutInsts[j]));
}
free(ncOutInsts);
ncOutInsts = NULL;
}
}
sem_mypost(REFRESHLOCK);
exit(0);
} else {
pids[i] = pid;
}
}
for (i=0; i<resourceCacheStage->numResources; i++) {
rc = timewait(pids[i], &status, 120);
if (!rc) {
// timed out, really bad failure (reset REFRESHLOCK semaphore)
sem_close(locks[REFRESHLOCK]);
locks[REFRESHLOCK] = sem_open("/eucalyptusCCrefreshLock", O_CREAT, 0644, config->ncFanout);
rc = 1;
} else if (rc > 0) {
// process exited, and wait picked it up.
if (WIFEXITED(status)) {
rc = WEXITSTATUS(status);
} else {
rc = 1;
}
} else {
// process no longer exists, and someone else reaped it
rc = 0;
}
if (rc) {
logprintfl(EUCAWARN, "error waiting for child pid '%d', exit code '%d'\n", pids[i], rc);
}
}
sem_mywait(RESCACHE);
memcpy(resourceCache, resourceCacheStage, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
if (pids) free(pids);
logprintfl(EUCADEBUG,"done.\n");
return(0);
}
int refresh_sensors(ncMetadata *ccMeta, int timeout, int dolock) {
time_t op_start = time(NULL);
logprintfl(EUCAINFO,"invoked\n");
int history_size;
long long collection_interval_time_ms;
if ((sensor_get_config (&history_size, &collection_interval_time_ms) != 0) ||
history_size < 1 ||
collection_interval_time_ms == 0)
return 0; // sensor system not configured yet
// critical NC call section
sem_mywait(RESCACHE);
memcpy(resourceCacheStage, resourceCache, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
sem_close(locks[REFRESHLOCK]);
locks[REFRESHLOCK] = sem_open("/eucalyptusCCrefreshLock", O_CREAT, 0644, config->ncFanout);
int * pids = malloc(sizeof(int) * resourceCacheStage->numResources);
if (!pids) {
logprintfl(EUCAFATAL, "out of memory!\n");
unlock_exit(1);
}
for (int i=0; i<resourceCacheStage->numResources; i++) {
sem_mywait(REFRESHLOCK);
pid_t pid = fork();
if (!pid) {
if (resourceCacheStage->resources[i].state == RESUP) {
int nctimeout = ncGetTimeout(op_start, timeout, 1, 1);
sensorResource ** srs;
int srsLen;
int rc = ncClientCall(ccMeta, nctimeout, resourceCacheStage->resources[i].lockidx, resourceCacheStage->resources[i].ncURL, "ncDescribeSensors", history_size, collection_interval_time_ms, NULL, 0, NULL, 0, &srs, &srsLen);
if (!rc) {
// update our cache
if (sensor_merge_records (srs, srsLen, TRUE) != OK) {
logprintfl (EUCAWARN, "failed to store all sensor data due to lack of spacen");
}
if (srsLen > 0) {
for (int j=0; j<srsLen; j++) {
free (srs[j]);
}
free (srs);
}
}
}
sem_mypost(REFRESHLOCK);
exit(0);
} else {
pids[i] = pid;
}
}
for (int i=0; i<resourceCacheStage->numResources; i++) {
int status;
int rc = timewait(pids[i], &status, 120);
if (!rc) {
// timed out, really bad failure (reset REFRESHLOCK semaphore)
sem_close(locks[REFRESHLOCK]);
locks[REFRESHLOCK] = sem_open("/eucalyptusCCrefreshLock", O_CREAT, 0644, config->ncFanout);
rc = 1;
} else if (rc > 0) {
// process exited, and wait picked it up.
if (WIFEXITED(status)) {
rc = WEXITSTATUS(status);
} else {
rc = 1;
}
} else {
// process no longer exists, and someone else reaped it
rc = 0;
}
if (rc) {
logprintfl(EUCAWARN, "error waiting for child pid '%d', exit code '%d'\n", pids[i], rc);
}
}
sem_mywait(RESCACHE);
memcpy(resourceCache, resourceCacheStage, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
if (pids) free(pids);
logprintfl(EUCADEBUG,"done.\n");
return(0);
}
int doDescribeInstances(ncMetadata *ccMeta, char **instIds, int instIdsLen, ccInstance **outInsts, int *outInstsLen) {
ccInstance *myInstance=NULL, *out=NULL, *cacheInstance=NULL;
int i, k, numInsts, found, ncOutInstsLen, rc, pid, count;
virtualMachine ccvm;
time_t op_start;
ncInstance **ncOutInsts=NULL;
ncStub *ncs;
logprintfl(EUCAINFO,"invoked\n");
logprintfl(EUCADEBUG,"params: userId=%s, instIdsLen=%d\n", SP(ccMeta ? ccMeta->userId : "UNSET"), instIdsLen);
op_start = time(NULL);
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
*outInsts = NULL;
*outInstsLen = 0;
sem_mywait(INSTCACHE);
count=0;
if (instanceCache->numInsts) {
*outInsts = malloc(sizeof(ccInstance) * instanceCache->numInsts);
if (!*outInsts) {
logprintfl(EUCAFATAL, "out of memory!\n");
unlock_exit(1);
}
for (i=0; i<MAXINSTANCES_PER_CC; i++) {
if (instanceCache->cacheState[i] == INSTVALID) {
if (count >= instanceCache->numInsts) {
logprintfl(EUCAWARN, "found more instances than reported by numInsts, will only report a subset of instances\n");
count=0;
}
memcpy( &((*outInsts)[count]), &(instanceCache->instances[i]), sizeof(ccInstance));
count++;
}
}
*outInstsLen = instanceCache->numInsts;
}
sem_mypost(INSTCACHE);
for (i=0; i< (*outInstsLen) ; i++) {
logprintfl(EUCAINFO, "instance response summary: instanceId=%s, state=%s, publicIp=%s, privateIp=%s\n", (*outInsts)[i].instanceId, (*outInsts)[i].state, (*outInsts)[i].ccnet.publicIp, (*outInsts)[i].ccnet.privateIp);
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(0);
}
int powerUp(ccResource *res) {
int rc,ret,len, i;
char cmd[MAX_PATH], *bc=NULL;
uint32_t *ips=NULL, *nms=NULL;
if (config->schedPolicy != SCHEDPOWERSAVE) {
return(0);
}
rc = getdevinfo(vnetconfig->privInterface, &ips, &nms, &len);
if (rc) {
ips = malloc(sizeof(uint32_t));
if (!ips) {
logprintfl(EUCAFATAL, "out of memory!\n");
unlock_exit(1);
}
nms = malloc(sizeof(uint32_t));
if (!nms) {
logprintfl(EUCAFATAL, "out of memory!\n");
unlock_exit(1);
}
ips[0] = 0xFFFFFFFF;
nms[0] = 0xFFFFFFFF;
len = 1;
}
for (i=0; i<len; i++) {
logprintfl(EUCADEBUG, "attempting to wake up resource %s(%s/%s)\n", res->hostname, res->ip, res->mac);
// try to wake up res
// broadcast
bc = hex2dot((0xFFFFFFFF - nms[i]) | (ips[i] & nms[i]));
rc = 0;
ret = 0;
if (strcmp(res->mac, "00:00:00:00:00:00")) {
snprintf(cmd, MAX_PATH, EUCALYPTUS_ROOTWRAP " powerwake -b %s %s", vnetconfig->eucahome, bc, res->mac);
} else if (strcmp(res->ip, "0.0.0.0")) {
snprintf(cmd, MAX_PATH, EUCALYPTUS_ROOTWRAP " powerwake -b %s %s", vnetconfig->eucahome, bc, res->ip);
} else {
ret = rc = 1;
}
if (bc) free(bc);
if (!rc) {
logprintfl(EUCAINFO, "waking up powered off host %s(%s/%s): %s\n", res->hostname, res->ip, res->mac, cmd);
rc = system(cmd);
rc = rc>>8;
if (rc) {
logprintfl(EUCAERROR, "cmd failed: %d\n", rc);
ret = 1;
} else {
logprintfl(EUCAERROR, "cmd success: %d\n", rc);
changeState(res, RESWAKING);
ret = 0;
}
}
}
if (ips) free(ips);
if (nms) free(nms);
return(ret);
}
int powerDown(ncMetadata *ccMeta, ccResource *node) {
int pid, rc, status, timeout;
ncStub *ncs=NULL;
time_t op_start;
if (config->schedPolicy != SCHEDPOWERSAVE) {
node->idleStart = 0;
return(0);
}
op_start = time(NULL);
logprintfl(EUCAINFO, "sending powerdown to node: %s, %s\n", node->hostname, node->ncURL);
timeout = ncGetTimeout(op_start, OP_TIMEOUT, 1, 1);
rc = ncClientCall(ccMeta, timeout, node->lockidx, node->ncURL, "ncPowerDown");
if (rc == 0) {
changeState(node, RESASLEEP);
}
return(rc);
}
void print_netConfig(char *prestr, netConfig *in) {
logprintfl(EUCADEBUG, "%s: vlan:%d networkIndex:%d privateMac:%s publicIp:%s privateIp:%s\n", prestr, in->vlan, in->networkIndex, in->privateMac, in->publicIp, in->privateIp);
}
int ccInstance_to_ncInstance(ccInstance *dst, ncInstance *src) {
int i;
safe_strncpy(dst->uuid, src->uuid, 48);
safe_strncpy(dst->instanceId, src->instanceId, 16);
safe_strncpy(dst->reservationId, src->reservationId, 16);
safe_strncpy(dst->accountId, src->accountId, 48);
safe_strncpy(dst->ownerId, src->ownerId, 48);
safe_strncpy(dst->amiId, src->imageId, 16);
safe_strncpy(dst->kernelId, src->kernelId, 16);
safe_strncpy(dst->ramdiskId, src->ramdiskId, 16);
safe_strncpy(dst->keyName, src->keyName, 1024);
safe_strncpy(dst->launchIndex, src->launchIndex, 64);
safe_strncpy(dst->platform, src->platform, 64);
safe_strncpy(dst->bundleTaskStateName, src->bundleTaskStateName, 64);
safe_strncpy(dst->createImageTaskStateName, src->createImageTaskStateName, 64);
safe_strncpy(dst->userData, src->userData, 16384);
safe_strncpy(dst->state, src->stateName, 16);
dst->ts = src->launchTime;
memcpy(&(dst->ncnet), &(src->ncnet), sizeof(netConfig));
for (i=0; i < src->groupNamesSize && i < 64; i++) {
snprintf(dst->groupNames[i], 64, "%s", src->groupNames[i]);
}
memcpy(dst->volumes, src->volumes, sizeof(ncVolume) * EUCA_MAX_VOLUMES);
dst->volumesSize = 0;
for (i=0; i < EUCA_MAX_VOLUMES; i++) {
if (strlen (dst->volumes[i].volumeId) == 0)
break;
dst->volumesSize++;
}
memcpy(&(dst->ccvm), &(src->params), sizeof(virtualMachine));
dst->blkbytes = src->blkbytes;
dst->netbytes = src->netbytes;
return(0);
}
int schedule_instance(virtualMachine *vm, char *targetNode, int *outresid) {
int ret;
ncMetadata ccMeta;
if (targetNode != NULL) {
ret = schedule_instance_explicit(vm, targetNode, outresid);
} else if (config->schedPolicy == SCHEDGREEDY) {
ret = schedule_instance_greedy(vm, outresid);
} else if (config->schedPolicy == SCHEDROUNDROBIN) {
ret = schedule_instance_roundrobin(vm, outresid);
} else if (config->schedPolicy == SCHEDPOWERSAVE) {
ret = schedule_instance_greedy(vm, outresid);
} else {
ret = schedule_instance_greedy(vm, outresid);
}
return(ret);
}
int schedule_instance_roundrobin(virtualMachine *vm, int *outresid) {
int i, done, start, found, resid=0;
ccResource *res;
*outresid = 0;
logprintfl(EUCADEBUG, "scheduler using ROUNDROBIN policy to find next resource\n");
// find the best 'resource' on which to run the instance
done=found=0;
start = config->schedState;
i = start;
logprintfl(EUCADEBUG, "scheduler state starting at resource %d\n", config->schedState);
while(!done) {
int mem, disk, cores;
res = &(resourceCache->resources[i]);
if (res->state != RESDOWN) {
mem = res->availMemory - vm->mem;
disk = res->availDisk - vm->disk;
cores = res->availCores - vm->cores;
if (mem >= 0 && disk >= 0 && cores >= 0) {
resid = i;
found=1;
done++;
}
}
i++;
if (i >= resourceCache->numResources) {
i = 0;
}
if (i == start) {
done++;
}
}
if (!found) {
// didn't find a resource
return(1);
}
*outresid = resid;
config->schedState = i;
logprintfl(EUCADEBUG, "scheduler state finishing at resource %d\n", config->schedState);
return(0);
}
int schedule_instance_explicit(virtualMachine *vm, char *targetNode, int *outresid) {
int i, done, resid, sleepresid;
ccResource *res;
*outresid = 0;
logprintfl(EUCADEBUG, "scheduler using EXPLICIT policy to run VM on target node '%s'\n", targetNode);
// find the best 'resource' on which to run the instance
resid = sleepresid = -1;
done=0;
for (i=0; i<resourceCache->numResources && !done; i++) {
int mem, disk, cores;
res = &(resourceCache->resources[i]);
if (!strcmp(res->hostname, targetNode)) {
done++;
if (res->state == RESUP) {
mem = res->availMemory - vm->mem;
disk = res->availDisk - vm->disk;
cores = res->availCores - vm->cores;
if (mem >= 0 && disk >= 0 && cores >= 0) {
resid = i;
}
} else if (res->state == RESASLEEP) {
mem = res->availMemory - vm->mem;
disk = res->availDisk - vm->disk;
cores = res->availCores - vm->cores;
if (mem >= 0 && disk >= 0 && cores >= 0) {
sleepresid = i;
}
}
}
}
if (resid == -1 && sleepresid == -1) {
// target resource is unavailable
return(1);
}
if (resid != -1) {
res = &(resourceCache->resources[resid]);
*outresid = resid;
} else if (sleepresid != -1) {
res = &(resourceCache->resources[sleepresid]);
*outresid = sleepresid;
}
if (res->state == RESASLEEP) {
powerUp(res);
}
return(0);
}
int schedule_instance_greedy(virtualMachine *vm, int *outresid) {
int i, done, resid, sleepresid;
ccResource *res;
*outresid = 0;
if (config->schedPolicy == SCHEDGREEDY) {
logprintfl(EUCADEBUG, "scheduler using GREEDY policy to find next resource\n");
} else if (config->schedPolicy == SCHEDPOWERSAVE) {
logprintfl(EUCADEBUG, "scheduler using POWERSAVE policy to find next resource\n");
}
// find the best 'resource' on which to run the instance
resid = sleepresid = -1;
done=0;
for (i=0; i<resourceCache->numResources && !done; i++) {
int mem, disk, cores;
res = &(resourceCache->resources[i]);
if ((res->state == RESUP || res->state == RESWAKING) && resid == -1) {
mem = res->availMemory - vm->mem;
disk = res->availDisk - vm->disk;
cores = res->availCores - vm->cores;
if (mem >= 0 && disk >= 0 && cores >= 0) {
resid = i;
done++;
}
} else if (res->state == RESASLEEP && sleepresid == -1) {
mem = res->availMemory - vm->mem;
disk = res->availDisk - vm->disk;
cores = res->availCores - vm->cores;
if (mem >= 0 && disk >= 0 && cores >= 0) {
sleepresid = i;
}
}
}
if (resid == -1 && sleepresid == -1) {
// didn't find a resource
return(1);
}
if (resid != -1) {
res = &(resourceCache->resources[resid]);
*outresid = resid;
} else if (sleepresid != -1) {
res = &(resourceCache->resources[sleepresid]);
*outresid = sleepresid;
}
if (res->state == RESASLEEP) {
powerUp(res);
}
return(0);
}
int doRunInstances(ncMetadata *ccMeta, char *amiId, char *kernelId, char *ramdiskId, char *amiURL, char *kernelURL, char *ramdiskURL, char **instIds, int instIdsLen, char **netNames, int netNamesLen, char **macAddrs, int macAddrsLen, int *networkIndexList, int networkIndexListLen, char **uuids, int uuidsLen, int minCount, int maxCount, char *accountId, char *ownerId, char *reservationId, virtualMachine *ccvm, char *keyName, int vlan, char *userData, char *launchIndex, char *platform, int expiryTime, char *targetNode, ccInstance **outInsts, int *outInstsLen) {
int rc=0, i=0, done=0, runCount=0, resid=0, foundnet=0, error=0, networkIdx=0, nidx=0, thenidx=0;
ccInstance *myInstance=NULL,
*retInsts=NULL;
char instId[16], uuid[48];
ccResource *res=NULL;
char mac[32], privip[32], pubip[32];
ncInstance *outInst=NULL;
virtualMachine ncvm;
netConfig ncnet;
ncStub *ncs=NULL;
char emiURLCached[1024], kernelURLCached[1024], ramdiskURLCached[1024];
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO,"invoked\n");
logprintfl(EUCADEBUG,"params: userId=%s, emiId=%s, kernelId=%s, ramdiskId=%s, emiURL=%s, kernelURL=%s, ramdiskURL=%s, instIdsLen=%d, netNamesLen=%d, macAddrsLen=%d, networkIndexListLen=%d, minCount=%d, maxCount=%d, accountId=%s, ownerId=%s, reservationId=%s, keyName=%s, vlan=%d, userData=%s, launchIndex=%s, platform=%s, targetNode=%s\n", SP(ccMeta ? ccMeta->userId : "UNSET"), SP(amiId), SP(kernelId), SP(ramdiskId), SP(amiURL), SP(kernelURL), SP(ramdiskURL), instIdsLen, netNamesLen, macAddrsLen, networkIndexListLen, minCount, maxCount, SP(accountId), SP(ownerId), SP(reservationId), SP(keyName), vlan, SP(userData), SP(launchIndex), SP(platform), SP(targetNode));
if (config->use_proxy) {
char walrusURL[MAX_PATH], *strptr=NULL, newURL[MAX_PATH];
// get walrus IP
done=0;
for (i=0; i<16 && !done; i++) {
if (!strcmp(config->services[i].type, "walrus")) {
snprintf(walrusURL, MAX_PATH, "%s", config->services[i].uris[0]);
done++;
}
}
if (done) {
// cache and reset endpoint
for (i=0; i<ccvm->virtualBootRecordLen; i++) {
newURL[0] = '\0';
if (!strcmp(ccvm->virtualBootRecord[i].typeName, "machine") || !strcmp(ccvm->virtualBootRecord[i].typeName, "kernel") || !strcmp(ccvm->virtualBootRecord[i].typeName, "ramdisk")) {
strptr = strstr(ccvm->virtualBootRecord[i].resourceLocation, "walrus://");
if (strptr) {
strptr += strlen("walrus://");
snprintf(newURL, MAX_PATH, "%s/%s", walrusURL, strptr);
logprintfl(EUCADEBUG, "constructed cacheable URL: %s\n", newURL);
rc = image_cache(ccvm->virtualBootRecord[i].id, newURL);
if (!rc) {
snprintf(ccvm->virtualBootRecord[i].resourceLocation, CHAR_BUFFER_SIZE, "http://%s:8776/%s", config->proxyIp, ccvm->virtualBootRecord[i].id);
} else {
logprintfl(EUCAWARN, "could not cache image %s/%s\n", ccvm->virtualBootRecord[i].id, newURL);
}
}
}
}
}
}
*outInstsLen = 0;
if (!ccvm) {
logprintfl(EUCAERROR,"invalid ccvm\n");
return(-1);
}
if (minCount <= 0 || maxCount <= 0 || instIdsLen < maxCount) {
logprintfl(EUCAERROR,"bad min or max count, or not enough instIds (%d, %d, %d)\n", minCount, maxCount, instIdsLen);
return(-1);
}
// check health of the networkIndexList
if ( (!strcmp(vnetconfig->mode, "SYSTEM") || !strcmp(vnetconfig->mode, "STATIC") || !strcmp(vnetconfig->mode, "STATIC-DYNMAC")) || networkIndexList == NULL) {
// disabled
nidx=-1;
} else {
if ( (networkIndexListLen < minCount) || (networkIndexListLen > maxCount) ) {
logprintfl(EUCAERROR, "network index length (%d) is out of bounds for min/max instances (%d-%d)\n", networkIndexListLen, minCount, maxCount);
return(1);
}
for (i=0; i<networkIndexListLen; i++) {
if ( (networkIndexList[i] < 0) || (networkIndexList[i] > (vnetconfig->numaddrs-1)) ) {
logprintfl(EUCAERROR, "network index (%d) out of bounds (0-%d)\n", networkIndexList[i], vnetconfig->numaddrs-1);
return(1);
}
}
// all checked out
nidx=0;
}
retInsts = malloc(sizeof(ccInstance) * maxCount);
if (!retInsts) {
logprintfl(EUCAFATAL, "out of memory!\n");
unlock_exit(1);
}
runCount=0;
// get updated resource information
done=0;
for (i=0; i<maxCount && !done; i++) {
snprintf(instId, 16, "%s", instIds[i]);
if (uuidsLen > i) {
snprintf(uuid, 48, "%s", uuids[i]);
} else {
snprintf(uuid, 48, "UNSET");
}
logprintfl(EUCADEBUG,"running instance %s\n", instId);
// generate new mac
bzero(mac, 32);
bzero(pubip, 32);
bzero(privip, 32);
strncpy(pubip, "0.0.0.0", 32);
strncpy(privip, "0.0.0.0", 32);
sem_mywait(VNET);
if (nidx == -1) {
rc = vnetGenerateNetworkParams(vnetconfig, instId, vlan, -1, mac, pubip, privip);
thenidx = -1;
} else {
rc = vnetGenerateNetworkParams(vnetconfig, instId, vlan, networkIndexList[nidx], mac, pubip, privip);
thenidx=nidx;
nidx++;
}
if (rc) {
foundnet = 0;
} else {
foundnet = 1;
}
sem_mypost(VNET);
if (thenidx != -1) {
logprintfl(EUCADEBUG,"assigning MAC/IP: %s/%s/%s/%d\n", mac, pubip, privip, networkIndexList[thenidx]);
} else {
logprintfl(EUCADEBUG,"assigning MAC/IP: %s/%s/%s/%d\n", mac, pubip, privip, thenidx);
}
if (mac[0] == '\0' || !foundnet) {
logprintfl(EUCAERROR,"could not find/initialize any free network address, failing doRunInstances()\n");
} else {
// "run" the instance
memcpy (&ncvm, ccvm, sizeof(virtualMachine));
ncnet.vlan = vlan;
if (thenidx >= 0) {
ncnet.networkIndex = networkIndexList[thenidx];
} else {
ncnet.networkIndex = -1;
}
snprintf(ncnet.privateMac, 24, "%s", mac);
snprintf(ncnet.privateIp, 24, "%s", privip);
snprintf(ncnet.publicIp, 24, "%s", pubip);
sem_mywait(RESCACHE);
resid = 0;
sem_mywait(CONFIG);
rc = schedule_instance(ccvm, targetNode, &resid);
sem_mypost(CONFIG);
res = &(resourceCache->resources[resid]);
if (rc) {
// could not find resource
logprintfl(EUCAERROR, "scheduler could not find resource to run the instance on\n");
// couldn't run this VM, remove networking information from system
free_instanceNetwork(mac, vlan, 1, 1);
} else {
int pid, status, ret, rbytes;
// try to run the instance on the chosen resource
logprintfl(EUCADEBUG, "scheduler decided to run instance '%s' on resource '%s', running count '%d'\n", instId, res->ncURL, res->running);
outInst=NULL;
pid = fork();
if (pid == 0) {
time_t startRun, ncRunTimeout;
sem_mywait(RESCACHE);
if (res->running > 0) {
res->running++;
}
sem_mypost(RESCACHE);
ret=0;
logprintfl(EUCAINFO,"sending run instance: node=%s instanceId=%s emiId=%s mac=%s privIp=%s pubIp=%s vlan=%d networkIdx=%d key=%.32s... mem=%d disk=%d cores=%d\n", res->ncURL, instId, SP(amiId), ncnet.privateMac, ncnet.privateIp, ncnet.publicIp, ncnet.vlan, ncnet.networkIndex, SP(keyName), ncvm.mem, ncvm.disk, ncvm.cores);
rc = 1;
startRun = time(NULL);
if (config->schedPolicy == SCHEDPOWERSAVE) {
ncRunTimeout = config->wakeThresh;
} else {
ncRunTimeout = 15;
}
while(rc && ((time(NULL) - startRun) < ncRunTimeout)) {
int clientpid;
// if we're running windows, and are an NC, create the pw/floppy locally
if (strstr(platform, "windows") && !strstr(res->ncURL, "EucalyptusNC")) {
//if (strstr(platform, "windows")) {
char cdir[MAX_PATH];
snprintf(cdir, MAX_PATH, EUCALYPTUS_STATE_DIR "/windows/", config->eucahome);
if (check_directory(cdir)) mkdir(cdir, 0700);
snprintf(cdir, MAX_PATH, EUCALYPTUS_STATE_DIR "/windows/%s/", config->eucahome, instId);
if (check_directory(cdir)) mkdir(cdir, 0700);
if (check_directory(cdir)) {
logprintfl(EUCAERROR, "could not create console/floppy cache directory '%s'\n", cdir);
} else {
// drop encrypted windows password and floppy on filesystem
rc = makeWindowsFloppy(config->eucahome, cdir, keyName, instId);
if (rc) {
logprintfl(EUCAERROR, "could not create console/floppy cache\n");
}
}
}
// call StartNetwork client
rc = ncClientCall(ccMeta, OP_TIMEOUT_PERNODE, res->lockidx, res->ncURL, "ncStartNetwork", uuid, NULL, 0, 0, vlan, NULL);
logprintfl(EUCADEBUG, "sent network start request for network idx '%d' on resource '%s' uuid '%s': result '%s'\n", vlan, res->ncURL, uuid, rc ? "FAIL" : "SUCCESS");
rc = ncClientCall(ccMeta, OP_TIMEOUT_PERNODE, res->lockidx, res->ncURL, "ncRunInstance", uuid, instId, reservationId, &ncvm, amiId, amiURL, kernelId, kernelURL, ramdiskId, ramdiskURL, ownerId, accountId, keyName, &ncnet, userData, launchIndex, platform, expiryTime, netNames, netNamesLen, &outInst);
logprintfl(EUCADEBUG, "sent run request for instance '%s' on resource '%s': result '%s' uuis '%s'\n", instId, res->ncURL, uuid, rc ? "FAIL" : "SUCCESS");
if (rc) {
// make sure we get the latest topology information before trying again
sem_mywait(CONFIG);
memcpy(ccMeta->services, config->services, sizeof(serviceInfoType) * 16);
memcpy(ccMeta->disabledServices, config->disabledServices, sizeof(serviceInfoType) * 16);
memcpy(ccMeta->notreadyServices, config->notreadyServices, sizeof(serviceInfoType) * 16);
sem_mypost(CONFIG);
sleep(1);
}
}
if (!rc) {
ret = 0;
} else {
ret = 1;
}
sem_mywait(RESCACHE);
if (res->running > 0) {
res->running--;
}
sem_mypost(RESCACHE);
exit(ret);
} else {
rc = 0;
logprintfl(EUCADEBUG,"call complete (pid/rc): %d/%d\n", pid, rc);
}
if (rc != 0) {
// problem
logprintfl(EUCAERROR, "tried to run the VM, but runInstance() failed; marking resource '%s' as down\n", res->ncURL);
res->state = RESDOWN;
i--;
// couldn't run this VM, remove networking information from system
free_instanceNetwork(mac, vlan, 1, 1);
} else {
res->availMemory -= ccvm->mem;
res->availDisk -= ccvm->disk;
res->availCores -= ccvm->cores;
logprintfl(EUCADEBUG, "resource information after schedule/run: %d/%d, %d/%d, %d/%d\n", res->availMemory, res->maxMemory, res->availCores, res->maxCores, res->availDisk, res->maxDisk);
myInstance = &(retInsts[runCount]);
bzero(myInstance, sizeof(ccInstance));
allocate_ccInstance(myInstance, instId, amiId, kernelId, ramdiskId, amiURL, kernelURL, ramdiskURL, ownerId, accountId, "Pending", "", time(NULL), reservationId, &ncnet, &ncnet, ccvm, resid, keyName, resourceCache->resources[resid].ncURL, userData, launchIndex, platform, myInstance->bundleTaskStateName, myInstance->groupNames, myInstance->volumes, myInstance->volumesSize);
// start up DHCP
sem_mywait(CONFIG);
config->kick_dhcp = 1;
sem_mypost(CONFIG);
// add the instance to the cache, and continue on
// add_instanceCache(myInstance->instanceId, myInstance);
refresh_instanceCache(myInstance->instanceId, myInstance);
print_ccInstance("", myInstance);
runCount++;
}
}
sem_mypost(RESCACHE);
}
}
*outInstsLen = runCount;
*outInsts = retInsts;
logprintfl(EUCADEBUG,"done.\n");
shawn();
if (error) {
return(1);
}
return(0);
}
int doGetConsoleOutput(ncMetadata *ccMeta, char *instId, char **outConsoleOutput) {
int i, rc, numInsts, start, stop, done, ret, rbytes, timeout=0;
ccInstance *myInstance;
ncStub *ncs;
time_t op_start;
ccResourceCache resourceCacheLocal;
i = numInsts = 0;
op_start = time(NULL);
myInstance = NULL;
*outConsoleOutput = NULL;
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO,"invoked\n");
logprintfl(EUCADEBUG,"params: userId=%s, instId=%s\n", SP(ccMeta->userId), SP(instId));
sem_mywait(RESCACHE);
memcpy(&resourceCacheLocal, resourceCache, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
rc = find_instanceCacheId(instId, &myInstance);
if (!rc) {
// found the instance in the cache
start = myInstance->ncHostIdx;
stop = start+1;
free(myInstance);
} else {
start = 0;
stop = resourceCacheLocal.numResources;
}
done=0;
for (i=start; i<stop && !done; i++) {
if (*outConsoleOutput) {
free(*outConsoleOutput);
*outConsoleOutput = NULL;
}
// if not talking to Eucalyptus NC (but, e.g., a Broker)
if (!strstr(resourceCacheLocal.resources[i].ncURL, "EucalyptusNC")) {
char pwfile[MAX_PATH];
*outConsoleOutput = NULL;
snprintf(pwfile, MAX_PATH, EUCALYPTUS_STATE_DIR "/windows/%s/console.append.log", config->eucahome, instId);
char *rawconsole=NULL;
if (!check_file(pwfile)) { // the console log file should exist for a Windows guest (with encrypted password in it)
rawconsole = file2str(pwfile);
} else { // the console log file will not exist for a Linux guest
rawconsole = strdup ("not implemented");
}
if (rawconsole) {
*outConsoleOutput = base64_enc((unsigned char *)rawconsole, strlen(rawconsole));
free (rawconsole);
}
// set the return code accordingly
if (!*outConsoleOutput) {
rc = 1;
} else {
rc = 0;
}
done++; // quit on the first host, since they are not queried remotely
} else { // otherwise, we *are* talking to a Eucalyptus NC, so make the remote call
timeout = ncGetTimeout(op_start, timeout, (stop - start), i);
rc = ncClientCall(ccMeta, timeout, resourceCacheLocal.resources[i].lockidx, resourceCacheLocal.resources[i].ncURL, "ncGetConsoleOutput", instId, outConsoleOutput);
}
if (rc) {
ret = 1;
} else {
ret = 0;
done++;
}
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(ret);
}
int doRebootInstances(ncMetadata *ccMeta, char **instIds, int instIdsLen) {
int i, j, rc, numInsts, start, stop, done, timeout=0, ret=0;
char *instId;
ccInstance *myInstance;
ncStub *ncs;
time_t op_start;
ccResourceCache resourceCacheLocal;
i = j = numInsts = 0;
instId = NULL;
myInstance = NULL;
op_start = time(NULL);
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO,"invoked\n");
logprintfl(EUCADEBUG,"params: userId=%s, instIdsLen=%d\n", SP(ccMeta->userId), instIdsLen);
sem_mywait(RESCACHE);
memcpy(&resourceCacheLocal, resourceCache, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
for (i=0; i<instIdsLen; i++) {
instId = instIds[i];
rc = find_instanceCacheId(instId, &myInstance);
if (!rc) {
// found the instance in the cache
start = myInstance->ncHostIdx;
stop = start+1;
free(myInstance);
} else {
start = 0;
stop = resourceCacheLocal.numResources;
}
done=0;
for (j=start; j<stop && !done; j++) {
timeout = ncGetTimeout(op_start, OP_TIMEOUT, (stop - start), j);
rc = ncClientCall(ccMeta, timeout, resourceCacheLocal.resources[j].lockidx, resourceCacheLocal.resources[j].ncURL, "ncRebootInstance", instId);
if (rc) {
ret = 1;
} else {
ret = 0;
done++;
}
}
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(0); /// XXX:gholms
}
int doTerminateInstances(ncMetadata *ccMeta, char **instIds, int instIdsLen, int force, int **outStatus) {
int i, j, shutdownState, previousState, rc, start, stop, done=0, timeout, ret=0;
char *instId;
ccInstance *myInstance=NULL;
ncStub *ncs;
ccResourceCache resourceCacheLocal;
i = j = 0;
instId = NULL;
myInstance = NULL;
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
set_dirty_instanceCache();
logprintfl(EUCAINFO,"invoked\n");
logprintfl(EUCADEBUG,"params: userId=%s, instIdsLen=%d, firstInstId=%s, force=%d\n", SP(ccMeta ? ccMeta->userId : "UNSET"), instIdsLen, SP(instIdsLen ? instIds[0] : "UNSET"), force);
sem_mywait(RESCACHE);
memcpy(&resourceCacheLocal, resourceCache, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
for (i=0; i<instIdsLen; i++) {
instId = instIds[i];
rc = find_instanceCacheId(instId, &myInstance);
if (!rc) {
// found the instance in the cache
if (myInstance != NULL && (!strcmp(myInstance->state, "Pending") || !strcmp(myInstance->state, "Extant") || !strcmp(myInstance->state, "Unknown"))) {
start = myInstance->ncHostIdx;
stop = start+1;
} else {
// instance is not in a terminatable state
start = 0;
stop = 0;
(*outStatus)[i] = 0;
}
if (myInstance) free(myInstance);
} else {
// instance is not in cache, try all resources
start = 0;
stop = 0;
(*outStatus)[i] = 0;
}
done=0;
for (j=start; j<stop && !done; j++) {
if (resourceCacheLocal.resources[j].state == RESUP) {
if (!strstr(resourceCacheLocal.resources[j].ncURL, "EucalyptusNC")) {
char cdir[MAX_PATH];
char cfile[MAX_PATH];
snprintf(cdir, MAX_PATH, EUCALYPTUS_STATE_DIR "/windows/%s/", config->eucahome, instId);
if (!check_directory(cdir)) {
snprintf(cfile, MAX_PATH, "%s/floppy", cdir);
if (!check_file(cfile)) unlink(cfile);
snprintf(cfile, MAX_PATH, "%s/console.append.log", cdir);
if (!check_file(cfile)) unlink(cfile);
rmdir(cdir);
}
}
rc = ncClientCall(ccMeta, 0, resourceCacheLocal.resources[j].lockidx, resourceCacheLocal.resources[j].ncURL, "ncTerminateInstance", instId, force, &shutdownState, &previousState);
if (rc) {
(*outStatus)[i] = 1;
logprintfl(EUCAWARN, "failed to terminate '%s': instance may not exist any longer\n", instId);
ret = 1;
} else {
(*outStatus)[i] = 0;
ret = 0;
done++;
}
rc = ncClientCall(ccMeta, 0, resourceCacheStage->resources[j].lockidx, resourceCacheStage->resources[j].ncURL, "ncAssignAddress", instId, "0.0.0.0");
if (rc) {
// problem, but will retry next time
logprintfl(EUCAWARN, "could not send AssignAddress to NC\n");
}
}
}
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(0);
}
int doCreateImage(ncMetadata *ccMeta, char *instanceId, char *volumeId, char *remoteDev) {
int i, rc, start = 0, stop = 0, ret=0, done=0, timeout;
ccInstance *myInstance;
ncStub *ncs;
time_t op_start;
ccResourceCache resourceCacheLocal;
i = 0;
myInstance = NULL;
op_start = time(NULL);
rc = initialize(ccMeta);
if (rc || ccIsEnabled()) {
return(1);
}
logprintfl(EUCAINFO, "invoked\n");
logprintfl(EUCADEBUG, "params: userId=%s, volumeId=%s, instanceId=%s, remoteDev=%s\n", SP(ccMeta ? ccMeta->userId : "UNSET"), SP(volumeId), SP(instanceId), SP(remoteDev));
if (!volumeId || !instanceId || !remoteDev) {
logprintfl(EUCAERROR, "bad input params\n");
return(1);
}
sem_mywait(RESCACHE);
memcpy(&resourceCacheLocal, resourceCache, sizeof(ccResourceCache));
sem_mypost(RESCACHE);
rc = find_instanceCacheId(instanceId, &myInstance);
if (!rc) {
// found the instance in the cache
if (myInstance) {
start = myInstance->ncHostIdx;
stop = start+1;
free(myInstance);
}
} else {
start = 0;
stop = resourceCacheLocal.numResources;
}
done=0;
for (i=start; i<stop && !done; i++) {
timeout = ncGetTimeout(op_start, OP_TIMEOUT, stop-start, i);
// rc = ncClientCall(ccMeta, timeout, NCCALL, resourceCacheLocal.resources[i].ncURL, "ncCreateImage", instanceId, volumeId, remoteDev);
rc = ncClientCall(ccMeta, timeout, resourceCacheLocal.resources[i].lockidx, resourceCacheLocal.resources[i].ncURL, "ncCreateImage", instanceId, volumeId, remoteDev);
if (rc) {
ret = 1;
} else {
ret = 0;
done++;
}
}
logprintfl(EUCADEBUG,"done.\n");
shawn();
return(ret);
}
int doDescribeSensors(ncMetadata *meta, int historySize, long long collectionIntervalTimeMs, char **instIds, int instIdsLen, char **sensorIds, int sensorIdsLen, sensorResource ***outResources, int *outResourcesLen)
{
logprintfl(EUCAINFO, "invoked historySize=%d collectionIntervalTimeMs=%lld\n", historySize, collectionIntervalTimeMs);
int err = sensor_config (historySize, collectionIntervalTimeMs); // update the config parameters if they are different
if (err != 0)
logprintfl (EUCAERROR, "failed to update sensor configuration (err=%d)\n", err);
int num_resources = sensor_get_num_resources();
if (num_resources < 0) {
logprintfl (EUCAERROR, "failed to determine number of available sensors\n");
return 1;
}
* outResources = NULL;
* outResourcesLen = 0;
if (num_resources > 0) {
* outResources = malloc (num_resources * sizeof (sensorResource *));
if ((*outResources) == NULL) {
return OUT_OF_MEMORY;
}
for (int i = 0; i < num_resources; i++) {
(* outResources) [i] = calloc (1, sizeof (sensorResource));
if (((* outResources) [i]) == NULL) {
return OUT_OF_MEMORY;
}
}
// if number of resources has changed since the call to sensor_get_num_resources(),
// then either we won't report on everything (ok, since we'll get it next time)
// or we'll have fewer records in outResrouces[] (ok, since empty ones will be ignored)
sensor_get_instance_data (NULL, NULL, 0, * outResources, num_resources);
* outResourcesLen = num_resources;
}
return 0;
}
int setup_shared_buffer(void **buf, char *bufname, size_t bytes, sem_t **lock, char *lockname, int mode) {
int shd, rc, ret;
// create a lock and grab it
*lock = sem_open(lockname, O_CREAT, 0644, 1);
sem_wait(*lock);
ret=0;
if (mode == SHARED_MEM) {
// set up shared memory segment for config
shd = shm_open(bufname, O_CREAT | O_RDWR | O_EXCL, 0644);
if (shd >= 0) {
// if this is the first process to create the config, init to 0
rc = ftruncate(shd, bytes);
} else {
shd = shm_open(bufname, O_CREAT | O_RDWR, 0644);
}
if (shd < 0) {
fprintf(stderr, "cannot initialize shared memory segment\n");
sem_post(*lock);
sem_close(*lock);
return(1);
}
*buf = mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_SHARED, shd, 0);
} else if (mode == SHARED_FILE) {
char *tmpstr, path[MAX_PATH];
struct stat mystat;
int fd;
tmpstr = getenv(EUCALYPTUS_ENV_VAR_NAME);
if (!tmpstr) {
snprintf(path, MAX_PATH, EUCALYPTUS_STATE_DIR "/CC/%s", "", bufname);
} else {
snprintf(path, MAX_PATH, EUCALYPTUS_STATE_DIR "/CC/%s", tmpstr, bufname);
}
fd = open(path, O_RDWR | O_CREAT, 0600);
if (fd<0) {
fprintf(stderr, "ERROR: cannot open/create '%s' to set up mmapped buffer\n", path);
ret = 1;
} else {
mystat.st_size = 0;
rc = fstat(fd, &mystat);
// this is the check to make sure we're dealing with a valid prior config
if (mystat.st_size != bytes) {
rc = ftruncate(fd, bytes);
}
*buf = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (*buf == NULL) {
fprintf(stderr, "ERROR: cannot mmap fd\n");
ret = 1;
}
close(fd);
}
}
sem_post(*lock);
return(ret);
}
int initialize(ncMetadata *ccMeta) {
int rc, ret;
ret=0;
rc = init_thread();
if (rc) {
ret=1;
logprintfl(EUCAERROR, "cannot initialize thread\n");
}
rc = init_log();
if (rc) {
ret = 1;
logprintfl(EUCAERROR, "cannot initialize local state\n");
}
rc = init_eucafaults ("cc"); // Returns # of faults loaded into registry.
if (!rc) {
logprintfl(EUCAERROR, "cannot initialize eucafault registry at startup--will retry initialization upon detection of any faults.\n");
}
rc = init_config();
if (rc) {
ret=1;
logprintfl(EUCAERROR, "cannot initialize from configuration file\n");
}
if (config->use_tunnels) {
rc = vnetInitTunnels(vnetconfig);
if (rc) {
logprintfl(EUCAERROR, "cannot initialize tunnels\n");
}
}
rc = init_pthreads();
if (rc) {
logprintfl(EUCAERROR, "cannot initialize background threads\n");
ret = 1;
}
if (ccMeta != NULL) {
logprintfl(EUCADEBUG, "ccMeta: userId=%s correlationId=%s\n", ccMeta->userId, ccMeta->correlationId);
}
if (!ret) {
// store information from CLC that needs to be kept up-to-date in the CC
if (ccMeta != NULL) {
int i;
sem_mywait(CONFIG);
memcpy(config->services, ccMeta->services, sizeof(serviceInfoType) * 16);
memcpy(config->disabledServices, ccMeta->disabledServices, sizeof(serviceInfoType) * 16);
memcpy(config->notreadyServices, ccMeta->notreadyServices, sizeof(serviceInfoType) * 16);
for (i=0; i<16; i++) {
int j;
if (strlen(config->services[i].type)) {
// search for this CCs serviceInfoType
/* if (!strcmp(config->services[i].type, "cluster")) {
char uri[MAX_PATH], uriType[32], host[MAX_PATH], path[MAX_PATH];
int port, done;
snprintf(uri, MAX_PATH, "%s", config->services[i].uris[0]);
rc = tokenize_uri(uri, uriType, host, &port, path);
if (strlen(host)) {
done=0;
for (j=0; j<32 && !done; j++) {
uint32_t hostip;
hostip = dot2hex(host);
if (hostip == vnetconfig->localIps[j]) {
// found a match, update local serviceInfoType
memcpy(&(config->ccStatus.serviceId), &(config->services[i]), sizeof(serviceInfoType));
done++;
}
}
}
} else */
if (!strcmp(config->services[i].type, "eucalyptus")) {
char uri[MAX_PATH], uriType[32], host[MAX_PATH], path[MAX_PATH];
int port, done;
// this is the cloud controller serviceInfo
snprintf(uri, MAX_PATH, "%s", config->services[i].uris[0]);
rc = tokenize_uri(uri, uriType, host, &port, path);
if (strlen(host)) {
config->cloudIp = dot2hex(host);
}
}
}
}
sem_mypost(CONFIG);
}
sem_mywait(INIT);
if (!init) {
// first time operations with everything initialized
sem_mywait(VNET);
vnetconfig->cloudIp = 0;
sem_mypost(VNET);
sem_mywait(CONFIG);
config->cloudIp = 0;
sem_mypost(CONFIG);
}
// initialization went well, this thread is now initialized
init=1;
sem_mypost(INIT);
}
return(ret);
}
int ccIsEnabled() {
// initialized, but ccState is disabled (refuse to service operations)
if (!config || config->ccState != ENABLED) {
return(1);
}
return(0);
}
int ccIsDisabled() {
// initialized, but ccState is disabled (refuse to service operations)
if (!config || config->ccState != DISABLED) {
return(1);
}
return(0);
}
int ccChangeState(int newstate) {
if (config) {
if (config->ccState == SHUTDOWNCC) {
// CC is to be shut down, there is no transition out of this state
return(0);
}
char localState[32];
config->ccLastState = config->ccState;
config->ccState = newstate;
ccGetStateString(localState, 32);
snprintf(config->ccStatus.localState, 32, "%s", localState);
return(0);
}
return(1);
}
int ccGetStateString(char *statestr, int n) {
if (config->ccState == ENABLED) {
snprintf(statestr, n, "ENABLED");
} else if (config->ccState == DISABLED) {
snprintf(statestr, n, "DISABLED");
} else if (config->ccState == STOPPED) {
snprintf(statestr, n, "STOPPED");
} else if (config->ccState == LOADED) {
snprintf(statestr, n, "LOADED");
} else if (config->ccState == INITIALIZED) {
snprintf(statestr, n, "INITIALIZED");
} else if (config->ccState == PRIMORDIAL) {
snprintf(statestr, n, "PRIMORDIAL");
} else if (config->ccState == NOTREADY || config->ccState == SHUTDOWNCC) {
snprintf(statestr, n, "NOTREADY");
}
return(0);
}
int ccCheckState(int clcTimer) {
char localDetails[1024];
int ret=0;
char cmd[MAX_PATH];
int port, done=0, i, j, rc, local_broker_down, is_ha_cc;
if (!config) {
return(1);
}
// check local configuration
if (config->ccState == SHUTDOWNCC) {
logprintfl(EUCAINFO, "this cluster controller marked as shut down\n");
ret++;
}
// configuration
{
char cmd[MAX_PATH];
snprintf(cmd, MAX_PATH, "%s", config->eucahome);
if (check_directory(cmd)) {
logprintfl(EUCAERROR, "cannot find directory '%s'\n", cmd);
ret++;
}
}
// shellouts
{
snprintf(cmd, MAX_PATH, EUCALYPTUS_ROOTWRAP, config->eucahome);
if (check_file(cmd)) {
logprintfl(EUCAERROR, "cannot find shellout '%s'\n", cmd);
ret++;
}
snprintf(cmd, MAX_PATH, EUCALYPTUS_HELPER_DIR "/dynserv.pl", config->eucahome);
if (check_file(cmd)) {
logprintfl(EUCAERROR, "cannot find shellout '%s'\n", cmd);
ret++;
}
snprintf(cmd, MAX_PATH, "ip addr show");
if (system(cmd)) {
logprintfl(EUCAERROR, "cannot run shellout '%s'\n", cmd);
ret++;
}
}
// filesystem
// network
// arbitrators
if (clcTimer == 1 && strlen(config->arbitrators)) {
char *tok, buf[256], *host;
uint32_t hostint;
int count=0;
int arbitratorFails=0;
snprintf(buf, 255, "%s", config->arbitrators);
tok = strtok(buf, " ");
while(tok && count<3) {
hostint = dot2hex(tok);
host = hex2dot(hostint);
if (host) {
logprintfl(EUCADEBUG, "checking health of arbitrator (%s)\n", tok);
snprintf(cmd, 255, "ping -c 1 %s", host);
rc = system(cmd);
if (rc) {
logprintfl(EUCADEBUG, "cannot ping arbitrator %s (ping rc=%d)\n", host, rc);
arbitratorFails++;
}
free(host);
}
tok = strtok(NULL, " ");
count++;
}
if (arbitratorFails) {
config->arbitratorFails++;
} else {
config->arbitratorFails=0;
}
if (config->arbitratorFails > 10) {
logprintfl(EUCADEBUG, "more than 10 arbitrator ping fails in a row (%d), failing check\n", config->arbitratorFails);
ret++;
}
}
// broker pairing algo
rc = doBrokerPairing();
if (rc) {
ret++;
}
snprintf(localDetails, 1023, "ERRORS=%d", ret);
snprintf(config->ccStatus.details, 1023, "%s", localDetails);
return(ret);
}
int doBrokerPairing() {
int ret, local_broker_down, i, j, is_ha_cc, port;
char buri[MAX_PATH], uriType[32], bhost[MAX_PATH], path[MAX_PATH], curi[MAX_PATH], chost[MAX_PATH];
ret = 0;
local_broker_down = 0;
is_ha_cc = 0;
snprintf(curi, MAX_PATH, "%s", config->ccStatus.serviceId.uris[0]);
bzero(chost, sizeof(char) * MAX_PATH);
tokenize_uri(curi, uriType, chost, &port, path);
//enabled
for (i=0; i<16; i++) {
if (!strcmp(config->ccStatus.serviceId.name, "self")) {
// logprintfl(EUCADEBUG, "local CC service info not yet initialized\n");
} else if (!memcmp(&(config->ccStatus.serviceId), &(config->services[i]), sizeof(serviceInfoType))) {
// logprintfl(EUCADEBUG, "found local CC information in services()\n");
} else if (!strcmp(config->services[i].type, "cluster") && !strcmp(config->services[i].partition, config->ccStatus.serviceId.partition)) {
// service is not 'me', but is a 'cluster' and in has the same 'partition', must be in HA mode
// logprintfl(EUCADEBUG, "CC is in HA mode\n");
is_ha_cc = 1;
}
}
//disabled
for (i=0; i<16; i++) {
if (!strcmp(config->ccStatus.serviceId.name, "self")) {
// logprintfl(EUCADEBUG, "local CC service info not yet initialized\n");
} else if (!memcmp(&(config->ccStatus.serviceId), &(config->disabledServices[i]), sizeof(serviceInfoType))) {
// logprintfl(EUCADEBUG, "found local CC information in disabled services()\n");
} else if (!strcmp(config->disabledServices[i].type, "cluster") && !strcmp(config->disabledServices[i].partition, config->ccStatus.serviceId.partition)) {
// service is not 'me', but is a 'cluster' and in has the same 'partition', must be in HA mode
// logprintfl(EUCADEBUG, "CC is in HA mode\n");
is_ha_cc = 1;
}
}
//notready
for (i=0; i<16; i++) {
int j;
//test
if (!strcmp(config->ccStatus.serviceId.name, "self")) {
// logprintfl(EUCADEBUG, "local CC service info not yet initialized\n");
} else if (!memcmp(&(config->ccStatus.serviceId), &(config->notreadyServices[i]), sizeof(serviceInfoType))) {
// logprintfl(EUCADEBUG, "found local CC information in notreadyServices()\n");
} else if (!strcmp(config->notreadyServices[i].type, "cluster") && !strcmp(config->notreadyServices[i].partition, config->ccStatus.serviceId.partition)) {
// service is not 'me', but is a 'cluster' and in has the same 'partition', must be in HA mode
// logprintfl(EUCADEBUG, "CC is in HA mode\n");
is_ha_cc = 1;
}
if (strlen(config->notreadyServices[i].type)) {
if (!strcmp(config->notreadyServices[i].type, "vmwarebroker")) {
for (j=0; j<8; j++) {
if (strlen(config->notreadyServices[i].uris[j])) {
logprintfl(EUCADEBUG, "found broker - %s\n", config->notreadyServices[i].uris[j]);
snprintf(buri, MAX_PATH, "%s", config->notreadyServices[i].uris[j]);
bzero(bhost, sizeof(char) * MAX_PATH);
tokenize_uri(buri, uriType, bhost, &port, path);
logprintfl(EUCADEBUG, "comparing found not ready broker host (%s) with local CC host (%s)\n", bhost, chost);
if (!strcmp(chost, bhost)) {
logprintfl(EUCAWARN, "detected local broker (%s) matching local CC (%s) in NOTREADY state\n", bhost, chost);
// ret++;
local_broker_down = 1;
}
}
}
}
}
}
if (local_broker_down && is_ha_cc) {
logprintfl(EUCADEBUG, "detected CC in HA mode, and local broker is not ENABLED\n", local_broker_down, is_ha_cc);
ret++;
}
return(ret);
}
/*
The CC will start a background thread to poll its collection of
nodes. This thread populates an in-memory cache of instance and
resource information that can be accessed via the regular
describeInstances and describeResources calls to the CC. The
purpose of this separation is to allow for a more scalable
framework where describe operations do not block on access to node
controllers.
*/
void *monitor_thread(void *in) {
int rc, ncTimer, clcTimer, ncRefresh = 0, clcRefresh = 0;
ncMetadata ccMeta;
char pidfile[MAX_PATH], *pidstr=NULL;
bzero(&ccMeta, sizeof(ncMetadata));
ccMeta.correlationId = strdup("monitor");
ccMeta.userId = strdup("eucalyptus");
if (!ccMeta.correlationId || !ccMeta.userId) {
logprintfl(EUCAFATAL, "out of memory!\n");
unlock_exit(1);
}
// set up default signal handler for this child process (for SIGTERM)
struct sigaction newsigact;
newsigact.sa_handler = SIG_DFL;
newsigact.sa_flags = 0;
sigemptyset(&newsigact.sa_mask);
sigprocmask(SIG_SETMASK, &newsigact.sa_mask, NULL);
sigaction(SIGTERM, &newsigact, NULL);
ncTimer = config->ncPollingFrequency+1;
clcTimer = config->clcPollingFrequency+1;
while(1) {
logprintfl(EUCADEBUG, "running\n");
if (config->kick_enabled) {
ccChangeState(ENABLED);
config->kick_enabled = 0;
}
rc = update_config();
if (rc) {
logprintfl(EUCAWARN, "bad return from update_config(), check your config file\n");
}
if (config->ccState == ENABLED) {
// NC Polling operations
if (ncTimer >= config->ncPollingFrequency) {
ncTimer=0;
ncRefresh=1;
}
ncTimer++;
// CLC Polling operations
if (clcTimer >= config->clcPollingFrequency) {
clcTimer=0;
clcRefresh=1;
}
clcTimer++;
if (ncRefresh) {
rc = refresh_resources(&ccMeta, 60, 1);
if (rc) {
logprintfl(EUCAWARN, "call to refresh_resources() failed in monitor thread\n");
}
rc = refresh_sensors(&ccMeta, 60, 1); // TODO3.2: change this to use sensorTimer instead of ncTimer
if (rc) {
logprintfl(EUCAWARN, "call to refresh_sensors() failed in monitor thread\n");
}
rc = refresh_instances(&ccMeta, 60, 1);
if (rc) {
logprintfl(EUCAWARN, "call to refresh_instances() failed in monitor thread\n");
}
}
if (ncRefresh) {
if (is_clean_instanceCache()) {
// Network state operations
// sem_mywait(RESCACHE);
logprintfl(EUCADEBUG, "syncing network state\n");
rc = syncNetworkState();
if (rc) {
logprintfl(EUCADEBUG, "syncNetworkState() triggering network restore\n");
config->kick_network = 1;
}
// sem_mypost(RESCACHE);
if (config->kick_network) {
logprintfl(EUCADEBUG, "restoring network state\n");
rc = restoreNetworkState();
if (rc) {
// failed to restore network state, continue
logprintfl(EUCAWARN, "restoreNetworkState returned false (may be already restored)\n");
} else {
sem_mywait(CONFIG);
config->kick_network = 0;
sem_mypost(CONFIG);
}
}
} else {
logprintfl(EUCADEBUG, "instanceCache is dirty, skipping network update\n");
}
}
if (clcRefresh) {
logprintfl(EUCADEBUG, "syncing CLC network rules ground truth with local state\n");
rc = reconfigureNetworkFromCLC();
if (rc) {
logprintfl(EUCAWARN, "cannot get network ground truth from CLC\n");
}
}
if (ncRefresh) {
logprintfl(EUCADEBUG, "maintaining network state\n");
rc = maintainNetworkState();
if (rc) {
logprintfl(EUCAERROR, "network state maintainance failed\n");
}
}
if (config->use_proxy) {
rc = image_cache_invalidate();
if (rc) {
logprintfl(EUCAERROR, "cannot invalidate image cache\n");
}
snprintf(pidfile, MAX_PATH, EUCALYPTUS_RUN_DIR "/httpd-dynserv.pid", config->eucahome);
pidstr = file2str(pidfile);
if (pidstr) {
if (check_process(atoi(pidstr), "dynserv-httpd.conf")) {
rc = image_cache_proxykick(resourceCache->resources, &(resourceCache->numResources));
if (rc) {
logprintfl(EUCAERROR, "could not start proxy cache\n");
}
}
free(pidstr);
} else {
rc = image_cache_proxykick(resourceCache->resources, &(resourceCache->numResources));
if (rc) {
logprintfl(EUCAERROR, "could not start proxy cache\n");
}
}
}
config->kick_monitor_running = 1;
} else {
// this CC is not enabled, ensure that local network state is disabled
rc = clean_network_state();
if (rc) {
logprintfl(EUCAERROR, "could not cleanup network state\n");
}
}
// do state checks under CONFIG lock
sem_mywait(CONFIG);
if (ccCheckState(clcTimer)) {
logprintfl(EUCAERROR, "ccCheckState() returned failures\n");
config->kick_enabled = 0;
ccChangeState(NOTREADY);
} else if (config->ccState == NOTREADY) {
ccChangeState(DISABLED);
}
sem_mypost(CONFIG);
shawn();
logprintfl(EUCADEBUG, "localState=%s - done.\n", config->ccStatus.localState);
//sleep(config->ncPollingFrequency);
ncRefresh = clcRefresh = 0;
sleep(1);
}
return(NULL);
}
int init_pthreads() {
// start any background threads
if (!config_init) {
return(1);
}
sem_mywait(CONFIG);
if (sensor_initd==0) {
sem * s = sem_alloc_posix (locks[SENSORCACHE]);
if (config->threads[SENSOR] == 0 || check_process(config->threads[SENSOR], NULL)) {
int pid;
pid = fork();
if (!pid) {
// set up default signal handler for this child process (for SIGTERM)
struct sigaction newsigact = { { NULL } };
newsigact.sa_handler = SIG_DFL;
newsigact.sa_flags = 0;
sigemptyset(&newsigact.sa_mask);
sigprocmask(SIG_SETMASK, &newsigact.sa_mask, NULL);
sigaction(SIGTERM, &newsigact, NULL);
logprintfl (EUCADEBUG, "sensor polling process running\n");
if (sensor_init (s, ccSensorResourceCache, MAX_SENSOR_RESOURCES, TRUE)==ERROR) // this call will not return
logprintfl (EUCAERROR, "failed to invoke the sensor polling process\n");
exit(0);
} else {
config->threads[SENSOR] = pid;
}
}
if (sensor_init (s, ccSensorResourceCache, MAX_SENSOR_RESOURCES, FALSE)==ERROR) { // this call will return
logprintfl (EUCAERROR, "failed to initialize sensor subsystem in this process\n");
} else {
logprintfl (EUCADEBUG, "sensor subsystem initialized in this process\n");
sensor_initd = 1;
}
}
// sensor initialization should preceed monitor thread creation so
// that monitor thread has its sensor subsystem initialized
if (config->threads[MONITOR] == 0 || check_process(config->threads[MONITOR], "httpd-cc.conf")) {
int pid;
pid = fork();
if (!pid) {
// set up default signal handler for this child process (for SIGTERM)
struct sigaction newsigact = { { NULL } };
newsigact.sa_handler = SIG_DFL;
newsigact.sa_flags = 0;
sigemptyset(&newsigact.sa_mask);
sigprocmask(SIG_SETMASK, &newsigact.sa_mask, NULL);
sigaction(SIGTERM, &newsigact, NULL);
config->kick_dhcp = 1;
config->kick_network = 1;
monitor_thread(NULL);
exit(0);
} else {
config->threads[MONITOR] = pid;
}
}
sem_mypost(CONFIG);
return(0);
}
int init_log(void)
{
char logFile[MAX_PATH], configFiles[2][MAX_PATH], home[MAX_PATH];
if (local_init==0) { // called by this process for the first time
// TODO: code below is replicated in init_config(), it would be good to join them
bzero(logFile, MAX_PATH);
bzero(home, MAX_PATH);
bzero(configFiles[0], MAX_PATH);
bzero(configFiles[1], MAX_PATH);
char * tmpstr = getenv(EUCALYPTUS_ENV_VAR_NAME);
if (!tmpstr) {
snprintf(home, MAX_PATH, "/");
} else {
snprintf(home, MAX_PATH, "%s", tmpstr);
}
snprintf(configFiles[1], MAX_PATH, EUCALYPTUS_CONF_LOCATION, home);
snprintf(configFiles[0], MAX_PATH, EUCALYPTUS_CONF_OVERRIDE_LOCATION, home);
snprintf(logFile, MAX_PATH, EUCALYPTUS_LOG_DIR "/cc.log", home);
configInitValues(configKeysRestartCC, configKeysNoRestartCC); // initialize config subsystem
readConfigFile(configFiles, 2);
char * log_prefix;
configReadLogParams (&(config->log_level), &(config->log_roll_number), &(config->log_max_size_bytes), &log_prefix);
if (log_prefix && strlen(log_prefix)>0) {
safe_strncpy (config->log_prefix, log_prefix, sizeof (config->log_prefix));
free (log_prefix);
}
// set the log file path (levels and size limits are set below)
log_file_set(logFile);
local_init=1;
}
// update log params on every request so that the updated values discovered
// by monitoring_thread will get picked up by other processes, too
log_params_set (config->log_level, (int)config->log_roll_number, config->log_max_size_bytes);
log_prefix_set (config->log_prefix);
return 0;
}
int init_thread(void) {
int rc, i;
logprintfl(EUCADEBUG, "init=%d %08X %08X %08X %08X\n", init, config, vnetconfig, instanceCache, resourceCache);
if (thread_init) {
// thread has already been initialized
} else {
// this thread has not been initialized, set up shared memory segments
srand(time(NULL));
bzero(locks, sizeof(sem_t *) * ENDLOCK);
bzero(mylocks, sizeof(int) * ENDLOCK);
locks[INIT] = sem_open("/eucalyptusCCinitLock", O_CREAT, 0644, 1);
sem_mywait(INIT);
for (i=NCCALL0; i<=NCCALL31; i++) {
char lockname[MAX_PATH];
snprintf(lockname, MAX_PATH, "/eucalyptusCCncCallLock%d", i);
locks[i] = sem_open(lockname, O_CREAT, 0644, 1);
}
if (config == NULL) {
rc = setup_shared_buffer((void **)&config, "/eucalyptusCCConfig", sizeof(ccConfig), &(locks[CONFIG]), "/eucalyptusCCConfigLock", SHARED_FILE);
if (rc != 0) {
fprintf(stderr, "Cannot set up shared memory region for ccConfig, exiting...\n");
sem_mypost(INIT);
exit(1);
}
}
if (instanceCache == NULL) {
rc = setup_shared_buffer((void **)&instanceCache, "/eucalyptusCCInstanceCache", sizeof(ccInstanceCache), &(locks[INSTCACHE]), "/eucalyptusCCInstanceCacheLock", SHARED_FILE);
if (rc != 0) {
fprintf(stderr, "Cannot set up shared memory region for ccInstanceCache, exiting...\n");
sem_mypost(INIT);
exit(1);
}
}
if (resourceCache == NULL) {
rc = setup_shared_buffer((void **)&resourceCache, "/eucalyptusCCResourceCache", sizeof(ccResourceCache), &(locks[RESCACHE]), "/eucalyptusCCResourceCacheLock", SHARED_FILE);
if (rc != 0) {
fprintf(stderr, "Cannot set up shared memory region for ccResourceCache, exiting...\n");
sem_mypost(INIT);
exit(1);
}
}
if (resourceCacheStage == NULL) {
rc = setup_shared_buffer((void **)&resourceCacheStage, "/eucalyptusCCResourceCacheStage", sizeof(ccResourceCache), &(locks[RESCACHESTAGE]), "/eucalyptusCCResourceCacheStatgeLock", SHARED_FILE);
if (rc != 0) {
fprintf(stderr, "Cannot set up shared memory region for ccResourceCacheStage, exiting...\n");
sem_mypost(INIT);
exit(1);
}
}
if (ccSensorResourceCache == NULL) {
rc = setup_shared_buffer((void **)&ccSensorResourceCache, "/eucalyptusCCSensorResourceCache", sizeof(sensorResourceCache)+sizeof(sensorResource)*(MAX_SENSOR_RESOURCES-1), &(locks[SENSORCACHE]), "/eucalyptusCCSensorResourceCacheLock", SHARED_FILE);
if (rc != 0) {
fprintf(stderr, "Cannot set up shared memory region for ccSensorResourceCache, exiting...\n");
sem_mypost(INIT);
exit(1);
}
}
if (vnetconfig == NULL) {
rc = setup_shared_buffer((void **)&vnetconfig, "/eucalyptusCCVNETConfig", sizeof(vnetConfig), &(locks[VNET]), "/eucalyptusCCVNETConfigLock", SHARED_FILE);
if (rc != 0) {
fprintf(stderr, "Cannot set up shared memory region for ccVNETConfig, exiting...\n");
sem_mypost(INIT);
exit(1);
}
}
sem_mypost(INIT);
thread_init=1;
}
return(0);
}
int update_config(void) {
char *tmpstr=NULL;
ccResource *res=NULL;
int rc, numHosts, ret=0;
sem_mywait(CONFIG);
rc = isConfigModified (config->configFiles, 2);
if (rc < 0) { // error
sem_mypost(CONFIG);
return(1);
} else if (rc > 0) { // config modification time has changed
rc = readConfigFile(config->configFiles, 2);
if (rc) {
// something has changed that can be read in
logprintfl(EUCAINFO, "ingressing new options.\n");
// read log params from config file and update in-memory configuration
char * log_prefix;
configReadLogParams (&(config->log_level), &(config->log_roll_number), &(config->log_max_size_bytes), &log_prefix);
if (log_prefix && strlen(log_prefix)>0) {
safe_strncpy (config->log_prefix, log_prefix, sizeof (config->log_prefix));
free (log_prefix);
}
// reconfigure the logging subsystem to use the new values, if any
log_params_set (config->log_level, (int)config->log_roll_number, config->log_max_size_bytes);
log_prefix_set (config->log_prefix);
// NODES
logprintfl(EUCAINFO, "refreshing node list.\n");
res = NULL;
rc = refreshNodes(config, &res, &numHosts);
if (rc) {
logprintfl(EUCAERROR, "cannot read list of nodes, check your config file\n");
sem_mywait(RESCACHE);
resourceCache->numResources = 0;
config->schedState = 0;
bzero(resourceCache->resources, sizeof(ccResource) * MAXNODES);
sem_mypost(RESCACHE);
ret = 1;
} else {
sem_mywait(RESCACHE);
if (numHosts > MAXNODES) {
logprintfl(EUCAWARN, "the list of nodes specified exceeds the maximum number of nodes that a single CC can support (%d). Truncating list to %d nodes.\n", MAXNODES, MAXNODES);
numHosts = MAXNODES;
}
resourceCache->numResources = numHosts;
config->schedState = 0;
memcpy(resourceCache->resources, res, sizeof(ccResource) * numHosts);
sem_mypost(RESCACHE);
}
if (res) free(res);
// CC Arbitrators
tmpstr = configFileValue("CC_ARBITRATORS");
if (tmpstr) {
snprintf(config->arbitrators, 255, "%s", tmpstr);
free(tmpstr);
} else {
bzero(config->arbitrators, 256);
}
// polling frequencies
// CLC
tmpstr = configFileValue("CLC_POLLING_FREQUENCY");
if (tmpstr) {
if (atoi(tmpstr) > 0) {
config->clcPollingFrequency = atoi(tmpstr);
} else {
config->clcPollingFrequency = 6;
}
free(tmpstr);
} else {
config->clcPollingFrequency = 6;
}
// NC
tmpstr = configFileValue("NC_POLLING_FREQUENCY");
if (tmpstr) {
if (atoi(tmpstr) > 6) {
config->ncPollingFrequency = atoi(tmpstr);
} else {
config->ncPollingFrequency = 6;
}
free(tmpstr);
} else {
config->ncPollingFrequency = 6;
}
}
}
sem_mypost(CONFIG);
return(ret);
}
int init_config(void) {
ccResource *res=NULL;
char *tmpstr=NULL, *proxyIp=NULL;
int rc, numHosts, use_wssec, use_tunnels, use_proxy, proxy_max_cache_size, schedPolicy, idleThresh, wakeThresh, ret, i;
char configFiles[2][MAX_PATH], netPath[MAX_PATH], eucahome[MAX_PATH], policyFile[MAX_PATH], home[MAX_PATH], proxyPath[MAX_PATH], arbitrators[256];
time_t instanceTimeout, ncPollingFrequency, clcPollingFrequency, ncFanout;
struct stat statbuf;
// read in base config information
tmpstr = getenv(EUCALYPTUS_ENV_VAR_NAME);
if (!tmpstr) {
snprintf(home, MAX_PATH, "/");
} else {
snprintf(home, MAX_PATH, "%s", tmpstr);
}
bzero(configFiles[0], MAX_PATH);
bzero(configFiles[1], MAX_PATH);
bzero(netPath, MAX_PATH);
bzero(policyFile, MAX_PATH);
snprintf(configFiles[1], MAX_PATH, EUCALYPTUS_CONF_LOCATION, home);
snprintf(configFiles[0], MAX_PATH, EUCALYPTUS_CONF_OVERRIDE_LOCATION, home);
snprintf(netPath, MAX_PATH, CC_NET_PATH_DEFAULT, home);
snprintf(policyFile, MAX_PATH, EUCALYPTUS_KEYS_DIR "/nc-client-policy.xml", home);
snprintf(eucahome, MAX_PATH, "%s/", home);
sem_mywait(INIT);
if (config_init && config->initialized) {
// this means that this thread has already been initialized
sem_mypost(INIT);
return(0);
}
if (config->initialized) {
config_init = 1;
sem_mypost(INIT);
return(0);
}
logprintfl(EUCADEBUG, "invoked\n");
logprintfl(EUCADEBUG, "initializing CC configuration\n");
configInitValues(configKeysRestartCC, configKeysNoRestartCC);
readConfigFile(configFiles, 2);
// DHCP configuration section
{
char *daemon=NULL,
*dhcpuser=NULL,
*numaddrs=NULL,
*pubmode=NULL,
*pubmacmap=NULL,
*pubips=NULL,
*pubInterface=NULL,
*privInterface=NULL,
*pubSubnet=NULL,
*pubSubnetMask=NULL,
*pubBroadcastAddress=NULL,
*pubRouter=NULL,
*pubDomainname=NULL,
*pubDNS=NULL,
*localIp=NULL,
*macPrefix=NULL;
uint32_t *ips, *nms;
int initFail=0, len, usednew=0;;
// DHCP Daemon Configuration Params
daemon = configFileValue("VNET_DHCPDAEMON");
if (!daemon) {
logprintfl(EUCAWARN,"no VNET_DHCPDAEMON defined in config, using default\n");
}
dhcpuser = configFileValue("VNET_DHCPUSER");
if (!dhcpuser) {
dhcpuser = strdup("root");
if (!dhcpuser) {
logprintfl(EUCAFATAL,"Out of memory\n");
unlock_exit(1);
}
}
pubmode = configFileValue("VNET_MODE");
if (!pubmode) {
logprintfl(EUCAWARN,"VNET_MODE is not defined, defaulting to 'SYSTEM'\n");
pubmode = strdup("SYSTEM");
if (!pubmode) {
logprintfl(EUCAFATAL,"Out of memory\n");
unlock_exit(1);
}
}
macPrefix = configFileValue("VNET_MACPREFIX");
if (!macPrefix) {
logprintfl(EUCAWARN, "VNET_MACPREFIX is not defined, defaulting to 'd0:0d'\n");
macPrefix = strdup("d0:0d");
if (!macPrefix) {
logprintfl(EUCAFATAL, "Out of memory!\n");
unlock_exit(1);
}
} else {
unsigned int a=0, b=0;
if (sscanf(macPrefix, "%02X:%02X", &a,&b) != 2 || (a > 0xFF || b > 0xFF)) {
logprintfl(EUCAWARN, "VNET_MACPREFIX is not defined, defaulting to 'd0:0d'\n");
if(macPrefix) free(macPrefix);
macPrefix = strdup("d0:0d");
}
}
pubInterface = configFileValue("VNET_PUBINTERFACE");
if (!pubInterface) {
logprintfl(EUCAWARN,"VNET_PUBINTERFACE is not defined, defaulting to 'eth0'\n");
pubInterface = strdup("eth0");
if (!pubInterface) {
logprintfl(EUCAFATAL, "out of memory!\n");
unlock_exit(1);
}
} else {
usednew=1;
}
privInterface = NULL;
privInterface = configFileValue("VNET_PRIVINTERFACE");
if (!privInterface) {
logprintfl(EUCAWARN,"VNET_PRIVINTERFACE is not defined, defaulting to 'eth0'\n");
privInterface = strdup("eth0");
if (!privInterface) {
logprintfl(EUCAFATAL, "out of memory!\n");
unlock_exit(1);
}
usednew = 0;
}
if (!usednew) {
tmpstr = NULL;
tmpstr = configFileValue("VNET_INTERFACE");
if (tmpstr) {
logprintfl(EUCAWARN, "VNET_INTERFACE is deprecated, please use VNET_PUBINTERFACE and VNET_PRIVINTERFACE instead. Will set both to value of VNET_INTERFACE (%s) for now.\n", tmpstr);
if (pubInterface) free(pubInterface);
pubInterface = strdup(tmpstr);
if (!pubInterface) {
logprintfl(EUCAFATAL, "out of memory!\n");
unlock_exit(1);
}
if (privInterface) free(privInterface);
privInterface = strdup(tmpstr);
if (!privInterface) {
logprintfl(EUCAFATAL, "out of memory!\n");
unlock_exit(1);
}
}
if (tmpstr) free(tmpstr);
}
if (pubmode && (!strcmp(pubmode, "STATIC") || !strcmp(pubmode, "STATIC-DYNMAC"))) {
pubSubnet = configFileValue("VNET_SUBNET");
pubSubnetMask = configFileValue("VNET_NETMASK");
pubBroadcastAddress = configFileValue("VNET_BROADCAST");
pubRouter = configFileValue("VNET_ROUTER");
pubDNS = configFileValue("VNET_DNS");
pubDomainname = configFileValue("VNET_DOMAINNAME");
pubmacmap = configFileValue("VNET_MACMAP");
pubips = configFileValue("VNET_PUBLICIPS");
if (!pubSubnet || !pubSubnetMask || !pubBroadcastAddress || !pubRouter || !pubDNS
|| (!strcmp(pubmode, "STATIC") && !pubmacmap) || (!strcmp(pubmode, "STATIC-DYNMAC") && !pubips)) {
logprintfl(EUCAFATAL,"in '%s' network mode, you must specify values for 'VNET_SUBNET, VNET_NETMASK, VNET_BROADCAST, VNET_ROUTER, VNET_DNS and %s'\n",
pubmode, (!strcmp(pubmode, "STATIC")) ? "VNET_MACMAP" : "VNET_PUBLICIPS");
initFail = 1;
}
} else if (pubmode && (!strcmp(pubmode, "MANAGED") || !strcmp(pubmode, "MANAGED-NOVLAN"))) {
numaddrs = configFileValue("VNET_ADDRSPERNET");
pubSubnet = configFileValue("VNET_SUBNET");
pubSubnetMask = configFileValue("VNET_NETMASK");
pubDNS = configFileValue("VNET_DNS");
pubDomainname = configFileValue("VNET_DOMAINNAME");
pubips = configFileValue("VNET_PUBLICIPS");
localIp = configFileValue("VNET_LOCALIP");
if (!localIp) {
logprintfl(EUCAWARN, "VNET_LOCALIP not defined, will attempt to auto-discover (consider setting this explicitly if tunnelling does not function properly.)\n");
}
if (!pubSubnet || !pubSubnetMask || !pubDNS || !numaddrs) {
logprintfl(EUCAFATAL,"in 'MANAGED' or 'MANAGED-NOVLAN' network mode, you must specify values for 'VNET_SUBNET, VNET_NETMASK, VNET_ADDRSPERNET, and VNET_DNS'\n");
initFail = 1;
}
}
if (initFail) {
logprintfl(EUCAFATAL, "bad network parameters, must fix before system will work\n");
if (pubSubnet) free(pubSubnet);
if (pubSubnetMask) free(pubSubnetMask);
if (pubBroadcastAddress) free(pubBroadcastAddress);
if (pubRouter) free(pubRouter);
if (pubDomainname) free(pubDomainname);
if (pubDNS) free(pubDNS);
if (pubmacmap) free(pubmacmap);
if (numaddrs) free(numaddrs);
if (pubips) free(pubips);
if (localIp) free(localIp);
if (pubInterface) free(pubInterface);
if (privInterface) free(privInterface);
if (dhcpuser) free(dhcpuser);
if (daemon) free(daemon);
if (pubmode) free(pubmode);
if (macPrefix) free(macPrefix);
sem_mypost(INIT);
return(1);
}
sem_mywait(VNET);
int ret = vnetInit(vnetconfig, pubmode, eucahome, netPath, CLC, pubInterface, privInterface, numaddrs, pubSubnet, pubSubnetMask, pubBroadcastAddress, pubDNS, pubDomainname, pubRouter, daemon, dhcpuser, NULL, localIp, macPrefix);
if (pubSubnet) free(pubSubnet);
if (pubSubnetMask) free(pubSubnetMask);
if (pubBroadcastAddress) free(pubBroadcastAddress);
if (pubDomainname) free(pubDomainname);
if (pubDNS) free(pubDNS);
if (pubRouter) free(pubRouter);
if (numaddrs) free(numaddrs);
if (pubmode) free(pubmode);
if (dhcpuser) free(dhcpuser);
if (daemon) free(daemon);
if (privInterface) free(privInterface);
if (pubInterface) free(pubInterface);
if (macPrefix) free(macPrefix);
if (localIp) free(localIp);
if(ret > 0) {
sem_mypost(VNET);
sem_mypost(INIT);
return(1);
}
vnetAddDev(vnetconfig, vnetconfig->privInterface);
if (pubmacmap) {
char *mac=NULL, *ip=NULL, *ptra=NULL, *toka=NULL, *ptrb=NULL;
toka = strtok_r(pubmacmap, " ", &ptra);
while(toka) {
mac = ip = NULL;
mac = strtok_r(toka, "=", &ptrb);
ip = strtok_r(NULL, "=", &ptrb);
if (mac && ip) {
vnetAddHost(vnetconfig, mac, ip, 0, -1);
}
toka = strtok_r(NULL, " ", &ptra);
}
vnetKickDHCP(vnetconfig);
free(pubmacmap);
} else if (pubips) {
char *ip, *ptra, *toka;
toka = strtok_r(pubips, " ", &ptra);
while(toka) {
ip = toka;
if (ip) {
rc = vnetAddPublicIP(vnetconfig, ip);
if (rc) {
logprintfl(EUCAERROR, "could not add public IP '%s'\n", ip);
}
}
toka = strtok_r(NULL, " ", &ptra);
}
// detect and populate ips
if (vnetCountLocalIP(vnetconfig) <= 0) {
ips = nms = NULL;
rc = getdevinfo("all", &ips, &nms, &len);
if (!rc) {
for (i=0; i<len; i++) {
char *theip=NULL;
theip = hex2dot(ips[i]);
if (vnetCheckPublicIP(vnetconfig, theip)) {
vnetAddLocalIP(vnetconfig, ips[i]);
}
if (theip) free(theip);
}
}
if (ips) free(ips);
if (nms) free(nms);
}
//free(pubips);
}
if(pubips) free(pubips);
sem_mypost(VNET);
}
tmpstr = configFileValue("SCHEDPOLICY");
if (!tmpstr) {
// error
logprintfl(EUCAWARN,"parsing config file (%s) for SCHEDPOLICY, defaulting to GREEDY\n",