@Override public String getEventDescription() { StringBuilder sb = new StringBuilder(); if (getUserSecurityGroupList() != null) { sb.append("group list(group/account): "); Collection userGroupCollection = getUserSecurityGroupList().values(); Iterator iter = userGroupCollection.iterator(); HashMap userGroup = (HashMap) iter.next(); String group = (String) userGroup.get("group"); String authorizedAccountName = (String) userGroup.get("account"); sb.append(group + "/" + authorizedAccountName); while (iter.hasNext()) { userGroup = (HashMap) iter.next(); group = (String) userGroup.get("group"); authorizedAccountName = (String) userGroup.get("account"); sb.append(", " + group + "/" + authorizedAccountName); } } else if (getCidrList() != null) { sb.append("cidr list: "); sb.append(StringUtils.join(getCidrList(), ", ")); } else { sb.append("<error: no ingress parameters>"); } return "authorizing ingress to group: " + getSecurityGroupId() + " to " + sb.toString(); }
@Override public String getEventDescription() { return "applying instances for load balancer: " + getLoadBalancerId() + " (ids: " + StringUtils.join(getVirtualMachineIds(), ",") + ")"; }
@Override public String getEventDescription() { return "removing instances from load balancer: " + getId() + " (ids: " + StringUtils.join(getVirtualMachineIds(), ",") + ")"; }
private void buildAuditTrail(StringBuffer auditTrailSb, String command, String result) { if (result == null) { return; } auditTrailSb.append(" " + HttpServletResponse.SC_OK + " "); if (command.equals("createSSHKeyPair")) { auditTrailSb.append("This result was not logged because it contains sensitive data."); } else { auditTrailSb.append(StringUtils.cleanString(result)); } }
@Override public void execute() { UserContext.current() .setEventDetails( "Load balancer Id: " + getLoadBalancerId() + " VmIds: " + StringUtils.join(getVirtualMachineIds(), ",")); boolean result = _lbService.assignToLoadBalancer(getLoadBalancerId(), virtualMachineIds); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); } else { throw new ServerApiException( ApiErrorCode.INTERNAL_ERROR, "Failed to assign load balancer rule"); } }
// NOTE: handle() only handles over the wire (OTW) requests from integration.api.port 8096 // If integration api port is not configured, actual OTW requests will be received by ApiServlet @SuppressWarnings({"unchecked", "rawtypes"}) @Override public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { // Create StringBuffer to log information in access log StringBuffer sb = new StringBuffer(); HttpServerConnection connObj = (HttpServerConnection) context.getAttribute("http.connection"); if (connObj instanceof SocketHttpServerConnection) { InetAddress remoteAddr = ((SocketHttpServerConnection) connObj).getRemoteAddress(); sb.append(remoteAddr.toString() + " -- "); } sb.append(StringUtils.cleanString(request.getRequestLine().toString())); try { List<NameValuePair> paramList = null; try { paramList = URLEncodedUtils.parse(new URI(request.getRequestLine().getUri()), "UTF-8"); } catch (URISyntaxException e) { s_logger.error("Error parsing url request", e); } // Use Multimap as the parameter map should be in the form (name=String, value=String[]) // So parameter values are stored in a list for the same name key // APITODO: Use Guava's (import com.google.common.collect.Multimap;) // (Immutable)Multimap<String, String> paramMultiMap = HashMultimap.create(); // Map<String, Collection<String>> parameterMap = paramMultiMap.asMap(); Map parameterMap = new HashMap<String, String[]>(); String responseType = BaseCmd.RESPONSE_TYPE_XML; for (NameValuePair param : paramList) { if (param.getName().equalsIgnoreCase("response")) { responseType = param.getValue(); continue; } parameterMap.put(param.getName(), new String[] {param.getValue()}); } // Get the type of http method being used. parameterMap.put("httpmethod", new String[] {request.getRequestLine().getMethod()}); // Check responseType, if not among valid types, fallback to JSON if (!(responseType.equals(BaseCmd.RESPONSE_TYPE_JSON) || responseType.equals(BaseCmd.RESPONSE_TYPE_XML))) { responseType = BaseCmd.RESPONSE_TYPE_XML; } try { // always trust commands from API port, user context will always be // UID_SYSTEM/ACCOUNT_ID_SYSTEM CallContext.register(_accountMgr.getSystemUser(), _accountMgr.getSystemAccount()); sb.insert( 0, "(userId=" + User.UID_SYSTEM + " accountId=" + Account.ACCOUNT_ID_SYSTEM + " sessionId=" + null + ") "); String responseText = handleRequest(parameterMap, responseType, sb); sb.append(" 200 " + ((responseText == null) ? 0 : responseText.length())); writeResponse(response, responseText, HttpStatus.SC_OK, responseType, null); } catch (ServerApiException se) { String responseText = getSerializedApiError(se, parameterMap, responseType); writeResponse( response, responseText, se.getErrorCode().getHttpCode(), responseType, se.getDescription()); sb.append(" " + se.getErrorCode() + " " + se.getDescription()); } catch (RuntimeException e) { // log runtime exception like NullPointerException to help identify the source easier s_logger.error("Unhandled exception, ", e); throw e; } } finally { s_accessLogger.info(sb.toString()); CallContext.unregister(); } }
@SuppressWarnings("rawtypes") public String handleRequest( Map params, boolean decode, String responseType, StringBuffer auditTrailSb) throws ServerApiException { String response = null; String[] command = null; try { command = (String[]) params.get("command"); if (command == null) { s_logger.error("invalid request, no command sent"); if (s_logger.isTraceEnabled()) { s_logger.trace("dumping request parameters"); for (Object key : params.keySet()) { String keyStr = (String) key; String[] value = (String[]) params.get(key); s_logger.trace( " key: " + keyStr + ", value: " + ((value == null) ? "'null'" : value[0])); } } throw new ServerApiException( ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "Invalid request, no command sent"); } else { Map<String, String> paramMap = new HashMap<String, String>(); Set keys = params.keySet(); Iterator keysIter = keys.iterator(); while (keysIter.hasNext()) { String key = (String) keysIter.next(); if ("command".equalsIgnoreCase(key)) { continue; } String[] value = (String[]) params.get(key); String decodedValue = null; if (decode) { try { decodedValue = URLDecoder.decode(value[0], "UTF-8"); } catch (UnsupportedEncodingException usex) { s_logger.warn(key + " could not be decoded, value = " + value[0]); throw new ServerApiException( ApiErrorCode.PARAM_ERROR, key + " could not be decoded, received value " + value[0]); } catch (IllegalArgumentException iae) { s_logger.warn(key + " could not be decoded, value = " + value[0]); throw new ServerApiException( ApiErrorCode.PARAM_ERROR, key + " could not be decoded, received value " + value[0] + " which contains illegal characters eg.%"); } } else { decodedValue = value[0]; } paramMap.put(key, decodedValue); } Class<?> cmdClass = getCmdClass(command[0]); if (cmdClass != null) { BaseCmd cmdObj = (BaseCmd) cmdClass.newInstance(); cmdObj.setFullUrlParams(paramMap); cmdObj.setResponseType(responseType); // This is where the command is either serialized, or directly dispatched response = queueCommand(cmdObj, paramMap); buildAuditTrail(auditTrailSb, command[0], response); } else { if (!command[0].equalsIgnoreCase("login") && !command[0].equalsIgnoreCase("logout")) { String errorString = "Unknown API command: " + ((command == null) ? "null" : command[0]); s_logger.warn(errorString); auditTrailSb.append(" " + errorString); throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, errorString); } } } } catch (InvalidParameterValueException ex) { s_logger.info(ex.getMessage()); throw new ServerApiException(ApiErrorCode.PARAM_ERROR, ex.getMessage(), ex); } catch (IllegalArgumentException ex) { s_logger.info(ex.getMessage()); throw new ServerApiException(ApiErrorCode.PARAM_ERROR, ex.getMessage(), ex); } catch (PermissionDeniedException ex) { ArrayList<String> idList = ex.getIdProxyList(); if (idList != null) { s_logger.info( "PermissionDenied: " + ex.getMessage() + " on uuids: [" + StringUtils.listToCsvTags(idList) + "]"); } else { s_logger.info("PermissionDenied: " + ex.getMessage()); } throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, ex.getMessage(), ex); } catch (AccountLimitException ex) { s_logger.info(ex.getMessage()); throw new ServerApiException(ApiErrorCode.ACCOUNT_RESOURCE_LIMIT_ERROR, ex.getMessage(), ex); } catch (InsufficientCapacityException ex) { s_logger.info(ex.getMessage()); String errorMsg = ex.getMessage(); if (UserContext.current().getCaller().getType() != Account.ACCOUNT_TYPE_ADMIN) { // hide internal details to non-admin user for security reason errorMsg = BaseCmd.USER_ERROR_MESSAGE; } throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, errorMsg, ex); } catch (ResourceAllocationException ex) { s_logger.info(ex.getMessage()); String errorMsg = ex.getMessage(); if (UserContext.current().getCaller().getType() != Account.ACCOUNT_TYPE_ADMIN) { // hide internal details to non-admin user for security reason errorMsg = BaseCmd.USER_ERROR_MESSAGE; } throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, errorMsg, ex); } catch (ResourceUnavailableException ex) { s_logger.info(ex.getMessage()); String errorMsg = ex.getMessage(); if (UserContext.current().getCaller().getType() != Account.ACCOUNT_TYPE_ADMIN) { // hide internal details to non-admin user for security reason errorMsg = BaseCmd.USER_ERROR_MESSAGE; } throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, errorMsg, ex); } catch (AsyncCommandQueued ex) { s_logger.error( "unhandled exception executing api command: " + ((command == null) ? "null" : command[0]), ex); throw new ServerApiException( ApiErrorCode.INTERNAL_ERROR, "Internal server error, unable to execute request."); } catch (ServerApiException ex) { s_logger.info(ex.getDescription()); throw ex; } catch (Exception ex) { s_logger.error( "unhandled exception executing api command: " + ((command == null) ? "null" : command[0]), ex); String errorMsg = ex.getMessage(); if (UserContext.current().getCaller().getType() != Account.ACCOUNT_TYPE_ADMIN) { // hide internal details to non-admin user for security reason errorMsg = BaseCmd.USER_ERROR_MESSAGE; } throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, errorMsg, ex); } return response; }
@Override public boolean addUserData(NicProfile nic, VirtualMachineProfile profile) { UserVmVO vm = _vmDao.findById(profile.getVirtualMachine().getId()); _vmDao.loadDetails(vm); String serviceOffering = _serviceOfferingDao .findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()) .getDisplayText(); String zoneName = _dcDao.findById(vm.getDataCenterId()).getName(); NicVO nvo = _nicDao.findById(nic.getId()); VmDataCommand cmd = new VmDataCommand( nvo.getIPv4Address(), vm.getInstanceName(), _ntwkModel.getExecuteInSeqNtwkElmtCmd()); // if you add new metadata files, also edit // systemvm/patches/debian/config/var/www/html/latest/.htaccess cmd.addVmData("userdata", "user-data", vm.getUserData()); cmd.addVmData("metadata", "service-offering", StringUtils.unicodeEscape(serviceOffering)); cmd.addVmData("metadata", "availability-zone", StringUtils.unicodeEscape(zoneName)); cmd.addVmData("metadata", "local-ipv4", nic.getIPv4Address()); cmd.addVmData("metadata", "local-hostname", StringUtils.unicodeEscape(vm.getInstanceName())); cmd.addVmData("metadata", "public-ipv4", nic.getIPv4Address()); cmd.addVmData("metadata", "public-hostname", StringUtils.unicodeEscape(vm.getInstanceName())); cmd.addVmData("metadata", "instance-id", String.valueOf(vm.getId())); cmd.addVmData("metadata", "vm-id", String.valueOf(vm.getInstanceName())); cmd.addVmData("metadata", "public-keys", null); String cloudIdentifier = _configDao.getValue("cloud.identifier"); if (cloudIdentifier == null) { cloudIdentifier = ""; } else { cloudIdentifier = "CloudStack-{" + cloudIdentifier + "}"; } cmd.addVmData("metadata", "cloud-identifier", cloudIdentifier); List<PhysicalNetworkVO> phys = _phynwDao.listByZone(vm.getDataCenterId()); if (phys.isEmpty()) { throw new CloudRuntimeException( String.format("Cannot find physical network in zone %s", vm.getDataCenterId())); } if (phys.size() > 1) { throw new CloudRuntimeException( String.format( "Baremetal only supports one physical network in zone, but zone %s has %s physical networks", vm.getDataCenterId(), phys.size())); } PhysicalNetworkVO phy = phys.get(0); QueryBuilder<BaremetalPxeVO> sc = QueryBuilder.create(BaremetalPxeVO.class); // TODO: handle both kickstart and PING // sc.addAnd(sc.getEntity().getPodId(), Op.EQ, vm.getPodIdToDeployIn()); sc.and(sc.entity().getPhysicalNetworkId(), Op.EQ, phy.getId()); BaremetalPxeVO pxeVo = sc.find(); if (pxeVo == null) { throw new CloudRuntimeException( "No PXE server found in pod: " + vm.getPodIdToDeployIn() + ", you need to add it before starting VM"); } try { Answer ans = _agentMgr.send(pxeVo.getHostId(), cmd); if (!ans.getResult()) { s_logger.debug( String.format( "Add userdata to vm:%s failed because %s", vm.getInstanceName(), ans.getDetails())); return false; } else { return true; } } catch (Exception e) { s_logger.debug(String.format("Add userdata to vm:%s failed", vm.getInstanceName()), e); return false; } }