public LocalManagementContext( Builder builder, Map<String, Object> brooklynAdditionalProperties, DataGridFactory datagridFactory) { super(builder.build(), datagridFactory); // TODO in a persisted world the planeId may be injected this.managementPlaneId = Strings.makeRandomId(8); this.managementNodeId = Strings.makeRandomId(8); checkNotNull(configMap, "brooklynProperties"); this.builder = builder; this.brooklynAdditionalProperties = brooklynAdditionalProperties; if (brooklynAdditionalProperties != null) configMap.addFromMap(brooklynAdditionalProperties); this.locationManager = new LocalLocationManager(this); this.accessManager = new LocalAccessManager(); this.usageManager = new LocalUsageManager(this); if (configMap.getConfig(OsgiManager.USE_OSGI)) { this.osgiManager = new OsgiManager(); osgiManager.start(); } INSTANCES.add(this); log.debug("Created management context " + this); }
public String configFile() { // Check template URL exists String templateUrl = driver.getEntity().getConfig(NginxController.SERVER_CONF_TEMPLATE_URL); ResourceUtils.create(this).checkUrlExists(templateUrl); // Check SSL configuration ProxySslConfig ssl = driver.getEntity().getConfig(NginxController.SSL_CONFIG); if (ssl != null && Strings.isEmpty(ssl.getCertificateDestination()) && Strings.isEmpty(ssl.getCertificateSourceUrl())) { throw new IllegalStateException( "ProxySslConfig can't have a null certificateDestination and null certificateSourceUrl. One or both need to be set"); } // For mapping by URL Iterable<UrlMapping> mappings = ((NginxController) driver.getEntity()).getUrlMappings(); Multimap<String, UrlMapping> mappingsByDomain = LinkedHashMultimap.create(); for (UrlMapping mapping : mappings) { Collection<String> addrs = mapping.getAttribute(UrlMapping.TARGET_ADDRESSES); if (addrs != null && addrs.size() > 0) { mappingsByDomain.put(mapping.getDomain(), mapping); } } Map<String, Object> substitutions = MutableMap.<String, Object>builder() .putIfNotNull("ssl", ssl) .put("urlMappings", mappings) .put("domainMappings", mappingsByDomain) .build(); // Get template contents and process String contents = ResourceUtils.create(driver.getEntity()).getResourceAsString(templateUrl); return TemplateProcessor.processTemplateContents(contents, driver, substitutions); }
/** * attempts to resolve hostnameTarget from origin * * @return null if it definitively can't be resolved, best-effort IP address if possible, or blank * if we could not run ssh or make sense of the output */ public static String getResolvedAddress( Entity entity, SshMachineLocation origin, String hostnameTarget) { ProcessTaskWrapper<Integer> task = SshTasks.newSshExecTaskFactory(origin, "ping -c 1 -t 1 " + hostnameTarget) .summary("checking resolution of " + hostnameTarget) .allowingNonZeroExitCode() .newTask(); DynamicTasks.queueIfPossible(task).orSubmitAndBlock(entity).asTask().blockUntilEnded(); if (task.asTask().isError()) { log.warn( "ping could not be run, at " + entity + " / " + origin + ": " + Tasks.getError(task.asTask())); return ""; } if (task.getExitCode() == null || task.getExitCode() != 0) { if (task.getExitCode() != null && task.getExitCode() < 10) { // small number means ping failed to resolve or ping the hostname log.debug( "not able to resolve " + hostnameTarget + " from " + origin + " for " + entity + " because exit code was " + task.getExitCode()); return null; } // large number means ping probably did not run log.warn( "ping not run as expected, at " + entity + " / " + origin + " (code " + task.getExitCode() + "):\n" + task.getStdout().trim() + " --- " + task.getStderr().trim()); return ""; } String out = task.getStdout(); try { String line1 = Strings.getFirstLine(out); String ip = Strings.getFragmentBetween(line1, "(", ")"); if (Strings.isNonBlank(ip)) return ip; } catch (Exception e) { Exceptions.propagateIfFatal(e); /* ignore non-parseable output */ } if (out.contains("127.0.0.1")) return "127.0.0.1"; return ""; }
/** * true if the URL points to content which must be resolved on the server-side (i.e. classpath) * and which is safe to do so (currently just images, though in future perhaps also javascript and * html plugins) * * <p>note we do not let caller access classpath through this mechanism, just those which are * supplied by the platform administrator e.g. as an icon url */ public boolean isUrlServerSideAndSafe(String url) { if (Strings.isEmpty(url)) return false; String ext = Files.getFileExtension(url); if (Strings.isEmpty(ext)) return false; MediaType mime = WebResourceUtils.getImageMediaTypeFromExtension(ext); if (mime == null) return false; return !Urls.isUrlWithProtocol(url) || url.startsWith("classpath:"); }
private DownloadResolver newDownloader(DownloadRequirement req) { // Infer filename String filename = null; for (Function<? super DownloadRequirement, String> filenameProducer : filenameProducers) { filename = filenameProducer.apply(req); if (!Strings.isBlank(filename)) break; } // If a filename-producer has given us the filename, then augment the DownloadRequirement with // that // (so that local-repo substitutions etc can use that explicit filename) DownloadRequirement wrappedReq; if (filename == null) { wrappedReq = req; } else { wrappedReq = BasicDownloadRequirement.copy(req, ImmutableMap.of("filename", filename)); } // Get ordered download targets to be tried List<String> primaries = Lists.newArrayList(); List<String> fallbacks = Lists.newArrayList(); for (Function<? super DownloadRequirement, ? extends DownloadTargets> producer : producers) { DownloadTargets vals = producer.apply(wrappedReq); primaries.addAll(vals.getPrimaryLocations()); fallbacks.addAll(vals.getFallbackLocations()); if (!vals.canContinueResolving()) { break; } } Set<String> result = Sets.newLinkedHashSet(); result.addAll(primaries); result.addAll(fallbacks); if (result.isEmpty()) { throw new IllegalArgumentException("No downloads matched for " + req); } // If filename-producers didn't give any explicit filename, then infer from download results if (filename == null) { for (String target : result) { filename = FilenameProducers.inferFilename(target); if (!Strings.isBlank(filename)) break; } } if (Strings.isBlank(filename)) { throw new IllegalArgumentException( "No filenames matched for " + req + " (targets " + result + ")"); } // And return the result return new BasicDownloadResolver(result, filename); }
@SuppressWarnings({"rawtypes", "unchecked"}) private <T extends Entity> brooklyn.entity.proxying.EntitySpec<?> toCoreEntitySpec( Class<T> clazz, String name, Map<String, String> configO) { Map<String, String> config = (configO == null) ? Maps.<String, String>newLinkedHashMap() : Maps.newLinkedHashMap(configO); brooklyn.entity.proxying.EntitySpec<? extends Entity> result; if (clazz.isInterface()) { result = brooklyn.entity.proxying.EntitySpec.create(clazz); } else { // If this is a concrete class, particularly for an Application class, we want the proxy // to expose all interfaces it implements. Class interfaceclazz = (Application.class.isAssignableFrom(clazz)) ? Application.class : Entity.class; Set<Class<?>> additionalInterfaceClazzes = Reflections.getInterfacesIncludingClassAncestors(clazz); result = brooklyn.entity.proxying.EntitySpec.create(interfaceclazz) .impl(clazz) .additionalInterfaces(additionalInterfaceClazzes); } if (!Strings.isEmpty(name)) result.displayName(name); result.configure(convertFlagsToKeys(result.getImplementation(), config)); return result; }
@SuppressWarnings("unchecked") private brooklyn.entity.proxying.EntitySpec<? extends Entity> toCoreEntitySpec( brooklyn.rest.domain.EntitySpec spec) { String type = spec.getType(); String name = spec.getName(); Map<String, String> config = (spec.getConfig() == null) ? Maps.<String, String>newLinkedHashMap() : Maps.newLinkedHashMap(spec.getConfig()); Class<? extends Entity> tempclazz; try { tempclazz = getCatalog().loadClassByType(type, Entity.class); } catch (NoSuchElementException e) { try { tempclazz = (Class<? extends Entity>) getCatalog().getRootClassLoader().loadClass(type); log.info("Catalog does not contain item for type {}; loaded class directly instead", type); } catch (ClassNotFoundException e2) { log.warn( "No catalog item for type {}, and could not load class directly; rethrowing", type); throw e; } } final Class<? extends Entity> clazz = tempclazz; brooklyn.entity.proxying.EntitySpec<? extends Entity> result; if (clazz.isInterface()) { result = brooklyn.entity.proxying.EntitySpec.create(clazz); } else { result = brooklyn.entity.proxying.EntitySpec.create(Entity.class).impl(clazz); } if (!Strings.isEmpty(name)) result.displayName(name); result.configure(convertFlagsToKeys(result.getType(), config)); configureRenderingMetadata(spec, result); return result; }
@Deprecated public static String fixLocation(String locationId) { if (locationId.startsWith("/v1/locations/")) { log.warn("REST API using legacy URI syntax for location: " + locationId); locationId = Strings.removeFromStart(locationId, "/v1/locations/"); } return locationId; }
public static Map<ConfigKey<String>, String> finalAndOriginalSpecs( String finalSpec, Object... sourcesForOriginalSpec) { // yuck!: TODO should clean up how these things get passed around Map<ConfigKey<String>, String> result = MutableMap.of(); if (finalSpec != null) result.put(LocationInternal.FINAL_SPEC, finalSpec); String originalSpec = null; for (Object source : sourcesForOriginalSpec) { if (source instanceof CharSequence) originalSpec = source.toString(); else if (source instanceof Map) { if (originalSpec == null) originalSpec = Strings.toString(((Map<?, ?>) source).get(LocationInternal.ORIGINAL_SPEC)); if (originalSpec == null) originalSpec = Strings.toString(((Map<?, ?>) source).get(LocationInternal.ORIGINAL_SPEC.getName())); } if (originalSpec != null) break; } if (originalSpec == null) originalSpec = finalSpec; if (originalSpec != null) result.put(LocationInternal.ORIGINAL_SPEC, originalSpec); return result; }
static String makeCommandExecutingInDirectory( String command, String executionDir, EntityLocal entity) { String finalCommand = command; String execDir = executionDir; if (Strings.isBlank(execDir)) { // default to run dir execDir = entity.getAttribute(SoftwareProcess.RUN_DIR); // if no run dir, default to home if (Strings.isBlank(execDir)) { execDir = "~"; } } else if (!Os.isAbsolutish(execDir)) { // relative paths taken wrt run dir String runDir = entity.getAttribute(SoftwareProcess.RUN_DIR); if (!Strings.isBlank(runDir)) { execDir = Os.mergePaths(runDir, execDir); } } if (!"~".equals(execDir)) { finalCommand = "mkdir -p '" + execDir + "' && cd '" + execDir + "' && " + finalCommand; } return finalCommand; }
@Override public void customize() { newScript(CUSTOMIZING) .body .append( format("mkdir -p %s", getRunDir()), format("cp -R %s/dist/{conf,html,logs,sbin} %s", getExpandedInstallDir(), getRunDir())) .execute(); // Install static content archive, if specified String archiveUrl = entity.getConfig(NginxController.STATIC_CONTENT_ARCHIVE_URL); if (Strings.isNonBlank(archiveUrl)) { getEntity().deploy(archiveUrl); } customizationCompleted = true; getEntity().doExtraConfigurationDuringStart(); }
@SuppressWarnings("rawtypes") private static void addNamedAction( MutableMap.Builder<String, URI> lb, RendererHints.NamedAction na, Entity entity, Sensor<?> sensor) { if (na instanceof RendererHints.NamedActionWithUrl) { try { String v = ((RendererHints.NamedActionWithUrl) na).getUrl(entity, (AttributeSensor<?>) sensor); if (Strings.isNonBlank(v)) { String action = na.getActionName().toLowerCase(); lb.putIfAbsent("action:" + action, URI.create(v)); } } catch (Exception e) { Exceptions.propagateIfFatal(e); log.warn("Unable to make use of URL sensor " + sensor + " on " + entity + ": " + e); } } }
public String getSummary() { if (summary != null) return summary; return Strings.join(commands, " ; "); }
@Override public void install() { // will fail later if can't sudo (if sudo is required) DynamicTasks.queueIfPossible(SshTasks.dontRequireTtyForSudo(getMachine(), false)) .orSubmitAndBlock(); DownloadResolver nginxResolver = mgmt().getEntityDownloadsManager().newDownloader(this); List<String> nginxUrls = nginxResolver.getTargets(); String nginxSaveAs = nginxResolver.getFilename(); setExpandedInstallDir( getInstallDir() + "/" + nginxResolver.getUnpackedDirectoryName(format("nginx-%s", getVersion()))); boolean sticky = ((NginxController) entity).isSticky(); boolean isMac = getMachine().getOsDetails().isMac(); MutableMap<String, String> installGccPackageFlags = MutableMap.of( "onlyifmissing", "gcc", "yum", "gcc", "apt", "gcc", "zypper", "gcc", "port", null); MutableMap<String, String> installMakePackageFlags = MutableMap.of( "onlyifmissing", "make", "yum", "make", "apt", "make", "zypper", "make", "port", null); MutableMap<String, String> installPackageFlags = MutableMap.of( "yum", "openssl-devel pcre-devel", "apt", "libssl-dev zlib1g-dev libpcre3-dev", "zypper", "libopenssl-devel pcre-devel", "port", null); String stickyModuleVersion = entity.getConfig(NginxController.STICKY_VERSION); DownloadResolver stickyModuleResolver = mgmt() .getEntityDownloadsManager() .newDownloader( this, "stickymodule", ImmutableMap.of("addonversion", stickyModuleVersion)); List<String> stickyModuleUrls = stickyModuleResolver.getTargets(); String stickyModuleSaveAs = stickyModuleResolver.getFilename(); String stickyModuleExpandedInstallDir = String.format( "%s/src/%s", getExpandedInstallDir(), stickyModuleResolver.getUnpackedDirectoryName( "nginx-sticky-module-" + stickyModuleVersion)); List<String> cmds = Lists.newArrayList(); cmds.add(BashCommands.INSTALL_TAR); cmds.add( BashCommands.alternatives( BashCommands.ifExecutableElse0( "apt-get", BashCommands.installPackage("build-essential")), BashCommands.ifExecutableElse0( "yum", BashCommands.sudo("yum -y --nogpgcheck groupinstall \"Development Tools\"")))); cmds.add(BashCommands.installPackage(installGccPackageFlags, "nginx-prerequisites-gcc")); cmds.add(BashCommands.installPackage(installMakePackageFlags, "nginx-prerequisites-make")); cmds.add(BashCommands.installPackage(installPackageFlags, "nginx-prerequisites")); cmds.addAll(BashCommands.commandsToDownloadUrlsAs(nginxUrls, nginxSaveAs)); String pcreExpandedInstallDirname = ""; if (isMac) { String pcreVersion = entity.getConfig(NginxController.PCRE_VERSION); DownloadResolver pcreResolver = mgmt() .getEntityDownloadsManager() .newDownloader(this, "pcre", ImmutableMap.of("addonversion", pcreVersion)); List<String> pcreUrls = pcreResolver.getTargets(); String pcreSaveAs = pcreResolver.getFilename(); pcreExpandedInstallDirname = pcreResolver.getUnpackedDirectoryName("pcre-" + pcreVersion); // Install PCRE cmds.addAll(BashCommands.commandsToDownloadUrlsAs(pcreUrls, pcreSaveAs)); cmds.add(format("mkdir -p %s/pcre-dist", getInstallDir())); cmds.add(format("tar xvzf %s", pcreSaveAs)); cmds.add(format("cd %s", pcreExpandedInstallDirname)); cmds.add(format("./configure --prefix=%s/pcre-dist", getInstallDir())); cmds.add("make"); cmds.add("make install"); cmds.add("cd .."); } cmds.add(format("tar xvzf %s", nginxSaveAs)); cmds.add(format("cd %s", getExpandedInstallDir())); if (sticky) { cmds.add("cd src"); cmds.addAll(BashCommands.commandsToDownloadUrlsAs(stickyModuleUrls, stickyModuleSaveAs)); cmds.add(format("tar xvzf %s", stickyModuleSaveAs)); cmds.add("cd .."); } // Note that for OS X, not including space after "-L" because broken in 10.6.8 (but fixed in // 10.7.x) // see http://trac.nginx.org/nginx/ticket/227 String withLdOpt = entity.getConfig(NginxController.WITH_LD_OPT); if (isMac) withLdOpt = format("-L%s/pcre-dist/lib", getInstallDir()) + (Strings.isBlank(withLdOpt) ? "" : " " + withLdOpt); String withCcOpt = entity.getConfig(NginxController.WITH_CC_OPT); StringBuilder configureCommand = new StringBuilder("./configure") .append(format(" --prefix=%s/dist", getExpandedInstallDir())) .append(" --with-http_ssl_module") .append(sticky ? format(" --add-module=%s ", stickyModuleExpandedInstallDir) : "") .append(!Strings.isBlank(withLdOpt) ? format(" --with-ld-opt=\"%s\"", withLdOpt) : "") .append(!Strings.isBlank(withCcOpt) ? format(" --with-cc-opt=\"%s\"", withCcOpt) : ""); if (isMac) { configureCommand .append(" --with-pcre=") .append(getInstallDir()) .append("/") .append(pcreExpandedInstallDirname); } cmds.addAll(ImmutableList.of("mkdir -p dist", configureCommand.toString(), "make install")); ScriptHelper script = newScript(INSTALLING) .body .append(cmds) .header .prepend("set -x") .gatherOutput() .failOnNonZeroResultCode(false); int result = script.execute(); if (result != 0) { String notes = "likely an error building nginx. consult the brooklyn log ssh output for further details.\n" + "note that this Brooklyn nginx driver compiles nginx from source. " + "it attempts to install common prerequisites but this does not always succeed.\n"; OsDetails os = getMachine().getOsDetails(); if (os.isMac()) { notes += "deploying to Mac OS X, you will require Xcode and Xcode command-line tools, and on " + "some versions the pcre library (e.g. using macports, sudo port install pcre).\n"; } if (os.isWindows()) { notes += "this nginx driver is not designed for windows, unless cygwin is installed, and you are patient.\n"; } if (getEntity().getApplication().getClass().getCanonicalName().startsWith("brooklyn.demo.")) { // this is maybe naughty ... but since we use nginx in the first demo example, // and since it's actually pretty complicated, let's give a little extra hand-holding notes += "if debugging this is all a bit much and you just want to run a demo, " + "you have two fairly friendly options.\n" + "1. you can use a well known cloud, like AWS or Rackspace, where this should run " + "in a tried-and-tested Ubuntu or CentOS environment, without any problems " + "(and if it does let us know and we'll fix it!).\n" + "2. or you can just use the demo without nginx, instead access the appserver instances directly.\n"; } if (!script.getResultStderr().isEmpty()) { notes += "\n" + "STDERR\n" + script.getResultStderr() + "\n"; Streams.logStreamTail( log, "STDERR of problem in " + Tasks.current(), Streams.byteArrayOfString(script.getResultStderr()), 1024); } if (!script.getResultStdout().isEmpty()) { notes += "\n" + "STDOUT\n" + script.getResultStdout() + "\n"; Streams.logStreamTail( log, "STDOUT of problem in " + Tasks.current(), Streams.byteArrayOfString(script.getResultStdout()), 1024); } Tasks.setExtraStatusDetails(notes.trim()); throw new IllegalStateException( "Installation of nginx failed (shell returned non-zero result " + result + ")"); } }
@SuppressWarnings("unchecked") public Application create(ApplicationSpec spec) { log.debug("REST creating application instance for {}", spec); if (!Entitlements.isEntitled( mgmt.getEntitlementManager(), Entitlements.DEPLOY_APPLICATION, spec)) { throw WebResourceUtils.unauthorized( "User '%s' is not authorized to deploy application %s", Entitlements.getEntitlementContext().user(), spec); } final String type = spec.getType(); final String name = spec.getName(); final Map<String, String> configO = spec.getConfig(); final Set<EntitySpec> entities = (spec.getEntities() == null) ? ImmutableSet.<EntitySpec>of() : spec.getEntities(); final Application instance; // Load the class; first try to use the appropriate catalog item; but then allow anything that // is on the classpath final Class<? extends Entity> clazz; if (Strings.isEmpty(type)) { clazz = BasicApplication.class; } else { Class<? extends Entity> tempclazz; try { tempclazz = getCatalog().loadClassByType(type, Entity.class); } catch (NoSuchElementException e) { try { tempclazz = (Class<? extends Entity>) getCatalog().getRootClassLoader().loadClass(type); log.info( "Catalog does not contain item for type {}; loaded class directly instead", type); } catch (ClassNotFoundException e2) { log.warn( "No catalog item for type {}, and could not load class directly; rethrowing", type); throw e; } } clazz = tempclazz; } if (Entitlements.isEntitled(mgmt.getEntitlementManager(), Entitlements.INVOKE_EFFECTOR, null)) { try { if (ApplicationBuilder.class.isAssignableFrom(clazz)) { Constructor<?> constructor = clazz.getConstructor(); ApplicationBuilder appBuilder = (ApplicationBuilder) constructor.newInstance(); if (!Strings.isEmpty(name)) appBuilder.appDisplayName(name); if (entities.size() > 0) log.warn( "Cannot supply additional entities when using an ApplicationBuilder; ignoring in spec {}", spec); log.info("REST placing '{}' under management", spec.getName()); appBuilder.configure(convertFlagsToKeys(appBuilder.getType(), configO)); configureRenderingMetadata(spec, appBuilder); instance = appBuilder.manage(mgmt); } else if (Application.class.isAssignableFrom(clazz)) { brooklyn.entity.proxying.EntitySpec<?> coreSpec = toCoreEntitySpec(clazz, name, configO); configureRenderingMetadata(spec, coreSpec); instance = (Application) mgmt.getEntityManager().createEntity(coreSpec); for (EntitySpec entitySpec : entities) { log.info("REST creating instance for entity {}", entitySpec.getType()); instance.addChild(mgmt.getEntityManager().createEntity(toCoreEntitySpec(entitySpec))); } log.info( "REST placing '{}' under management", spec.getName() != null ? spec.getName() : spec); Entities.startManagement(instance, mgmt); } else if (Entity.class.isAssignableFrom(clazz)) { if (entities.size() > 0) log.warn( "Cannot supply additional entities when using a non-application entity; ignoring in spec {}", spec); brooklyn.entity.proxying.EntitySpec<?> coreSpec = toCoreEntitySpec(BasicApplication.class, name, configO); configureRenderingMetadata(spec, coreSpec); instance = (Application) mgmt.getEntityManager().createEntity(coreSpec); final Class<? extends Entity> eclazz = getCatalog().loadClassByType(spec.getType(), Entity.class); Entity soleChild = mgmt.getEntityManager().createEntity(toCoreEntitySpec(eclazz, name, configO)); instance.addChild(soleChild); instance.addEnricher(Enrichers.builder().propagatingAll().from(soleChild).build()); log.info("REST placing '{}' under management", spec.getName()); Entities.startManagement(instance, mgmt); } else { throw new IllegalArgumentException( "Class " + clazz + " must extend one of ApplicationBuilder, Application or Entity"); } return instance; } catch (Exception e) { log.error("REST failed to create application: " + e, e); throw Exceptions.propagate(e); } } throw WebResourceUtils.unauthorized( "User '%s' is not authorized to create application from applicationSpec %s", Entitlements.getEntitlementContext().user(), spec); }
@Override public boolean isAuthenticated(HttpSession session) { if (session == null) return false; Object value = session.getAttribute(getAuthenticationKey()); return Strings.isNonBlank(Strings.toString(value)); }