Esempio n. 1
0
static void VerifySQLPromise(Attributes a, Promise *pp)
{
    char database[CF_MAXVARSIZE], table[CF_MAXVARSIZE], query[CF_BUFSIZE];
    char *sp;
    int count = 0;
    CfdbConn cfdb;
    CfLock thislock;
    char lockname[CF_BUFSIZE];

    snprintf(lockname, CF_BUFSIZE - 1, "db-%s", pp->promiser);

    thislock = AcquireLock(lockname, VUQNAME, CFSTARTTIME, a, pp, false);

    if (thislock.lock == NULL)
    {
        return;
    }

    database[0] = '\0';
    table[0] = '\0';

    for (sp = pp->promiser; *sp != '\0'; sp++)
    {
        if (strchr("./\\", *sp))
        {
            count++;
            strncpy(table, sp + 1, CF_MAXVARSIZE - 1);
            sscanf(pp->promiser, "%[^.\\/]", database);

            if (strlen(database) == 0)
            {
                cfPS(cf_error, CF_FAIL, "", pp, a,
                     "SQL database promiser syntax should be of the form \"database.table\"");
                PromiseRef(cf_error, pp);
                YieldCurrentLock(thislock);
                return;
            }
        }
    }

    if (count > 1)
    {
        cfPS(cf_error, CF_FAIL, "", pp, a, "SQL database promiser syntax should be of the form \"database.table\"");
        PromiseRef(cf_error, pp);
    }

    if (strlen(database) == 0)
    {
        strncpy(database, pp->promiser, CF_MAXVARSIZE - 1);
    }

    if (a.database.operation == NULL)
    {
        cfPS(cf_error, CF_FAIL, "", pp, a ,
             "Missing database_operation in database promise");
        PromiseRef(cf_error, pp);
        YieldCurrentLock(thislock);
        return;
    }

    if (strcmp(a.database.operation, "delete") == 0)
    {
        /* Just deal with one */
        strcpy(a.database.operation, "drop");
    }

/* Connect to the server */

    CfConnectDB(&cfdb, a.database.db_server_type, a.database.db_server_host, a.database.db_server_owner,
                a.database.db_server_password, database);

    if (!cfdb.connected)
    {
        /* If we haven't said create then db should already exist */

        if ((a.database.operation) && (strcmp(a.database.operation, "create") != 0))
        {
            CfOut(cf_error, "", "Could not connect an existing database %s - check server configuration?\n", database);
            PromiseRef(cf_error, pp);
            CfCloseDB(&cfdb);
            YieldCurrentLock(thislock);
            return;
        }
    }

/* Check change of existential constraints */

    if ((a.database.operation) && (strcmp(a.database.operation, "create") == 0))
    {
        CfConnectDB(&cfdb, a.database.db_server_type, a.database.db_server_host, a.database.db_server_owner,
                    a.database.db_server_password, a.database.db_connect_db);

        if (!cfdb.connected)
        {
            CfOut(cf_error, "", "Could not connect to the sql_db server for %s\n", database);
            return;
        }

        /* Don't drop the db if we really want to drop a table */

        if ((strlen(table) == 0) || ((strlen(table) > 0) && (strcmp(a.database.operation, "drop") != 0)))
        {
            VerifyDatabasePromise(&cfdb, database, a, pp);
        }

        /* Close the database here to commit the change - might have to reopen */

        CfCloseDB(&cfdb);
    }

/* Now check the structure of the named table, if any */

    if (strlen(table) == 0)
    {
        YieldCurrentLock(thislock);
        return;
    }

    CfConnectDB(&cfdb, a.database.db_server_type, a.database.db_server_host, a.database.db_server_owner,
                a.database.db_server_password, database);

    if (!cfdb.connected)
    {
        CfOut(cf_inform, "", "Database %s is not connected\n", database);
    }
    else
    {
        snprintf(query, CF_MAXVARSIZE - 1, "%s.%s", database, table);

        if (VerifyTablePromise(&cfdb, query, a.database.columns, a, pp))
        {
            cfPS(cf_inform, CF_NOP, "", pp, a, " -> Table \"%s\" is as promised", query);
        }
        else
        {
            cfPS(cf_inform, CF_FAIL, "", pp, a, " -> Table \"%s\" is not as promised", query);
        }

/* Finally check any row constraints on this table */

        if (a.database.rows)
        {
            CfOut(cf_inform, "",
                  " !! Database row operations are not currently supported. Please contact cfengine with suggestions.");
        }

        CfCloseDB(&cfdb);
    }

    YieldCurrentLock(thislock);
}
Esempio n. 2
0
static PromiseResult VerifySQLPromise(EvalContext *ctx, const Attributes *a, const Promise *pp)
{
    assert(a != NULL);
    char database[CF_MAXVARSIZE], table[CF_MAXVARSIZE], query[CF_BUFSIZE];
    char *sp;
    int count = 0;
    CfdbConn cfdb;
    CfLock thislock;
    char lockname[CF_BUFSIZE];

    snprintf(lockname, CF_BUFSIZE - 1, "db-%s", pp->promiser);

    thislock = AcquireLock(ctx, lockname, VUQNAME, CFSTARTTIME, a->transaction.ifelapsed, a->transaction.expireafter, pp, false);
    if (thislock.lock == NULL)
    {
        return PROMISE_RESULT_SKIPPED;
    }

    database[0] = '\0';
    table[0] = '\0';

    for (sp = pp->promiser; *sp != '\0'; sp++)
    {
        if (strchr("./\\", *sp))
        {
            count++;
            strlcpy(table, sp + 1, CF_MAXVARSIZE);
            sscanf(pp->promiser, "%[^.\\/]", database);

            if (strlen(database) == 0)
            {
                cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a,
                     "SQL database promiser syntax should be of the form \"database.table\"");
                PromiseRef(LOG_LEVEL_ERR, pp);
                YieldCurrentLock(thislock);
                return PROMISE_RESULT_FAIL;
            }
        }
    }

    PromiseResult result = PROMISE_RESULT_NOOP;
    if (count > 1)
    {
        cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "SQL database promiser syntax should be of the form \"database.table\"");
        PromiseRef(LOG_LEVEL_ERR, pp);
        result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
    }

    if (strlen(database) == 0)
    {
        strlcpy(database, pp->promiser, CF_MAXVARSIZE);
    }

    if (a->database.operation == NULL)
    {
        cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a,
             "Missing database_operation in database promise");
        PromiseRef(LOG_LEVEL_ERR, pp);
        YieldCurrentLock(thislock);
        return PROMISE_RESULT_FAIL;
    }

    if (strcmp(a->database.operation, "delete") == 0)
    {
        /* Just deal with one */
        strcpy(a->database.operation, "drop");
    }

/* Connect to the server */

    CfConnectDB(&cfdb, a->database.db_server_type, a->database.db_server_host, a->database.db_server_owner,
                a->database.db_server_password, database);

    if (!cfdb.connected)
    {
        /* If we haven't said create then db should already exist */

        if ((a->database.operation) && (strcmp(a->database.operation, "create") != 0))
        {
            Log(LOG_LEVEL_ERR, "Could not connect an existing database '%s' - check server configuration?", database);
            PromiseRef(LOG_LEVEL_ERR, pp);
            CfCloseDB(&cfdb);
            YieldCurrentLock(thislock);
            return PROMISE_RESULT_FAIL;
        }
    }

/* Check change of existential constraints */

    if ((a->database.operation) && (strcmp(a->database.operation, "create") == 0))
    {
        CfConnectDB(&cfdb, a->database.db_server_type, a->database.db_server_host, a->database.db_server_owner,
                    a->database.db_server_password, a->database.db_connect_db);

        if (!cfdb.connected)
        {
            Log(LOG_LEVEL_ERR, "Could not connect to the sql_db server for '%s'", database);
            return PROMISE_RESULT_FAIL;
        }

        /* Don't drop the db if we really want to drop a table */

        if ((strlen(table) == 0) || ((strlen(table) > 0) && (strcmp(a->database.operation, "drop") != 0)))
        {
            VerifyDatabasePromise(&cfdb, database, a);
        }

        /* Close the database here to commit the change - might have to reopen */

        CfCloseDB(&cfdb);
    }

/* Now check the structure of the named table, if any */

    if (strlen(table) == 0)
    {
        YieldCurrentLock(thislock);
        return result;
    }

    CfConnectDB(&cfdb, a->database.db_server_type, a->database.db_server_host, a->database.db_server_owner,
                a->database.db_server_password, database);

    if (!cfdb.connected)
    {
        Log(LOG_LEVEL_INFO, "Database '%s' is not connected", database);
    }
    else
    {
        snprintf(query, CF_MAXVARSIZE - 1, "%s.%s", database, table);

        if (VerifyTablePromise(ctx, &cfdb, query, a->database.columns, a, pp, &result))
        {
            cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_NOOP, pp, a, "Table '%s' is as promised", query);
        }
        else
        {
            cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Table '%s' is not as promised", query);
            result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
        }

/* Finally check any row constraints on this table */

        if (a->database.rows)
        {
            Log(LOG_LEVEL_INFO,
                  "Database row operations are not currently supported. Please contact cfengine with suggestions.");
        }

        CfCloseDB(&cfdb);
    }

    YieldCurrentLock(thislock);

    return result;
}