Buscar este blog

sábado, 30 de diciembre de 2017

Centos 7.x - Minimal network setup

This is a continuation of a previous post, but this time dedicated to CentOS 7 (our customer is evolving!!)

Environment:
  • Virtualbox 5.1.10
  • CentOS 7.4.1708
Before start with the installation, in Virtualbox you have to configure two network adapters:
  • Adapter 1: Host only
  • Adapter 2: NAT
The first one will be used to communicate host and guest, for example, by using a ssh connection. The second one will be used by the guest in order to gain direct access to the internet.

When CentOS starts for first time, you will already had internet access. But local network will be disabled. Execute the following command to check your network interfaces:
ip add

The result will be something like this:


Here you can see three interfaces:
  • lo: Loopback
  • enp0s3: Host-Only adapter
  • enp0s8: NAT adapter
If you have doubts about which is the host-only, you can check the MAC address and compare it with the Virtualbox adapter.


Once you are sure enp0s3 is your interface, go to /etc/sysconfig/network-scripts/ and edit ifcfg-enp0s3 file, for example with vi. You will have to make two changes:
  • Set BOOTPROTO=none
  • Set ONBOOT=yes
  • Add IPADDR=your IP

Then execute the following command:
systemctl restart network.service

Now you will have your interface up and with the IP address you set before.


Note

As stated in my previous post, remember to configure proxy settings for system and yum configuration:

System config

Edit ~/.bash_profile file and add the following lines:

# The Web proxy server used by this account
http_proxy="http://usuario:password@my.proxy:8080"
export no_proxy=localhost,127.0.0.1
export http_proxy

YUM config

Edit  /etc/yum.conf y add the following lines:

# The proxy server - proxy server:port number
proxy=http://my.proxy:8080
# The account details for yum connections
proxy_username=usuario
proxy_password=password

sábado, 23 de diciembre de 2017

LibreOffice - Force PDF/A export

I was using LibreOffice to convert documents from disparate formats to PDF. This is done by using the following command:
libreoffice5.3 --headless --convert-to pdf prueba.txt

My problem was that the output file was not int PDF/A format.



LibreOffice, by working with it´s GUI interface, do supports PDF/A conversion, so the problem should be in some kind of default configuration.


There is configuration file called registrymodifications.xcu which contains all settings used by the programa, and during the exportation too. This file is located in  ~/.config/libreoffice/4/user/ directory. For example /root/.config/libreoffice/4/user/registrymodifications.xcu.

This is an xml based file with a lot of (poor/undocumented) preferences. In particular, in order to set PDF/A as default option, you have to insert the following config line:
<?xml version="1.0" encoding="UTF-8"?>
<oor:items xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 (...)
 <item oor:path="/org.openoffice.Office.Common/Filter/PDF/Export">
  <prop oor:name="SelectPdfVersion" oor:op="fuse">
   <value>1</value>
  </prop>
 </item>
 (...)
</oor:items>

Now, if you launch the conversion again you will get a PDF/A-1A file.

Though registrymodifications.xcu file is quite obscure, you can get mor info by using the GUI version of the program. If you navigate to Tools > Options > LibreOffice > Advanced > Open Expert Configuration, you can check the whole list of settings.

viernes, 15 de diciembre de 2017

Unix - CIFS / NFS Mount

Mount CIFS

fstab:
//host/server_dir /mnt/unix_dir  cifs gid=jboss,uid=jboss,domain=xxxxx,user=yyyyy,password=zzzzz,_netdev,rw   0 0

Mount NFS

fstab:
host:/server_dir /mnt/unix_dir nfs rsize=8192,timeo=14,intr 0 0

jueves, 7 de diciembre de 2017

HTTP response '413: Request Entity Too Large' when communicating with 'xxx'

I was able to reproduce this error with Apache 2.2 + mod_ssl.

Just configure a virtual host port 443 and set the SSLVerifyClient to required or optional.
<Location />
    SSLRequireSSL 
    SSLOptions +StdEnvVars +ExportCertData +StrictRequire
    SSLVerifyClient optional
    SSLVerifyDepth 2   
</Location>

When you send a large request, for example a SOAP message which contains a file (bad practice, use MTOM), you could get the following error:
[2017-12-07 16:59:42,313] (LogUtils.java:478) WARN main org.apache.cxf.phase.PhaseInterceptorChain Interceptor for {http:/xxxxxxxxxxxxxxxx}yyyyyyyyy#{http:/xxxxxxxxxxxxxxxx}generarCSV has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Could not send Message.
 at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:64)
 at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
 at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:518)
 at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:427)
 at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:328)
 at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:281)
 at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
 at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:139)
 at com.sun.proxy.$Proxy22.generarCSV(Unknown Source)
 at es.sisifo.cxf.client.SinaturaServiceClient.run(SinaturaServiceClient.java:81)
 at es.sisifo.cxf.client.SinaturaServiceClient.main(SinaturaServiceClient.java:93)
Caused by: org.apache.cxf.transport.http.HTTPException: HTTP response '413: Request Entity Too Large' when communicating with https://my-service-endpoint
 at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.doProcessResponseCode(HTTPConduit.java:1609)
 at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1616)
 at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1560)
 at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1361)
 at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
 at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:658)
 at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
 ... 10 more

The solution is to use the SSLRenegBufferSize directive:
If an SSL renegotiation is required in per-location context, for example, any use of SSLVerifyClient in a Directory or Location block, then mod_ssl must buffer any HTTP request body into memory until the new SSL handshake can be performed. This directive can be used to set the amount of memory that will be used for this buffer.
This buffer is referred to the whole size of the request, i.e, if you are sending a 200KB file, then the value should be set to around 250000 (you have to spare some size for the rest of the request).
<Location />
    SSLRequireSSL 
    SSLOptions +StdEnvVars +ExportCertData +StrictRequire
    SSLVerifyClient optional
    SSLVerifyDepth 2
    SSLRenegBufferSize 250000 
</Location>


In other places you can also found that the problem could be solved with other two directives, LimitXMLRequestBody  and LimitRequestBody but I was not able to reproduce my problem by using them.

sábado, 28 de octubre de 2017

Java command tools Cheat sheet

JPS - Java Virtual Machine Process Status Tool

Find all java process in a host:
C:\Program Files\Java\jdk1.7.0_79\bin>jps -lv
6192 sun.tools.jps.Jps -Dapplication.home=C:\Program Files\Java\jdk1.7.0_79 -Xms8m
5348 C:\Desarrollo\eclipse-neon-2\\plugins/org.eclipse.equinox.launcher_1.3.201.v20161025-1711.jar -Dosgi.requiredJavaVersion=1.8 -XX:+UseG1GC -XX:+UseStringDeduplication -Dosgi.requiredJavaVersion=1.8 -Xms256m -Xmx2048m
3496 org.jboss.modules.Main -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:49626 -Dprogram.name=JBossTools: Red Hat JBoss EAP 6.1+ -Xms512m -Xmx1024m -XX:MaxPermSize=512m -Dorg.jboss.resolver.warning=true -Djava.net.preferIPv4Stack=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true -Dorg.jboss.boot.log.file=C:/Servers/jboss-eap-6.2/standalone/log/boot.log -Dlogging.configuration=file:/C:/Servers/jboss-eap-6.2/standalone/configuration/logging.properties -Djboss.home.dir=C:/Servers/jboss-eap-6.2 -Dorg.jboss.logmanager.nocolor=true -Djboss.bind.address.management=localhost -Dfile.encoding=Cp1252

JMAP - Memory analysis

Print heap usage sumary:
C:\Program Files\Java\jdk1.7.0_79\bin>jmap -heap 3496
Attaching to process ID 3496, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.79-b02

using thread-local object allocation.
Parallel GC with 4 thread(s)

Heap Configuration:
   MinHeapFreeRatio = 0
   MaxHeapFreeRatio = 100
   MaxHeapSize      = 1073741824 (1024.0MB)
   NewSize          = 1310720 (1.25MB)
   MaxNewSize       = 17592186044415 MB
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 21757952 (20.75MB)
   MaxPermSize      = 536870912 (512.0MB)
   G1HeapRegionSize = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 241172480 (230.0MB)
   used     = 101086072 (96.40319061279297MB)
   free     = 140086408 (133.59680938720703MB)
   41.914430701214336% used
From Space:
   capacity = 56623104 (54.0MB)
   used     = 0 (0.0MB)
   free     = 56623104 (54.0MB)
   0.0% used
To Space:
   capacity = 56623104 (54.0MB)
   used     = 0 (0.0MB)
   free     = 56623104 (54.0MB)
   0.0% used
PS Old Generation
   capacity = 358088704 (341.5MB)
   used     = 194474744 (185.46556854248047MB)
   free     = 163613960 (156.03443145751953MB)
   54.30909766983323% used
PS Perm Generation
   capacity = 296222720 (282.5MB)
   used     = 144879144 (138.16751861572266MB)
   free     = 151343576 (144.33248138427734MB)
   48.90885614715846% used

44021 interned Strings occupying 5210120 bytes.

Print heap histogram:
C:\Program Files\Java\jdk1.7.0_79\bin>jmap -histo 3496
 num     #instances         #bytes  class name
----------------------------------------------
   1:        105723       53508480  [B
   2:        577164       46177512  [C
   3:        245156       35415432  <constMethodKlass>
   4:        245156       31391216  <methodKlass>
   5:         25900       28928112  <constantPoolKlass>
   6:        628395       25135800  java.util.LinkedHashMap$Entry
   [...]
11430:            1             16  org.jboss.as.platform.mbean.ThreadMXBeanFindDeadlockedThreadsHandler
11431:            1             16  org.jboss.msc.service.ServiceContainerImpl$4
11432:            1             16  org.jboss.as.jmx.JMXExtension$JMXSubsystemParser_1_3
Total       8243462      503304768

JCMD

Show JVM Information:
C:\Program Files\Java\jdk1.7.0_79\bin>jcmd 3496 help
3496:
The following commands are available:
VM.native_memory
VM.commercial_features
GC.rotate_log
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
Thread.print
GC.class_histogram
GC.heap_dump
GC.run_finalization
GC.run
VM.uptime
VM.flags
VM.system_properties
VM.command_line
VM.version
help

For more information about a specific command use 'help <command>'.

Print all JVM Threads:
C:\Program Files\Java\jdk1.7.0_79\bin>jcmd 3496 help Thread.print
3496:
Thread.print
Print all threads with stacktraces.

Impact: Medium: Depends on the number of threads.

Syntax : Thread.print [options]

Options: (options must be specified using the <key> or <key>=<value> syntax)
        -l : [optional] print java.util.concurrent locks (BOOLEAN, false)


C:\Program Files\Java\jdk1.7.0_79\bin>jcmd 3496 Thread.print
[...]

Generate a Heap dump:
C:\Program Files\Java\jdk1.7.0_79\bin>jcmd 3496 help GC.heap_dump
3496:
GC.heap_dump
Generate a HPROF format dump of the Java heap.

Impact: High: Depends on Java heap size and content. Request a full GC unless the '-all' option is specified.

Syntax : GC.heap_dump [options] <filename>

Arguments:
        filename :  Name of the dump file (STRING, no default value)

Options: (options must be specified using the <key> or <key>=<value> syntax)
        -all : [optional] Dump all objects, including unreachable objects (BOOLEAN, false)
 
 
C:\Program Files\Java\jdk1.7.0_79\bin>jcmd 3496 GC.heap_dump D:\tmp\test_jboss.hpprof
3496:
Heap dump file created

Important!! When you execute a heap dump, the JVM performs a garbage collector first. Therefore you will not get the heap´s snapshot, but a cleaner version.

JSTAT

Monitor Garbage Colector:
Program Files\Java\jdk1.7.0_79\bin>jstat -options
-cl
-compiler
-gc
-gccapacity
-gccause
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-printcompilation


C:\Program Files\Java\jdk1.7.0_79\bin>jstat -gcutil 3496 1000
  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT
  0,00  24,73  88,78  72,67  99,92     23    0,973     0    0,000    0,973
  0,00  24,73  88,79  72,67  99,92     23    0,973     0    0,000    0,973
  0,00  24,73  89,02  72,67  99,92     23    0,973     0    0,000    0,973

domingo, 3 de septiembre de 2017

WINSCP Scripting Cheat sheet

Invoke the script from command line:
WinSCPPortable.exe /script="D:\PortableApps\WinSCPPortable\myScript.txt" /log="D:\PortableApps\WinSCPPortable\myScript.log /console" /loglevel=2

Script code:
open ftp://user:pass@host

get 80/00/95/FB.pdf D:\tmp\local\80\00\95\FB.pdf
get 80/00/96/02.pdf D:\tmp\local\80\00\96\02.pdf

exit

References:

domingo, 13 de agosto de 2017

Documentum - Oracle query to find file path

This is a small tweak of this useful post: https://msroth.wordpress.com/2011/09/04/finding-an-objects-content-file/

It was tested with Documentum 6.7 and Oracle database 11g.
select
    CR.parent_id AS OID,
    L.file_system_path AS Base_Path,
    CS.data_ticket AS Ticket,   
    TRIM(TO_CHAR(TO_NUMBER(CS.data_ticket) + 4294967296, 'XXXXXXXX')) AS Ticket_HEX,
    '/' ||
    SUBSTR(TRIM(TO_CHAR(TO_NUMBER(CS.data_ticket) + 4294967296, 'XXXXXXXX')), 1, 2) || '/' ||
    SUBSTR(TRIM(TO_CHAR(TO_NUMBER(CS.data_ticket) + 4294967296, 'XXXXXXXX')), 3, 2) || '/' ||
    SUBSTR(TRIM(TO_CHAR(TO_NUMBER(CS.data_ticket) + 4294967296, 'XXXXXXXX')), 5, 2) || '/'  AS DIRECTORY,       
    SUBSTR(TRIM(TO_CHAR(TO_NUMBER(CS.data_ticket) + 4294967296, 'XXXXXXXX')), 7, 2) || '.' || CS.full_format AS FILE_NAME,
    CS.full_format AS FILE_EXTENSION,
    CS.full_content_size AS FILE_SIZE   
from 
    DMR_CONTENT_S CS, 
    DMR_CONTENT_R CR, 
    DM_FILESTORE_S F, 
    DM_LOCATION_S L, 
    DM_SYSOBJECT_S S 
where 
    CS.r_object_id = CR.r_object_id 
    AND CR.parent_id = '0898968180000ada'
    AND CS.storage_id = F.r_object_id
    AND F.root = S.object_name 
    AND S.r_object_id = L.r_object_id;

Result:

Note: As the was stated in the referenced post, 4294967296 is 2^32, and is used to convert the negative number of the ticket to hexadecimal.

viernes, 11 de agosto de 2017

JBoss - Vault utility outside JBoss

JBoss Password Vault is tool to store and retrive encrypted passwords. It´s based in a keystore (which contains a private key) used to encrypt passwords, and a data file to store them. Check JBoss development guide for more info.

When working with JBoss, you can configure your Vault with a tool also provided, and the you only need to reference a set of configuration from standalone.xml/domain.xml files. Then, you can store new passwords in the Vault, being each of them referenced by a string in the format "Vault::XXXX:YYYY:n". Any time you need to use these passwords you can place them in JBoss config files (with ${}) or inside your EAR/WARs and by decrypting them manually with SecurityVault. JBoss uses picketbox in order to encrypt/decrypt these passwords.

When you configure JBoss Vault you begin with a keystore file, specify some configuration values, and obtains an store data file. All these stuff are then referenced in JBoss by an xml snippet, as described in the development guide.

I put here the steps in order to create the keystore, configure the Vault, and store a new password in it:
1) Create the keystore:
keytool -genseckey -alias jboss -storetype jceks -keyalg AES -keysize 128 -storepass 123456 -keypass 123456 -validity 999 -keystore vault(123456).keystore

2) Configure the Vault:
Please enter a Digit::   0: Start Interactive Session  1: Remove Interactive Session  2: Exit
0
Starting an interactive session
Enter directory to store encrypted files:C:/Servers/jboss-eap-6.4/VAULT/
Enter Keystore URL:C:/Servers/jboss-eap-6.4/VAULT/vault(123456).keystore
Enter Keystore password:
Enter Keystore password again:
Values match
Enter 8 character salt:1234abcd
Enter iteration count as a number (Eg: 44):100
Enter Keystore Alias:jboss
Initializing Vault
ago 11, 2017 12:56:53 PM org.jboss.security.vault.SecurityVaultFactory secondVaultInfo
WARN: PBOX000378: Attempt to create the second Security Vault [org.picketbox.plugins.vault.PicketBoxSecurityVault] is invalid. Only one Security Vault is supported. Change your configuration, please.
ago 11, 2017 12:56:53 PM org.picketbox.plugins.vault.PicketBoxSecurityVault init
INFO: PBOX000361: Default Security Vault Implementation Initialized and Ready
Vault Configuration in configuration file:
********************************************
...
</extensions>
<vault>
  <vault-option name="KEYSTORE_URL" value="C:/Servers/jboss-eap-6.4/VAULT/vault(123456).keystore"/>
  <vault-option name="KEYSTORE_PASSWORD" value="MASK-AwOVVL6T7qb"/>
  <vault-option name="KEYSTORE_ALIAS" value="jboss"/>
  <vault-option name="SALT" value="1234abcd"/>
  <vault-option name="ITERATION_COUNT" value="100"/>
  <vault-option name="ENC_FILE_DIR" value="C:/Servers/jboss-eap-6.4/VAULT/"/>
</vault><management> ...
********************************************
Vault is initialized and ready for use
Handshake with Vault complete
Please enter a Digit::  0: Store a secured attribute  1: Check whether a secured attribute exists  2: Remove secured attribute  3: Exit

3) Store a new password:
Please enter a Digit::  0: Store a secured attribute  1: Check whether a secured attribute exists  2: Remove secured attribute  3: Exit
0
Task: Store a secured attribute
Please enter secured attribute value (such as password):
Please enter secured attribute value (such as password) again:
Values match
Enter Vault Block:Pruebas
Enter Attribute Name:pass1
Secured attribute value has been stored in vault.
Please make note of the following:
********************************************
Vault Block:Pruebas
Attribute Name:pass1
Configuration should be done as follows:
VAULT::Pruebas::pass1::1
********************************************
Please enter a Digit::  0: Store a secured attribute  1: Check whether a secured attribute exists  2: Remove secured attribute  3: Exit


The question here is how to use JBoss Vault outside JBoss. I mean, I have a JBoss Vault used by a JBoss Domain, and I also have an standalone java application which needs to use enrypted passwods. By customer requirements, this application must use JBoss Vault in order to retrive these passwords values.

In order to do that, you can use the following java utility:
import java.util.HashMap;
import java.util.Map;

import org.jboss.security.vault.SecurityVault;
import org.jboss.security.vault.SecurityVaultException;
import org.jboss.security.vault.SecurityVaultFactory;
import org.jboss.security.vault.SecurityVaultUtil;
import org.picketbox.plugins.vault.PicketBoxSecurityVault;

public class Main {
    public static void main(final String[] args) throws SecurityVaultException {

        final SecurityVault vault = SecurityVaultFactory.get();
        if (!vault.isInitialized()) {
            final Map<String, Object> optionsInitVault = new HashMap<String, Object>();
            optionsInitVault.put(PicketBoxSecurityVault.KEYSTORE_URL, "C:/Servers/jboss-eap-6.4/VAULT/vault(123456).keystore");
            optionsInitVault.put(PicketBoxSecurityVault.KEYSTORE_PASSWORD, "MASK-AwOVVL6T7qb");
            optionsInitVault.put(PicketBoxSecurityVault.KEYSTORE_ALIAS, "jboss");
            optionsInitVault.put(PicketBoxSecurityVault.KEYSTORE_TYPE, "jceks");
            optionsInitVault.put(PicketBoxSecurityVault.SALT, "1234abcd");
            optionsInitVault.put(PicketBoxSecurityVault.ITERATION_COUNT, "100");
            optionsInitVault.put(PicketBoxSecurityVault.ENC_FILE_DIR, "C:/Servers/jboss-eap-6.4/VAULT/");
            vault.init(optionsInitVault);
        }


        final String textoCifrado = "VAULT::Pruebas::pass1::1";
        if (!SecurityVaultUtil.isVaultFormat(textoCifrado)) {
            System.out.println("La cadena no está cifrada. Se ha introducido un valor en claro");
        }
        else {
            System.out.println(SecurityVaultUtil.getValueAsString(textoCifrado));
        }
    }
}

As you see, the standalone application will need to know the parameters used to create the Vault, and also will need access to the keystore and data store file.

Maven dependencies, assuming JBoss EAP 6.4, are as follow:
<dependency>
 <groupId>org.picketbox</groupId>
 <artifactId>picketbox</artifactId>
 <version>4.1.1.Final</version>
</dependency>

<dependency>
 <groupId>org.jboss.logging</groupId>
 <artifactId>jboss-logging</artifactId>
 <version>3.1.4.GA</version>
</dependency>

jueves, 10 de agosto de 2017

OpenSSL - Certificate and private key cheat sheet

We start with a PKCS12 file called sisifo.pfx, which password is "1234".

A PKCS12 file contains:
  • Certificate
    • Certificate, information about the owner. If it is a certificate chain, it also contains information about the CAs.
    • Public key
  • Private key


Extract certificate and private key from a PKCS12 file (check here):
openssl pkcs12 -in sisifo.pfx -nocerts -out sisifo-key.pem -nodes
openssl rsa -in sisifo-key.pem -out sisifo.key

openssl pkcs12 -in sisifo.pfx -nokeys -out sisifo.cer


Merge certificate and private key files in a PKCS12 file (check here):
openssl pkcs12 -export -in sisifo.cer -inkey sisifo.key -name sisifo -out sisifo-2.pfx

If everything went fine, both files should be the same (or very similar ;)).

domingo, 6 de agosto de 2017

Tomcat Manager - Commands cheat sheet

Tomcat rest commands: https://tomcat.apache.org/tomcat-7.0-doc/manager-howto.html#Supported_Manager_Commands


First, you need to create a user with the manager-script role. The complete list of available roles can be found in $TOMCAT_HOME/webapps/manager/WEB-INF/web.xml:
  • manager-gui — Access to the HTML interface.
  • manager-status — Access to the "Server Status" page only.
  • manager-script — Access to the tools-friendly plain text interface that is described in this document, and to the "Server Status" page.
  • manager-jmx — Access to JMX proxy interface and to the "Server Status" page.

Then, you need to assign this role to a user. Users are configured en $TOMCAT_HOME/conf/tomcat-users.xml:
<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users>
  <role rolename="manager-gui"/>
  <role rolename="manager-script"/>
  <role rolename="manager-status"/>
  <role rolename="manager-jmx"/>
    
  <user username="admin"  password="admin"  roles="manager-gui"/>
  <user username="admins" password="admins" roles="manager-script"/>
</tomcat-users>

Finally, use curl tool:
curl -u admins:admins http://localhost:8080/manager/text/serverinfo

curl -u admins:admins http://localhost:8080/manager/text/list

curl -u admins:admins http://localhost:8080/manager/text/sessions?path=/examples
curl -u admins:admins http://localhost:8080/manager/text/start?path=/examples
curl -u admins:admins http://localhost:8080/manager/text/stop?path=/examples
curl -u admins:admins http://localhost:8080/manager/text/reload?path=/examples


lunes, 24 de julio de 2017

Oracle 11g - Export/Import as different user

Origin Machine

  • User to export: user1
  • System credentials: SYSTEM/pass1

Execute de following command:
exp system/pass1 FILE=user1.dmp OWNER=user1 LOG=user1-dump.log

Now you have the dump file, wich contains all user database info (views includes). In order to see the text content you can use this command:
strings user1.dmp | more

If you also need to export de user itself, you can use de followings SQL commands;
SQL> CONNECT SYSTEM/pass1;

SQL> SELECT DBMS_METADATA.GET_DDL('USER','SCOTT') FROM dual;
SQL> SELECT DBMS_METADATA.GET_GRANTED_DDL('ROLE_GRANT','SCOTT') from dual;
SQL> SELECT DBMS_METADATA.GET_GRANTED_DDL('OBJECT_GRANT','SCOTT') from dual;
SQL> SELECT DBMS_METADATA.GET_GRANTED_DDL('SYSTEM_GRANT','SCOTT') from dual;

Destination Machine

  • User to import: user2
  • System credentials: SYSTEM/pass2
The user2 is empty.

Execute de following command:
imp system/pass2 FILE=user1.dmp FROMUSER=user1 TOUSER=user2 LOG=user2-load.log

sábado, 24 de junio de 2017

CentOS - Run Elasticsearch as service

I assume there is a configured Elasticsearch installation in /opt/elasticsearch-1.5.2. The purpose of this post is to show how to configure this tool to run as an auto start service in CentOS.

First of all, is a best practice to use symbolic links with these kind of installations. If you change the program version you only will need to update the symbolic reference.
ln -s /opt/elasticsearch-1.5.2 /opt/elasticsearch

Also another best practice is to run the program with its own user.
useradd elasticsearch

chown -Rf elasticsearch:elasticsearch /opt/elasticsearch
chown -Rf elasticsearch:elasticsearch /opt/elasticsearch-1.5.2

Then, you go to /etc/init.d and create the service file ("inspired" from here and from one my previous post here):
#!/bin/sh
#
# 
# elasticsearch
#
# chkconfig: 2345 90 60

 
 
# Source function library.
. /etc/init.d/functions
 

 
PROGRAM_CONSOLE_LOG=/var/log/elasticsearch/elasticsearch.log
PROGRAM_PIDFILE=/var/run/elasticsearch.pid
PROGRAM_SCRIPT="/opt/elasticsearch/bin/elasticsearch -p $PROGRAM_PIDFILE"


 
 
PROGRAM_USER=elasticsearch
prog='Elasticsearch'
 
 
 
# Set defaults.
export PROGRAM_PIDFILE
 
 
if [ -z "$STARTUP_WAIT" ]; then
  STARTUP_WAIT=30
fi

 
if [ -z "$SHUTDOWN_WAIT" ]; then
  SHUTDOWN_WAIT=30
fi
 
 
 
start() {
  echo -n "Starting $prog: "
  if [ -f $PROGRAM_PIDFILE ]; then
    read ppid < $PROGRAM_PIDFILE
    if [ `ps --pid $ppid 2> /dev/null | grep -c $ppid 2> /dev/null` -eq '1' ]; then
      echo -n "$prog is already running"
      failure
      echo
      return 1
    else
      rm -f $PROGRAM_PIDFILE
    fi
  fi
  mkdir -p $(dirname $PROGRAM_CONSOLE_LOG)
  cat /dev/null > $PROGRAM_CONSOLE_LOG
  chown -Rf $PROGRAM_USER $(dirname $PROGRAM_CONSOLE_LOG) || true
 
 
  mkdir -p $(dirname $PROGRAM_PIDFILE)
  chown $PROGRAM_USER $(dirname $PROGRAM_PIDFILE) || true
 
   
  daemon --user $PROGRAM_USER --pidfile $PROGRAM_PIDFILE "$PROGRAM_SCRIPT" 1>"$PROGRAM_CONSOLE_LOG" 2>&1 &
  sleep 2
 # pidofproc node > $PROGRAM_PIDFILE
 
  count=0
  launched=false
 
  until [ $count -gt $STARTUP_WAIT ]
  do
    echo 'checking start...'
    grep 'started' $PROGRAM_CONSOLE_LOG > /dev/null
    if [ $? -eq 0 ] ; then
      launched=true
      break
    fi
    sleep 1
    let count=$count+1;
  done
 
  if [ "$launched" = true ] ; then
    echo 'Unable to start program'
  fi 

  success
  echo
  return 0
}
 
stop() {
  echo -n $"Stopping $prog: "
  count=0;
 
  if [ -f $PROGRAM_PIDFILE ]; then
    read kpid < $PROGRAM_PIDFILE
    let kwait=$SHUTDOWN_WAIT
 
    # Try issuing SIGTERM
 
    kill -15 $kpid
    until [ `ps --pid $kpid 2> /dev/null | grep -c $kpid 2> /dev/null` -eq '0' ] || [ $count -gt $kwait ]
    do
      sleep 1
      let count=$count+1;
    done
 
    if [ $count -gt $kwait ]; then
      kill -9 $kpid
    fi
  fi
  rm -f $PROGRAM_PIDFILE
  success
  echo
}
 
status() {
  if [ -f $PROGRAM_PIDFILE ]; then
    read ppid < $PROGRAM_PIDFILE
    if [ `ps --pid $ppid 2> /dev/null | grep -c $ppid 2> /dev/null` -eq '1' ]; then
      echo "$prog is running (pid $ppid)"
      return 0
    else
      echo "$prog dead but pid file exists"
      return 1
    fi
  fi
  echo "$prog is not running"
  return 3
}
 
case "$1" in
  start)
      start
      ;;
  stop)
      stop
      ;;
  restart)
      $0 stop
      $0 start
      ;;
  status)
      status
      ;;
  *)
      ## If no parameters are given, print which are avaiable.
      echo "Usage: $0 {start|stop|status|restart|reload}"
      exit 1
      ;;
esac

Finally, you have to make this script as runnable and configure the service as autostart.
chmod +x /etc/init.d/elasticsearch

chkconfig --add elasticsearch
chkconfig elasticsearch on

viernes, 23 de junio de 2017

CentOS - Install Java

Steps to install a JDK in Centos 6:
[root@servidor ~]# mkdir /usr/java
[root@servidor ~]# tar -zxvf jdk-8u121-linux-x64.tar.gz --directory /usr/java

In order to set this JDK as default installation, you have to run the followings commands:
[root@servidor ~]# alternatives --install "/usr/bin/javac" "javac" "/usr/java/jdk1.8.0_121/bin/javac" 50

[root@servidor ~]# alternatives --install "/usr/bin/java" "java" "/usr/java/jdk1.8.0_121/bin/java" 50

[root@servidor ~]# alternatives --install "/usr/bin/javaws" "javaws" "/usr/java/jdk1.8.0_121/bin/javaws" 50

[root@servidor ~]# alternatives --install "/usr/bin/jar" "jar" "/usr/java/jdk1.8.0_121/bin/jar" 50

CentOS - Iptables - Open TCP ports

In order to open TCP ports in a CentOS 6 machine you have to edit the following files:
  • /etc/sysconfig/iptables
  • /etc/sysconfig/ip6tables

For example, to open HTTP and HTTPS ports, you can use the following lines:
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT

Then, just restart the services:
[root@ servidor ~]# /etc/init.d/iptables restart
[root@ servidor ~]# /etc/init.d/ip6tables restart

lunes, 5 de junio de 2017

Windows 7 - Set default TWAIN scanner

I had a Epson scanner installed in Windows 7. Then I installed another scanner, a fujitsu, and unplugged the first one.

When working with an application wich used TWAIN drivers in order to connect to the scanner, the default device was the Epson. Specifically, the application used the Dynamsoft Dynamic Web TWAIN plugin.

The default TWAIN device is stored in Windows registry, under the following key:
HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\TWAIN




In the referenced folder, C:\Windows\twain_32, I had the following structure:



The solution was just to select the fujitsu ds file, and update the registry entry.


lunes, 10 de abril de 2017

ActiveMQ - SQL Server - Change default schema

When using ActiveMQ JBDB Persistence Adapter with SQL Server, all tables are created in the default dbo schema. If you use a Master/Slave configuration (http://activemq.apache.org/jdbc-master-slave.html), all brokers will share this schema and use these tables to synchronize.

Then, I was thinking of having a network of brokers with two pairs of Master/Slave brokers. There would be the following brokers:
  • Broker AM. Master broker of "subnetwork" A
  • Broker AS. Slave broker of "subnetwork" A
  • Broker BM. Master broker of "subnetwork" B
  • Broker BS. Slave broker of "subnetwork" B
Because of you have two pairs of Master/Slave, you need two databases to syncronize them, each one with its default dbo chema. But if you set two diferent connection users and, for each user, you set a different default schema, SQL Server will use this schema in all SQL Sentences. So you can use the same database and all the extra config will be handled by SQL Server.

The scenario will be as follows:


In SQL Server Management Studio you create two users:
  • ActiveMQ1
  • ActiveMQ2
Then you associate these users with the storage database.


Next, you create the two schemas and set the corresponding user as owner. Schemas are created in [database] > Security > Schemas option.

Finally, set the default schema for each user. This is done in [database] > Security > Users > [user].


Done. When brokers start, the master of each network (the first one to start) will create its tables in its own schema.

ActiveMQ - SQL Server - JDBC Master-Slave

These are the basic instructions to configure a Shared JDBC Persistence Adapter with SQL Server. The objective is to prepare a master/slave configuration with two or more Brokers.

Tested with ActiveMQ 5.14.4.

Add the following dependencies to ACTIVEMQ_HOME/lib/extra in all brokers:
  • Apache commons dbcp2
  • Apache commons pool 2
  • sqljdbc4

Edit the broker config in ACTIVEMQ_HOME/conf/activemq.xml, for all nodes:
<beans ... >

 (...)
  
 <bean id="sqlServerDS" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
   <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
   <property name="url" value="jdbc:sqlserver://windowsServer-R2:1433;DatabaseName=ActiveMQ"/>
   <property name="username" value="activemq"/>
   <property name="password" value="activemq"/>
   <property name="poolPreparedStatements" value="true"/>
 </bean>
 
 (...)
  
 <broker xmlns="http://activemq.apache.org/schema/core" brokerName="brokerA" dataDirectory="${activemq.data}">  
     (...)
  
     <persistenceAdapter>
        <jdbcPersistenceAdapter dataDirectory="${activemq.base}/data" dataSource="#sqlServerDS" />          
     </persistenceAdapter>
  
     (...)
 </broker>
</beans>

The database should be empty and the first time the first broker starts, all tables will be automatically created (you could get some warnings at this point)


viernes, 31 de marzo de 2017

JBoss EAP Allow weak password

In order to allow weak user passwords edit JBOSS_HOME/bin/add-user.properties file.

Set de following config keys:
  • password.restriction=RELAX
  • password.restriction.minLength=4
  • password.restriction.mustNotMatchUsername=FALSE
  • password.restriction.forbiddenValue=
  • password.restriction.strength=VERY_WEAK

# Valid values: RELAX, WARN or REJECT
# RELAX : Don't perform any strength checks on the password in both interactive and non-interactive mode
# WARN : Display a message about the strength of the password. Ask confirmation if the password is weak in interactive mode
# REJECT : Display a message about the strength of the password (if the password is weak, the user is not created).
# Ask confirmation if the password is weak in interactive mode
password.restriction=RELAX

# Password minimum length
password.restriction.minLength=4

# Password must contains at least one alpha
password.restriction.minAlpha=1

# Password must contains at least one digit
password.restriction.minDigit=1

# Password must contains at least one symbol
password.restriction.minSymbol=1

# Password must not match the username. Valid values: TRUE or FALSE.
password.restriction.mustNotMatchUsername=FALSE

# Comma separated list of forbidden passwords (easily guessable)
password.restriction.forbiddenValue=

# Password strength. Valid values: VERY_WEAK, WEAK, MODERATE, MEDIUM, STRONG, VERY_STRONG or EXCEPTIONAL.
# If not present, it defaults to "MODERATE"
password.restriction.strength=VERY_WEAK

# Class of password strength checker.
# If not present, utility will revert to default implementation
password.restriction.checker=org.jboss.as.domain.management.security.password.simple.SimplePasswordStrengthChecker

A dream come true for lazy (and bad memory) developers.

jueves, 9 de marzo de 2017

JavaMelody Collect Server - CentOS - Configure as Service

This is how I configured the JavaMelody Collect Server to start as a service in CentOS 6. The collect server is deployed as a WAR with its embedded server.

JavaMelody: https://github.com/javamelody/javamelody/wiki
JavaMelody Collect Server: https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#optional-centralization-server-setup

Directory structure:
 - /opt/javamelody
     - javamelody-X.X.X.war
     - javamelody.war (symbolic link to the previous war)
     - conf
         - javamelody.sh (launch script)
      - work
         - tmp (java temp directory for de process)
         - storage (storage directory for monitor info)


First, create the directoy structure:
mkdir /opt/javamelody

cp javamelody-1.63.0.war /opt/javamelody/

ln -s  /opt/javamelody/javamelody-1.63.0.war /opt/javamelody/javamelody.war

mkdir /opt/javamelody/work

mkdir /opt/javamelody/work/tmp

mkdir /opt/javamelody/work/storage

mkdir /opt/javamelody/conf

In /opt/javamelody/conf you have to create the launching script, called javamelody.sh:
#!/bin/sh
#
# JavaMelody script
# 09/03/2017
#
# https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#3-simpler-alternative-of-deployment-of-the-webapp-of-monitoring
#
# Params:
# - JMELODY_CONSOLE_LOG : Log directory
# - JMELODY_PIDFILE : File where the pid is stored
#
#

JAVA_OPTS="-server -Xmx256m"
JAVA_OPTS="$JAVA_OPTS -Djava.io.tmpdir=/opt/javamelody/work/tmp"
JAVA_OPTS="$JAVA_OPTS -Djavamelody.storage-directory=/opt/javamelody/work/storage"
JAVA_OPTS="$JAVA_OPTS -Djavamelody.authorized-users=sisifo:sisifo"

JMELODY_WAR=/opt/javamelody/javamelody.war

JMELODY_OPTS="--httpPort=9080"

# Run and store the PID
nohup java $JAVA_OPTS -jar $JMELODY_WAR $JMELODY_OPTS 0</dev/null 2>&1 >> $JMELODY_CONSOLE_LOG &
JMELODY_PID=$!
echo $JMELODY_PID > $JMELODY_PIDFILE

JavaMelody will be executed with its own user, called 'javamelody':
useradd -U javamelody

chown -Rf javamelody:javamelody /opt/javamelody/

Now, you have to create the service script called javamelody in /etc/init.d:
#!/bin/sh
#
# JavaMeoldy Collect Server script
#


# Source function library.
. /etc/init.d/functions

JMELODY_SCRIPT=/opt/javamelody/conf/javamelody.sh


JMELODY_CONSOLE_LOG=/var/log/javamelody/javamelody.log
JMELODY_PIDFILE=/var/run/javamelody.pid


JMELODY_USER=javamelody
prog='JavaMelody Collect Server'



# Set defaults.
if [ -z "$JMELODY_PIDFILE" ]; then
  JMELODY_PIDFILE=/var/run/javamelody.pid

fi
export JMELODY_PIDFILE


if [ -z "$JMELODY_CONSOLE_LOG" ]; then
  JMELODY_CONSOLE_LOG=/var/log/javamelody/javamelody.log
fi


if [ -z "$STARTUP_WAIT" ]; then
  STARTUP_WAIT=30
fi

if [ -z "$SHUTDOWN_WAIT" ]; then
  SHUTDOWN_WAIT=30
fi



start() {
  echo -n "Starting $prog: "
  if [ -f $JMELODY_PIDFILE ]; then
    read ppid < $JMELODY_PIDFILE
    if [ `ps --pid $ppid 2> /dev/null | grep -c $ppid 2> /dev/null` -eq '1' ]; then
      echo -n "$prog is already running"
      failure
      echo
      return 1
    else
      rm -f $JMELODY_PIDFILE
    fi
  fi
  mkdir -p $(dirname $JMELODY_CONSOLE_LOG)
  cat /dev/null > $JMELODY_CONSOLE_LOG
  chown -Rf $JMELODY_USER $(dirname $JMELODY_CONSOLE_LOG) || true


  mkdir -p $(dirname $JMELODY_PIDFILE)
  chown $JMELODY_USER $(dirname $JMELODY_PIDFILE) || true

  
  daemon --user $JMELODY_USER --pidfile $JMELODY_PIDFILE JMELODY_PIDFILE=$JMELODY_PIDFILE JMELODY_CONSOLE_LOG=$JMELODY_CONSOLE_LOG $JMELODY_SCRIPT
 

  count=0
  launched=false

  until [ $count -gt $STARTUP_WAIT ]
  do
    grep 'Winstone Servlet * Engine' $JMELODY_CONSOLE_LOG > /dev/null
    if [ $? -eq 0 ] ; then
      launched=true
      break
    fi
    sleep 1
    let count=$count+1;
  done


  success
  echo
  return 0
}

stop() {
  echo -n $"Stopping $prog: "
  count=0;

  if [ -f $JMELODY_PIDFILE ]; then
    read kpid < $JMELODY_PIDFILE
    let kwait=$SHUTDOWN_WAIT

    # Try issuing SIGTERM

    kill -15 $kpid
    until [ `ps --pid $kpid 2> /dev/null | grep -c $kpid 2> /dev/null` -eq '0' ] || [ $count -gt $kwait ]
    do
      sleep 1
      let count=$count+1;
    done

    if [ $count -gt $kwait ]; then
      kill -9 $kpid
    fi
  fi
  rm -f $JMELODY_PIDFILE
  success
  echo
}

status() {
  if [ -f $JMELODY_PIDFILE ]; then
    read ppid < $JMELODY_PIDFILE
    if [ `ps --pid $ppid 2> /dev/null | grep -c $ppid 2> /dev/null` -eq '1' ]; then
      echo "$prog is running (pid $ppid)"
      return 0
    else
      echo "$prog dead but pid file exists"
      return 1
    fi
  fi
  echo "$prog is not running"
  return 3
}

case "$1" in
  start)
      start
      ;;
  stop)
      stop
      ;;
  restart)
      $0 stop
      $0 start
      ;;
  status)
      status
      ;;
  *)
      ## If no parameters are given, print which are avaiable.
      echo "Usage: $0 {start|stop|status|restart|reload}"
      exit 1
      ;;
esac

Finally, just configure it as an automatic service:
chmod +x /etc/init.d/javamelody

chkconfig --add javamelody
chkconfig javamelody on
service javamelody start

domingo, 12 de febrero de 2017

Centos 6 - Configure SonarQube with PostgreSQL

Just for my reminder.
How to configure SonarQube 5.X with PostgreSQL 8.X in Centos 6.6

Install postgresql.
yum install postgresql-server

service postgresql initdb

chkconfig postgresql on
service postgresql start

Configure access.
Edit /var/lib/pgsql/data/pg_hba.conf file and set the following config:
local all all trust
host all 127.0.0.1/32 trust

Create sonar user and database (you have to restart the service before).
psql -U postgres
postgres=# create user sonar with password 'sonar';
postgres=# create database sonar with owner sonar encoding 'UTF8';

Configure sonar.
Edit /usr/local/sonarqube/conf/sonar.properties file:
(...)

# User credentials.
# Permissions to create tables, indices and triggers must be granted to JDBC user.
# The schema must be created first.
sonar.jdbc.username=sonar
sonar.jdbc.password=sonar

#----- Embedded Database (default)
# H2 embedded database server listening port, defaults to 9092
#sonar.embeddedDatabase.port=9092

(...)

#----- PostgreSQL 8.x/9.x
# If you don't use the schema named "public", please refer to http://jira.sonarsource.com/browse/SONAR-5000
sonar.jdbc.url=jdbc:postgresql://localhost/sonar

(...)

Done.

Apache httpd - ap_proxy_connect_backend disabling worker for (XXXX)

Problem

I have a web service which is published (by Camel y JBoss Fuse) in http://fuse-01:8888/conversor.
The service clients, instead of accessing the service directly, they will use an Apache httpd server as proxy.

I configure the proxy in this way, in /etc/httpd/conf.d:
<VirtualHost *:80>
    ServerName fuse-01   
    DocumentRoot /var/www/fuse-01

    <Directory /var/www/fuse-01>
        Options FollowSymLinks
        AllowOverride None
        Order deny,allow
        Allow from all
    </Directory>    


    # Configuración conversor PDF
    ProxyRequests     Off
    ProxyPreserveHost On

    <Location /conversor> 
 ProxyPass http://localhost:8888/conversor
 ProxyPassReverse http://localhost:8888/conversor
    </Location>


    ErrorLog logs/fuse-01-error_log
    CustomLog logs/fuse-01-access_log common
</VirtualHost>

But when I try http://fuse-01/conversor?wsdl I get the following error in the browser:
Error 503
Service Temporarily Unavailable
The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.
By checking Apache logs files I see this in fuse-01-error_log:
[Sun Feb 12 11:28:59 2017] [error] (13)Permission denied: proxy: HTTP: attempt to connect to 192.168.56.103:8888 (fuse-01) failed
[Sun Feb 12 11:28:59 2017] [error] ap_proxy_connect_backend disabling worker for (fuse-01)

Solution

Execute the following command:
/usr/sbin/setsebool -P httpd_can_network_connect true

SELinux (Security-Enhanced Linux) is a security module for supporting access control security policies.
There are lots of boolean variables which control multiple security aspects of the system, and you can check then all by using:
getsebool -a

Statted from Redhat official doc:

httpd_can_network_connectWhen disabled, this Boolean prevents HTTP scripts and modules from initiating a connection to a network or remote port. Enable this Boolean to allow this access.

sábado, 11 de febrero de 2017

CentOS 6 - Install LibreOffice - Offline installation

In the previous post CentOS 6 - Install LibreOffice as a service I installed libre office by using yum repositories. But if your client machine does not have access to the yum repository wich contains these packages, you have a problem.

In my local installation, I used my CentOS-Base.repo yum repo (check appendix I). This is the repo in /etc/yum.repos.d/CentOS-Base.repo file:
(...)
[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
(...)

This mirror is resolved as http://mirrorlist.centos.org/?release=6&arch=x86_64&repo=os&infra=stock (check appendix II)

So, you can add this repo to the client machine or you can prepare a "bundle" which contains all packages needed to your installation. I tried this second one.

In my local machine I used yum downloadonly plugin in order to download the libreoffice packages and all their dependencies, and save them in a directory.
yum install yum-plugin-downloadonly

yum install --downloadonly --downloaddir=/tmp/libreoffice libreoffice-headless
yum install --downloadonly --downloaddir=/tmp/libreoffice libreoffice-writer

cd /tmp
tar -zcvf libreoffice-4.3.7.gz libreoffice

Once you have all the RPM files, you only need to put them in the client machine and make a local install.
tar -xvf libreoffice-4.3.7.gz
cd libreoffice

yum localinstall *.rpm

Appendix I - How to know which repo a package came from

I you have a package installed and you want to know where it came from, you can use repoquery. This is a utility of yum-utils:
yum install yum-utils

repoquery -i libreoffice-writer

Appendix II - How to resolve yum properties

Yum properties like "releasever", "basearch" and "infra" can be resolved by using a python script:
/usr/bin/python -c 'import yum;yb=yum.YumBase();yb.doConfigSetup(init_plugins=False);print yb.conf.yumvar["rleaseserver"]'
/usr/bin/python -c 'import yum;yb=yum.YumBase();yb.doConfigSetup(init_plugins=False);print yb.conf.yumvar["basearch "]'
/usr/bin/python -c 'import yum;yb=yum.YumBase();yb.doConfigSetup(init_plugins=False);print yb.conf.yumvar["infra"]'

Apendix III - Why I did not install the latest version of libreoffice

My Unix skills are quite meager. I tried to download and install the latest stable libreoffice RPMs by downloading them from the official site: https://es.libreoffice.org/descarga/libreoffice-estable/?type=rpm-x86_64&version=5.2 , but after the installation I got a lot of errors like:
/opt/libreoffice5.1/program/oosplash: error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory

Each time I installed the missing library, another one missing library appeared. I think this is due to the fact that I was using a CentOS server installation, without Gnome or KDE...

sábado, 4 de febrero de 2017

CentOS 6 - Install LibreOffice as a service

The purpose of this post is to show how to install LibreOffice in CentOS 6, without GUI. My requirements were to use LibreOffice as a PDF converter.

Install LibreOffice by using yum:
yum install libreoffice-headless

yum install libreoffice-writer

libreoffice --version

The install directory will be /usr/lib64/libreoffice

In order to make a test, you can try convert a file:
echo 'hola' > prueba.txt

libreoffice --headless --convert-to pdf prueba.txt

If you want to install it as a service, just create the following file and save it in /etc/init.d (I copied this file from here):
#!/bin/sh
#
# ooffice       openoffice conversion service
#
#
# chkconfig: 345 50 25
# description: Startup script for the Open Office conversion process
# pidfile: /var/run/ooffice.pid

# Source function library.
. /etc/rc.d/init.d/functions

proc="/usr/lib64/libreoffice/program/soffice.bin"
options="--headless --accept=\"socket,host=0,port=8100,tcpNoDelay=1;urp\" --nodefault --nofirststartwizard --nolockcheck --nologo --norestore --invisible &"
if [ ! -f $proc ]; then
        proc="/usr/lib64/openoffice.org3/program/soffice.bin"
        options="--headless --accept=\"socket,host=0,port=8100,tcpNoDelay=1;urp\" --nodefault --nofirststartwizard --nolockcheck --nologo --norestore --invisible &"
fi


prog=ooffice
PID_FILE=/var/run/ooffice.pid

LOG=/var/log/ooffice
if [ ! -f $LOG ]; then
        touch $LOG
        chmod 644 $LOG
fi


start() {
        echo -n $"Starting $prog: "
        umask 000
        daemon $prog $options
        RETVAL=$?
        echo
        sleep 1
        pidofproc $proc > $PID_FILE
        echo "`date +\"%Y-%m-%d %T\"`  Starting ooffice." >> $LOG
        return $RETVAL
}

stop() {
        echo -n $"Stopping $prog: "
        killproc -p $PID_FILE $prog
        RETVAL=$?
        echo
        echo "`date +\"%Y-%m-%d %T\"`  Stopping ooffice." >> $LOG
        return $RETVAL
}

case "$1" in
        start)
                start
                ;;
        stop)
                stop
                ;;
        restart)
                stop
                sleep 1
                start
                ;;
        status)
                status -p $PID_FILE $prog
                ;;
        *)
                echo $"Usage: $prog {start | stop | restart | status}"
                exit 1
esac

exit $RETVAL

Finally configure this script as an executable and set the service as autostart:
chmod +x /etc/init.d/soffice
chkconfig --add soffice
chkconfig soffice on
service soffice start

domingo, 8 de enero de 2017

Chrome DevTools persist changes on page reload

Chrome DevTools allow you, amongst much other things, to edit HTML and JS files and save them in a workspace.
When debugging, you can add a local folder as a workspace. Then you can map any JS file served by the server to a local file in this workspace. Any change you made in this file, by using chrome editor, is automatically saved in the workspace.
You can check the full explanation here.

There is a problem though, each time you reload the page, the browser request again de JS file and your changes are "lost". Indeed, the changes still are saved in the workspace, but you see again the file loaded from the server.


There is a solution for this. Just set the workspace as the server resources folder. In this way, you edit the same file the browser is loading.
But what happens when you does not have direct access to the server resources folder?


My solution is to combine chrome DevTools with Fiddler Autoresponder.

Fiddler is a proxy tool that captures all http traffic and allows you to inspect and change it. With the autoresponder option you can return a local response when the browser request some URL, based on a set of rules. In this way you can build your own responses or modify some previous ones, instead to request them to the server.
The problem is that the fiddler response file is not editable by chrome. The fiddler file has two parts: headers and body, being the body the JS file. So, you need two files, the fiddler response and the JS body.


You edit the JS file by using chrome editor, then copy the body to the fiddler response file, and when the page is reloaded fiddler will return the modified response.

Instead editing the fiddler response file manually, I created a python script wich inspects the chrome workspace folder looking for JS files. For each of them, the script creates a fiddler file response by appending a set of headers. These headers are also in other common file.

This script read recursively all files in a root folder, keeping only th JS files. For each one create the corresponding fiddler response file by appending a common response headers.

You can check the script here: https://github.com/evazquezma/python/blob/master/fiddlerResponse/generateResponses.py